How to update JComboBox without Selected Item being changed

Discussion in 'Java' started by =?iso-8859-1?q?J=FCrgen_Gerstacker?=, Dec 15, 2006.

  1. Hello,
    I want to periodically update a Combobox due to changes in the OS
    (available RS232 serial ports).
    I started to fill the box every time the combobox becomes visible

    setup_cbport.removeAllItems();
    while () {
    ...
    setup_cbport.addItem(portId.getName());
    ...
    }
    setup_cbport.setSelectedItem(port); // previously selected item

    But when the box is being filled, an actionPerformed is fired


    public void actionPerformed(ActionEvent e) {
    if (e.getSource()==setup_cbport) {
    Object obj=setup_cbport.getSelectedItem();
    port=(String)obj; // new selection
    }


    and the previous selected item is overwritten.

    I could compare the items in the box with the new items and
    'add'/'remove' individually but this would complicated the code. I
    would like a simple solution, e.g. to allow the new selection only when
    the user changes the ComboBox, not when the 'actionPerformed' is issued
    by the System.
    Any ideas?

    Juergen
     
    =?iso-8859-1?q?J=FCrgen_Gerstacker?=, Dec 15, 2006
    #1
    1. Advertising

  2. =?iso-8859-1?q?J=FCrgen_Gerstacker?=

    Guest

    Jürgen Gerstacker wrote:
    > Hello,
    > I want to periodically update a Combobox due to changes in the OS
    > (available RS232 serial ports).
    > I started to fill the box every time the combobox becomes visible
    >
    > setup_cbport.removeAllItems();
    > while () {
    > ...
    > setup_cbport.addItem(portId.getName());
    > ...
    > }
    > setup_cbport.setSelectedItem(port); // previously selected item
    >
    > But when the box is being filled, an actionPerformed is fired
    >
    >
    > public void actionPerformed(ActionEvent e) {
    > if (e.getSource()==setup_cbport) {
    > Object obj=setup_cbport.getSelectedItem();
    > port=(String)obj; // new selection
    > }
    >
    >
    > and the previous selected item is overwritten.
    >
    > I could compare the items in the box with the new items and
    > 'add'/'remove' individually but this would complicated the code. I
    > would like a simple solution, e.g. to allow the new selection only when
    > the user changes the ComboBox, not when the 'actionPerformed' is issued
    > by the System.
    > Any ideas?


    Jurgen,

    The problem you have is that you want fairly complex functionality from
    your combo box but you are using the simple, convinience methods to
    manage it. Obviously this isn't going to work.

    The reason you are seeing the actionPerformed event is most likley
    because your combo box is informed of the model change after you call
    'removeAllItems'. This is causing the selected item to change (because
    you have removed it). The combo box default model cannot 'know' that
    you intend to add the item back again a few lines later.

    What you need to do to solve this issue is write your own
    ComboBoxModel. This will give you complete control over the items in
    the combo box as well as complete control over when the combo box will
    attempt to re-evaluate its data based on the new model.

    The interface you should implement is
    http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/ComboBoxModel.html

    Implementing this should not be hard (its only a few methods) but you
    must remember to keep track of your 'ListDataListeners' (which are
    provided to you when addListDataListener is called) and when you update
    the contents of your model with the new information, fire an
    appropriate event to all of your ListDataListeners. It is when this
    event is fired, that the combo box will re-evaluate the model. It will
    call 'getSelectedItem' and provided the item is equal (.equals) to the
    previous item, it should not change the selected item and therefore not
    fire actionPerformed. You will, of course, have to formulate a strategy
    for what happens when the selected item IS removed, but you would have
    had to do that anyway, and using a custom model will give you much more
    control over the behaviour.

    Good Luck!
     
    , Dec 15, 2006
    #2
    1. Advertising

  3. =?iso-8859-1?q?J=FCrgen_Gerstacker?=

    Nigel Wade Guest

    Jürgen Gerstacker wrote:

    > Hello,
    > I want to periodically update a Combobox due to changes in the OS
    > (available RS232 serial ports).
    > I started to fill the box every time the combobox becomes visible
    >
    > setup_cbport.removeAllItems();
    > while () {
    > ...
    > setup_cbport.addItem(portId.getName());
    > ...
    > }
    > setup_cbport.setSelectedItem(port); // previously selected item
    >
    > But when the box is being filled, an actionPerformed is fired
    >
    >
    > public void actionPerformed(ActionEvent e) {
    > if (e.getSource()==setup_cbport) {
    > Object obj=setup_cbport.getSelectedItem();
    > port=(String)obj; // new selection
    > }
    >
    >
    > and the previous selected item is overwritten.
    >
    > I could compare the items in the box with the new items and
    > 'add'/'remove' individually but this would complicated the code. I
    > would like a simple solution, e.g. to allow the new selection only when
    > the user changes the ComboBox, not when the 'actionPerformed' is issued
    > by the System.
    > Any ideas?
    >
    > Juergen


    You could remove the listeners before updating the ComboBox, then restore them
    after the update is complete:

    ActionListener[] listeners = setup_cbport.getActionListeners();
    for(ActionListener l:listeners) {
    setup_cbport.removeActionListener(l);
    }

    // do whatever you need to here.

    for(ActionListner l:listeners) {
    setup_cbport.addActionListener(l);
    }

    --
    Nigel Wade, System Administrator, Space Plasma Physics Group,
    University of Leicester, Leicester, LE1 7RH, UK
    E-mail :
    Phone : +44 (0)116 2523548, Fax : +44 (0)116 2523555
     
    Nigel Wade, Dec 15, 2006
    #3
  4. =?iso-8859-1?q?J=FCrgen_Gerstacker?=

    Guest


    >
    > You could remove the listeners before updating the ComboBox, then restore them
    > after the update is complete:


    YUCK! This is a terrible habbit. It should be the last of the last of
    resorts.

    In any case, I dont think it will solve the OPs problem. Calling
    'removeAllItems' will result in the selected item being lost. The
    JComboBox is a listener of it's model. It is taking control of the
    events that fire between the model that is needed.

    The correct solution is a custom model.
     
    , Dec 15, 2006
    #4
  5. schrieb:

    > >
    > > You could remove the listeners before updating the ComboBox, then restore them
    > > after the update is complete:


    > In any case, I dont think it will solve the OPs problem. Calling
    > 'removeAllItems' will result in the selected item being lost.


    I know this issue, I restore the selected item after updating the
    contents.

    setup_cbport.setSelectedItem(port); // previously selected item

    After all, the modification of the combobox is not a bad idea.


    Vector<String> set=new Vector<String>();
    while (...) {
    // collect items from the OS
    set.add(pId.getName());
    }

    // delete items from the box
    Vector<String> set2=new Vector<String>();
    int i=0; while (i<setup_cbport.getItemCount()) {
    String itm=(String)setup_cbport.getItemAt(i);
    if (!set.contains(itm)) setup_cbport.removeItemAt(i);
    else {set2.add(itm); i++;}
    }

    // add new items
    Iterator it = set.iterator();
    while (it.hasNext()) {
    Object itm=it.next();
    if (!set2.contains(itm)) setup_cbport.addItem(itm);
    }
     
    =?iso-8859-1?q?J=FCrgen_Gerstacker?=, Dec 15, 2006
    #5
  6. =?iso-8859-1?q?J=FCrgen_Gerstacker?=

    Guest

    Jürgen Gerstacker wrote:
    > schrieb:
    >
    > > >
    > > > You could remove the listeners before updating the ComboBox, then restore them
    > > > after the update is complete:

    >
    > > In any case, I dont think it will solve the OPs problem. Calling
    > > 'removeAllItems' will result in the selected item being lost.

    >
    > I know this issue, I restore the selected item after updating the
    > contents.


    There is more to it than this, removing the selected item sets into
    motion a whole series of events that is what ultimately ends up in your
    actionPerformed event being fired. This happens before your remove
    method invocation even returns. Restoring the selected item later will
    not prevent it.

    The slightly lazy approach, is what Nigel suggested. Remove the
    listeners, then add them back after you are done with your
    manipulation. I stand by my point that this is a bad bad habbit, but I
    would be lying if I said I haven't done it myself and it (now that I
    understand a little more) should solve your problem for now.

    My point, is that the better way is to take control over which events
    are fired between your model and your view. This can be accomplished by
    creating your own model rather than using the default one. As you get
    into more complex swing code, you will eventually have no choice but to
    create your own models. In this example, you do have a choice, but it
    is a choice between lots of ugly code that is doing far more work than
    required, or the elegant solution where you use the libraries how Sun
    originally intended.

    The more elegant solution may require for you to learn a little more
    about MVC and how it works within Swing, and if you dont have the time
    and/or inclination to learn this then you would be better of going down
    your own path or using the listener removal technique. You may find
    that you will reach an impasse with this approach though, and be forced
    to learn the 'proper' way.
     
    , Dec 15, 2006
    #6
  7. =?iso-8859-1?q?J=FCrgen_Gerstacker?=

    Lew Guest

    Jürgen Gerstacker wrote:
    > Vector<String> set=new Vector<String>();


    Are you relying on the synchronization of Vector methods? If not, a better
    declaration might be:

    List <String> set = new ArrayList <String>();

    Also, since there is a Set type, naming a List variable "set" might be a tad
    misleading.

    - Lew
     
    Lew, Dec 15, 2006
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Hal Vaughan
    Replies:
    7
    Views:
    1,441
    Hal Vaughan
    Sep 16, 2006
  2. Iain
    Replies:
    3
    Views:
    952
  3. Mariano
    Replies:
    15
    Views:
    1,894
    Michael Rauscher
    Mar 27, 2007
  4. Constantly Distracted
    Replies:
    0
    Views:
    295
    Constantly Distracted
    Jun 14, 2008
  5. mldardy
    Replies:
    0
    Views:
    982
    mldardy
    Sep 28, 2010
Loading...

Share This Page