views:

2557

answers:

6

Hi,

I have a dropdown box in my GUI which shows the contents of an ArrayList in another class. New objects can be added to the ArrayList elsewhere in the GUI, so I need to know when it is updated, so I can refresh the dropdown menu. From what I can gather, my two options are to extend the ArrayList class to allow me to add my own changeListener to it, or to make the class which contains the ArrayList in question extend observable. Which would be a more appropriate solution?

Thanks,

Simon

+1  A: 

The Observable implementation in Java is rarely used, and doesn't inter-operate well with Swing. Use an EventListener instead.

In particular, is there a reason not to extend AbstractListModel or even use DefaultListModel directly when managing the contents of the list "elsewhere in the GUI"? Then your combo box could use a ComboBoxModel that delegates to the same ListModel instance, adding its own implementation to track the selection state.

I have in mind something like this (but I haven't test it):

final class MyComboBoxModel 
  extends AbstractListModel 
  implements ComboBoxModel 
{

  private final ListModel data;

  private volatile Object selection;

  MyComboBoxModel(ListModel data) { 
    /* 
     * Construct this object with a reference to your list, 
     * which contents are managed somewhere else in the UI.
     */
    this.data = data;
    data.addListDataListener(new ListDataListener() {
      public void contentsChanged(ListDataEvent evt) { 
        fireContentsChanged(this, evt.getIndex0(), evt.getIndex1()); 
      }
      public void intervalAdded(ListDataEvent evt) { 
        fireContentsChanged(this, evt.getIndex0(), evt.getIndex1()); 
      }
      public void intervalRemoved(ListDataEvent evt) { 
        fireContentsChanged(this, evt.getIndex0(), evt.getIndex1()); 
      }
    });
  }

  public void setSelectedItem(Object selection) { 
    this.selection = selection;
    fireContentsChanged(this, 0, data.getSize() - 1);
  }

  public Object getSelectedItem() { return selection; }

  public int getSize() { return data.getSize(); }

  public Object getElementAt(int idx) { return data.getElementAt(idx); }

}
erickson
+3  A: 

The two solutions are essentially implementations of the same root design pattern (the "Observer" pattern as defined by the Gang of Four.) In the former case, you are making the ArrayList itself "observable", in the latter you are making the domain object which uses the array list "observable."

My tendency would be to do the latter: make the domain object observable. This is primarily because you may eventually have other things that could change about the domain object (for which the GUI should be updated.) If it is already observable, you're already set.

Note that you don't strictly have to extend java.util.Observable - you can implement the design pattern without doing that.

Jared
This seems like the easiest way, Thanks for all the other answers though.
Simonw
A: 

Always prefer composition over extension (my reference is effective java and my personal experience). extending ArrayList is simply a promise that you will not violate any of the classes invariants. It also binds you to the specific list implementation you are extending.

MahdeTo
A: 

You could switch to using a GUI design pattern. Or construct a limited implementation.

Create a GUI Form Interface that has a method DrawXArrayList (with X being some meaningfull name. It has a parameters of type ArrayList

Create a new class called GUIView. It has at least two methods: UpdateXArrayList, and RegisterForm

When you initialize your application have the GUI Form register itself with the class implementing GUIView. Make the class implementing GUIView visible to the form.

When anything in your GUI Form updates the arraylist have it call UpdateXArrayList as the last thing it does. The UpdateXArrayList method in the class implementing GUIView will then in turn call DrawXArrayList passing the updated arraylist. DrawXArrayList in the form class implementing the GUIFormInterface will then take the steps need to update the control displaying the ArrayList.

While this seems like a lot of steps compared to a observer and listener setup. You have more control over how the various user actions effect the UI then the observer-listener pattern. In addition you documented, in code, the interaction between the user action and the updates to the UI.

RS Conley
A: 

Why not use bindings?

http://wiki.eclipse.org/index.php/JFace_Data_Binding

Bind your GUI widget to your List. Changes will propogate between the two objects transparently. Be sure to wrap your model with an appropriate observable, such as WritableList (if using the ArrayList directly).

James Schek
A: 

If you can add a new jar to the application, check out glazed Lists

l_39217_l