Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swing: Is there a way to differentiate between a user-caused ItemEvent and an application-caused one?

I'm working with a combobox in a Swing-based application, and I'm having a hard time figuring out what to do to differentiate between an ItemEvent that is generated from a user event vs one caused by the application.

For instance, Lets say I have a combobox, 'combo' and I'm listening for itemStateChanged events with my ItemListener, 'listener'. When either a user changes the selection to item 2 or I execute the line (pseudocode):

combo.setSelection(2)

.. it seems like I'm not able to tell these events apart.

That said, I'm no Swing expert by any means, so I thought I would ask.

Thanks!

like image 348
awied Avatar asked Oct 06 '08 20:10

awied


3 Answers

Whether the user selects Item 2, or the API calls setSelection(2), the event will appear the same.

The solution to your problem might be in re-thinking what you want the itemStateChanged code to do when the selection changes. Why would your app work differently under each condition? Maybe there are similarities that you can use to your advantage.

Be careful when using flags. The itemStateChanged event will occur on the Event Dispatch Thread, which is a different thread than the one on which you'd set the state of the flag. This would mean that using a flag may not be 100% reliable.

like image 65
David Koelle Avatar answered Nov 15 '22 04:11

David Koelle


The Action and Reaction law is quite clear :). If you try to react on change there is no need to distinguish between user and application. I can imagine only one use case where you need to "distinguish". The case where application is displaying some data. In this case you have, probably, data model for your application. And also there are some change listener in this model and application GUI will react by setting values to components. And also. If user selects anything into GUI component. The data model will react by changing value. In this case it is easy to set up some sort of read-only state on data model which will notify model to ignore ANY event coming from observed objects. This notification set should run in EDT and there is no problem with flagging. Small example:

class ApplicationDataModel {

    private Flag current = Flag.RW;

    public void setData(ApplicationData data) {
        current = Flag.RO;
        setDataImpl(data);
        notifyObservers();
        current = Flag.RW;
    }

    public void reaction(Event e) {
        if (flag = Flag.RO) return;
        ...
    }

}

Be careful with flagging and don't forget about threading. If you are calling setData from another thread then EDT you are going into trouble. Of course. The extraction of ApplicationData object has to be run in different thread ;). In general, rethink design of your application.

like image 30
Rastislav Komara Avatar answered Nov 15 '22 04:11

Rastislav Komara


You can set a flag in your code before you set the selection, and then check for this flag in the listener (and unset the flag if it is set)...

There may be a better way since Java 6, but this is the way I always used to do it...

[Edit]: As David points out, you will need to set the flag (and update the combo) in the EDT using SwingUtilities.invokeLater or similar (you should do this anyway, as you are changing a UI control)

like image 45
tim_yates Avatar answered Nov 15 '22 04:11

tim_yates