I have a perfectly normal ArrayList<MyObject> that I need to edit and pick an object from.
In the application window, I have a JComboBox to select the appropriate choice from the list. I'm writing an editor dialog for these objects, which just includes a JList of these objects and editor fields. It's easy enough to do; I'll just have a ListModel implementation of some kind. Stick the ArrayList in, access it through the usual fields. The stuff in the GUI list is 1:1 representation of the stuff in the actual list. Easy.
But the combo box in the main application window is giving me a bit of a headache, because I need a special value. Ideally, the first item in the list should be "(None)", and return a null.
Do I just need to write some sort of weird ComboBoxModel implementation for this, or is there an easier, already implemented way to do this? I'd definitely imagine this sort of situation has cropped up before.
Implementing your own ComboBoxModel should be quite easy.
Since this solution creates a new Vector from your ArrayList, changes to yourArrayList after creating Vector won't be visible in your JComboBox. If you need this, then you'll have to implement your own ComboBoxModel (see DefaultComboBoxModel implementation).
You would have to do this anyway, since there is no DefaultComboBoxModel constructor that takes a List.
class SpecialComboBoxModel extends DefaultComboBoxModel {
public final static String NULL_ELEMENT = "<None>";
public SpecialComboBoxModel(Vector v) {
super(v);
}
#Override
public int getSize() {
return super.getSize() + 1;
}
#Override
public Object getElementAt(int index) {
if( index == 0) {
return NULL_ELEMENT;
}
return super.getElementAt(index - 1);
}
}
ArrayList<String> yourArrayList = new ArrayList<String>();
yourArrayList.add("Value1");
yourArrayList.add("Value2");
Vector<String> v = new Vector<String>(yourArrayList);
dropdown.setModel(new SpecialComboBoxModel(v));
You might want to use a null-object. For example
public class MyObject {
public static final MyObject NULL_OBJECT = new MyObject();
..
}
and then in your ArrayList just call:
arrayList.add(0, MyObject.NULL_OBJECT);
You null-object should have all of its properties set to null (or to some reasonable defaults), and your toString() method (if you are using it), should return "(none)" if all the fields are null.
Related
This is my first SO question. I hope i provide enough details.
I have an EMF Model with a class called ScopeContainer, which has two containment References as ELists of Different Types.
I have generated the
model
model.edit
and
model.editor
codes with the Genmodel
I am trying to show the contents of one of those lists in a org.eclipse.jface.viewers.TableViewer with only one Column.
This can't be a org.eclipse.swt.widgets.List since i want to be able to edit those entries.
TableViewer viewer;
AdapterFactory adapterFactory = storage.getDomain().getAdapterFactory();
AdapterFactoryLabelProvider labelProvider = new AdapterFactoryLabelProvider(adapterFactory);
AdapterFactoryContentProvider contentProvider = new AdapterFactoryContentProvider(adapterFactory);
viewer.setLabelProvider(labelProvider);
viewer.setContentProvider(contentProvider);
viewer.setInput(project.getScopecontainer().getFilters());
When I set the input as the the ScopeContainer Object. I can see all the objects in both lists
When i set the input as the EList<Filter> the Table is empty.
What do i have to do to set the Input of the TableViewer as EList?
A simple solution would be to override AdapterFactoryContentProvider.getElements() to return an array of Filter elements (derived from the EList<Filter> input).
As suggested I overrode the getElements Method Like this:
public class EListContentProvider<T> extends AdapterFactoryContentProvider{
public EListContentProvider(AdapterFactory adapterFactory) {
super(adapterFactory);
}
#Override
public Object[] getElements(Object inputElement) {
Object[] arr = null;
if(inputElement instanceof EList) {
arr = ((EList<T>) inputElement).toArray();
}
return arr;
}
}
You should check the class org.eclipse.jface.viewers.ArrayContentProvider or the class org.eclipse.jface.databinding.viewers.ObservableListContentProvider, depending on if your list is supposed to change or not.
Those content providers do exactly what you are asking for: manage a collection input for a table or a viewer.
I have this DefaultListModel
DefaultListModel listModel;
//constructor does the right hting... etc.. I skipped over a lot of code
JList jlist_available_items;
....
jlist_available_items= new JList(cartModel); //etc
Everything is working almost perfectly the issue is that
listModel.addElement(product);
if I change it to product.name it will look correctly, but behave wrongly [the object itself won't be accesisble, only the name]
Is adding the object to the view, and all I want to add is the object name.
When I change it to the name it causes all sorts of issues, because I store the objects in a hashmap, and the hashmap uses objects as keys, not the product.name string.
The reason is so that this method can search the hashmap for the right object.
for (Product p : store.database.keySet()) {
if (jlist_available_items.getSelectedValuesList().contains(
(Product) p)) { // if item is selected
cart.addItem(p);
}
}
How can I fix this?? I have been trying to fix it and related bugs for almsot two hours = ( !
Also sample output is
Product [description=descrion test, name=test]
That is what it is printing. I just want it to print the name. = (!
Also the objects are in a hashmap. I can just iterate through the hashmap until an object has the same name value and then use that, but I don't want to. I want a more proper and scalable solution, namely because I am having so much trouble thinking of one.
BY THE WAY! This is a GUI app in Swing! If you want images just ask = )!
EDIT: And now nmy list cell renderer is broken! It was working just a moment ago... = (
#Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
Product product = (Product) value;
return this;
}
}
By default, the toString() method of the objects in the model is called to display the list element. And your Product.toString() method returns Product [description=descrion test, name=test].
If you want to display something else, then use a ListCellRenderer, as explained in the swing tutorial about JList.
EDIT: your renderer has a bug: it doesn't set the text of the returned component (which is a JLabel). It should be:
Product product = (Product) value;
setText(product.getName());
return this;
I am using 4 JLists that is an array,
JList jlst = new JList[4];
Then I am adding first list items from array of objects,
jlst[0].setListData(getObjAL());
Here the function getObjAL() function will give the array of objects.
I want to display selected item of first list(jlst[0]) into second list(jlst[1]).
For that I am writing the code,
jlstPrimitives[i].addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent listevt) {
Jlist objLstTemp = (Jlist) listevt.getSource();
jlst[1].setListData(objLstTemp.getSelectedValue()));
}
});
But it is not displaying in list[1].
Please any one help me...
I can think of a dozen things that might be going wrong, none of which would affect you. For better support in the future, post a runnable example that demonstrates your problem. Pasting code out of context doesn't help (alot).
From your code, getObjAL() seems to be returning a Object[] array (single dimension), yet when you select a value, you seem to be assuming that the selected value is actually an array, which I'm pretty sure it isn't.
JList#setListData is expected either a object array (Object[]) or Vector.
Try something like this instead.
jlstPrimitives[i].addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent listevt) {
Jlist objLstTemp = (Jlist) listevt.getSource();
jlst[1].setListData(new Object[]{objLstTemp.getSelectedValue()}));
}
});
We have a Virtual Table in my Eclipse RCP application. We make a call to the backend to retrieve the data to be populated in the virtual table.
We want default sorting on the table on a single column. We use ViewerComparator to achieve sorting functionality. My problem is, I am not able to get this sorting working when the table loads with the data for the 1st time. But when I click on the column, everything works fine as expected.
This is how, I set the Comparator to the column
TableViewerColumn tvc = viewer.addColumn(100, SWT.LEFT, "Name");
viewer.setColumnComparator(tvc,
new Comparator<Person>() {
#Override
public int compare(Person o1,Person o2) {
double firstValue = Double.parseDouble(o1
.getAge());
double secondValue = Double.parseDouble(o2
.getAge());
return firstValue > secondValue ? 1 : -1;
}
});
setColumnComparator method in custom viewer
public void setColumnComparator(TableViewerColumn tvc, Comparator<T> cmp){
final MyViewerComparator c = new MyViewerComparator(cmp);
final TableColumn tc = tvc.getColumn();
setComparator(c);
getTable().setSortDirection(c.getDirection());
getTable().setSortColumn(tc);
refresh();
tc.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
<same code as above>
}
});
MyViewerComparator
class MyViewerComparator extends ViewerComparator{
Comparator<T> cmp;
boolean desc = true;
MyViewerComparator(Comparator<T> cmp){
this.cmp = cmp;
}
int getDirection(){
return desc?SWT.UP:SWT.DOWN;
}
void flipDirection(){
desc = !desc;
}
#Override
public int compare(Viewer viewer, Object e1, Object e2) {
if(e1 == null || e2==null){
return 0;
}
int rc = cmp.compare((T)e1, (T)e2);
if(desc)
return -rc;
return rc;
}
}
When the table loads the data for the 1st time, it goes inside the Bolded condition in the above code as one of the object is ALWAYS NULL
Note: This functionality works totally fine if I use a Standard table rather than VIRTUAL TABLE. I am not sure whether I can change it to use Standard table as we want the lazy load functionality as well..
ContentProvider used is: ObservableListContentProvider
Please advise..
A late answer that hopefully still helps others. I encountered exactly the same problem when using SWT.VIRTUAL with an ObservableListContentProvider in combination with sorting.
The original intent of SWT.VIRTUAL is that not all elements in the contents need to be fetched to show only part of the contents. A custom content provider needs to be implemented which only has to return the elements that need to be currently shown on the screen. You also have to tell the table the total number of elements in existence. In such a use case, a table cannot be sorted in the normal way with a ViewerComparator because not all elements are known. However SWT.VIRTUAL can also be used as a performance optimization for rendering a table with many elements. This seems to work fine with the non-observable ArrayContentProvider.
But when using ObservableListContentProvider I am seeing exactly the same issue as you have. Somehow it tries to be smart and update only the elements that have actually changed. Somewhere in the depths of it's implementation something goes wrong for virtual tables, I have no clue exactly what. But I do have a solution: don't use ObservableListContentProvider at all and simply refresh the table viewer. You can e.g. use a plain ArrayContentProvider and add the following listener to the IObservableList contents of the viewer:
new IListChangeListener() {
#Override
public void handleListChange(ListChangeEvent event) {
viewer.refresh();
}
};
I actually implemented my own "SimpleObservableListContentProvider" that does exactly this, but also takes care of switching table input by implementing the inputChanged method to remove this listener from the old input list and add it to the new one.
I am looking for code that will add favorites / MRU type behavior to a JComboBox.
I could code this myself, but it sure seems like someone else has probably already done it.
I found the following (which looks exactly like what I want, but the source code is nowhere near complete): http://java.sys-con.com/node/36658
Any suggestions? I need to keep this relatively light, so I'd prefer to not use a component that's part of a monolithic widget library, and open source is preferred.
Consider extending DefaultComboBoxModel: override addElement() and insertElementAt() to insert at zero and remove the last element.
Addendum: Here's an example; per SO, the license is cc-wiki. I'd use Preferences to persist the entries.
class MRUComboBoxModel extends DefaultComboBoxModel {
#Override
public void addElement(Object element) {
this.insertElementAt(element, 0);
}
#Override
public void insertElementAt(Object element, int index) {
super.insertElementAt(element, 0);
int size = this.getSize();
if (size > 10) {
this.removeElementAt(size - 1);
}
}
}
What about just subclassing JComboBox and overriding the
public void addItem(Object anObject)
to give it the functionality you want?
You can just keep an internal list of items synched with the effective one, and whenever you add a new item it can check if size() >= maxItems and trim down least recent ones.
Then you should find a way to refresh an item whenever it is used. If its selection it's enough to be refreshed you can write an ItemListener that does it. Otherwise you'll need a specified external action or an observer/observable pattern..