Should swing event handling code be queued after the event on the EDT? If so, is it the responsibility of the event source to schedule the event handlers, or is it the responsibility of the event handler to schedule the actual handling code later?
Consider:
JButton b = new JButton();
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
/*
* SNIP 1
* do something that may affect other
* components or generate new events...
*/
// SNIP 2
EventQueue.invokeLater(new Runnable(){
public void run(){
/*
* do something that may affect other
* components or generate new events...
*/
}
});
}
});
SNIP 1 runs handler code when the event is received. If the JButton takes responsibility for scheduling event by EventQueue.invokeLater(), then this is probably correct. SNIP 2 receives the event, and takes responsibility of scheduling handler code after the event is received (and handled by all other listeners for this specific event type). Which is correct?
EDIT: Just for clarity, I want to schedule event handlers later on EDT because changing state in the first event handler may hide original state at the time of the event from other event handlers for the component.
Please let me know though if I am misunderstanding your question, but all code in the Swing event Listeners is by run on the EDT, so there is no need to queue anything on to the EDT. I have only rarely seen code such as in snip2 used in a Swing listener, and usually that's if the listener calls an anonymous inner Runnable in a background thread.
As #HFOE notes, elements in the EventQueue are sequential and ordered; SNIP 2 shouldn't be required. If I understand your requirement, one approach might be to forward the event to any other interested listener(s), as suggested in this question & answer.
I know its probably bad form to answer my own question, but I've come to the conclusion that one should queue event handlers after an event in Swing. The reason is this: each component can have more than one listener of a given type. You don't know what listeners are listening on any given component (swing itself may add listeners that you are unaware of), and you don't know what assumptions they make about the component tree, and the state of the tree when they handle an event.
Now, because each component can have multiple event handler for a certain event type, we don't know which event handler will be invoked first. If my event handler modifies the component tree, a subsequent event handler for the same event type will not see the component tree as it was at the time of the event. Instead, it will see the component tree as it was after my changes. The same problem exists for other application state which may be inspected and modified by two separate listeners of the same type on the same component. This is surely not right.
Secondly, there is a concept of events being dispatched by the EDT in a sequential order. ie. If event x happened before event y in real time, then the event handlers for x should run before the event handlers for y. Now, if my component, lets call it c1, has 2 event handlers for event actionPerformed() - eh1 and eh2. When actionPerformed() is fired on c1, eh1 is invoked to handle the event. It then modifies component c2, and causes a itemStateChanged() event to be fired on c2. Because this change queued after the first actionPerformed() event was complete (later on the EDT), and because c2 does not queue the itemStateChanged() event to run later on the EDT, the itemStateChanged() event is handled by all its listeners. Only then does the second actionPerformed() listener (eh2) get to handle the original actionPerformed() event.
If eh2 was also a listener to itemStateChanged() events on component c2, then it would appear to eh2 that the itemStateChanged() event actually happened before the actionPerformed() event. This too is surely not right.
So that answers question 1. Yes, event handling code, which modifies application state or the component tree should be scheduled for execution after the event is processed. The event handlers should inspect whatever state they need to inspect at the time of the event, but react to the event (make changes) later on the EDT, by calling EventQueue.invokeLater().
The second part of my question is about whose responsibility it is to ensure that handling of events happens after the event itself has taken place. In hindsight, this is a stupid question. The same problem exists if the event handlers are executed immediately when an event occurs, or if they are executed later by the component calling EventQueue.invokeLater().
Incidentally, while I was researching this, I saw that not all Swing component do this uniformly. For example, JCheckBox fires the itemStateChanged() events immediately when the event occurs, while JComponent fires componentResized() (via is super class java.awt.Component) later on the EDT.
So it seems that the most robust way to handle events is to first inspect your state to make decisions about what actions you will take, then perform those actions later on the EDT. Any thoughts? I'd love to hear other people's insight into this.
Related
just a question about SwingUtilities.InvokeLater().
To my understanding, any time I update my Swing interface I need to call SwingUtilities.InvokeLater to get onto the EDT. Does this need to be done if I am attempting to update my GUI from a button listener, as they button events are already on the EDT?
i.e, would i have to..
public void mouseClicked(MouseEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//GUI updates
}
});
}
or would I simply be able to...
public void mouseClicked(MouseEvent e) {
//GUI updates
}
Furthermore, Does the same logic apply if I am calling a method on an object that will update the GUI?
any time I update my Swing interface I need to call SwingUtilities.InvokeLater to get onto the EDT
Correct. This includes any time you update the model of the component, since this will also result in the repainting of the component.
Does this need to be done if I am attempting to update my GUI from a button listener, as they button events are already on the EDT?
Again correct. Since the code is automatically invoked on the EDT you do not need to manually add it to the EDT using the invokeLater().
You typically use the SwingUtilities.invokeLater() if your code is executing on a separate Thread and part of that logic needs to update a GUI component.
Updating this message :
Swing event handling code runs on a special thread known as the event dispatch thread. So all of the component(button, checkbox, radio button etc.,) actions are handled on EDT. So no need to have SwingUtilities.invokeLater() inside your button action as it always runs on EDT.
Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive.
So if you are planning to perform a long running task that could affect a GUI inside an action then better go for Worker Threads or Background Threads.
SwingWorker has doInBackground(), done() and process() methods to handle the long running tasks well without impacting the GUI.
Go through below links to get more info
Why does SwingUtilities.invokeLater() cause JButton to freeze?
What does SwingUtilities.invokeLater do?
https://www.javacodegeeks.com/2012/12/multi-threading-in-java-swing-with-swingworker.html
When it comes to events, I definitely come from an ActionScript background. I am currently working on a project using Swing in which I need to dispatch an event from one object and capture the event in the parent, and I have no idea how to do it.
In ActionScript3, you can dispatch an event with a dispatchEvent call. For example, let's say I wanted to programmatically dispatch a mouseClick event (even though the mouse was not clicked) so that some other listener will activate. I can do that by using
dispatchEvent(MouseEvent.Click);
Once that gets called, the event will bubble up through it's parent objects until it hits the top, and event listeners can capture it on the way. (Technically it bubbles down and back up, but that's outside the scope of the question, I believe). So if I want to listen for that mouseClick event in the parent object, I would just add a listener like so:
parent.addEventListener(MouseEvent.Click, Function);
Which would capture that mouseClick and perform the Function.
That's how it works in ActionScript3. I'm trying to do something similar in Java, and there appears to be some big theory changes in how Java events work. How would I do the same thing in java? Specifically, how to I programmatically dispatch an event and capture that event in a parent object?
I have done my own research on the subject, and it has merely confused me further. I have looked at:
How do I programatically send ActionEvent to JButton?
Concurrency in Swing - The Event Dispatch Thread.
Events and listeners - How do you create a custom event?
For firing events programmatically, look at AbstractButton.doClick() if you are outside the button, or preferably AbstractButton.fireActionPerformed() in a subclass.
When developing components, the lack of bubbling means that each parent component needs to handle and redispatch child component events:
innerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent buttonEvent) {
MyEvent myEvent = ... // process buttonEvent
fireMyEventHappened(myEvent);
}
});
The Component class has a dispatchEvent(...) method, so you can create and dispatch an event to any component directly.
Or if you want to generate an OS event manually then you can use the Robot class and Java will do the dispatching of the event for you. In this case
When we implement Listener, Renderer or Editor, inside methods how Java its calling automatically?
Code:
Class A implements ActionListener{
A(){
//bla bla
//bla bla
this.addActionListener(btn);
}
public void actionPerformed(ActionEvent e){**// How actionPerformed method called //automatically if we register button**
}
}
How its calling actionPerformed method automatically after registering button object? We are just passing the btn object into addActionListener(btn). How inside its calling that method?
I checked through netbeans inside addActionListener method*. There is no calling method of actionPerformed method. Also if we register it keeps on working. Is it calling by thread anywhere inside? But i checked source code. nothing is there. How?
Events are dispatched from an EventListenerList, owned by the parent JComponent, using a convention outlined in the API and discussed here. Editors and Renderers are evoked by the owning view component.
Addendum: Can we create interface same as it is? How?
Yes, JFreeChart is a fairly accessible example. Although a chart is not itself a JComponent, it uses the same model for its own events.
In Java, anything which happens upon any windows component is dealt with by the Event Dispatcher Thread:
The event dispatching thread (EDT) is a background thread used in Java
to process events from the Abstract Window Toolkit (AWT) graphical
user interface event queue. These events are primarily update events
that cause user interface components to redraw themselves, or input
events from input devices such as the mouse or keyboard.
Whenever you click or do some event, it is the EDT which kick starts the action listener, which is why doing any Thread.sleep in your action listener will eventually freeze the UI for a period of time.
Since your class implements a given interface, your class will guarantee the EDT that it will have a series of methods which the EDT can use to do whatever it needs.
For more information on the EDT, please take a look at this Oracle document.
It's magic.
Event handling is taken care of for you by the AWT API. These events are then queue and dispatched to the various components (via a serious of steps). Each interested party then handles those requests that are of interest to them before passing them up the food chain till it reaches you.
The question is, should you care?
In some respects yes, but do you care how electricity works or just that you can turn on the light switch?
I'm sure there's better documentation, but you could take a look at http://docs.oracle.com/javase/1.3/docs/guide/awt/designspec/events.html for starters...
Swing calls your ActionListener automatically when the action occurs. The actual method call is located deep inside the source code of Swing.
i've panel which contains a text field for entering number and a submit button
sometimes new (updated) value can not be sent when i click the button (the previous value of the field is sent)
in the debug mode, i see that sometimes
AbstractButton.fireActionPerformed()
is called (which gets the value of the field at that time and then submits) by event dispatch thread before
JFormattedTextFiled.FocusLostHandler
and
JFormattedTextField.commitEdit()
(which updates the value of the field).
i think jbutton event should have never been called before the text field loses the focus and updates its value
any idea about the problem?
i'm using xp-sp2 and java 1.6.0_06-b02
As far as I know, Java makes no guarantees about the order of events (someone please correct me if I am wrong!). In any case, problems with the focusLost event seem to be normal. We naturally expect it to be processed before the focus actually shifts and events for the new control are initiated. This is not the case.
As the post by Catalina Island implies, the solution is to use "invokeLater". The code for your "submit" button should look something like this:
protected void buttonClick() {
Runnable doStuff = new Runnable() {
public void run() {
// Do whatever button processing is needed here
}
};
// Invoke later, so that any LostFocus event will have been processed first
SwingUtilities.invokeLater(doListSelection);
}
If you have many controls that do some processing, and many controls that could be losing the focus, there seems to be no "nice" solution. Frankly, this is a weakness in Swing: it should guarantee a logical order of events during a change of focus.
Sorry, I have re-read your question - I have misunderstood it previously.
I cannot tell you why the focus is not moved from the field, but we had a similar issue in our application, but with the JTable and edits were not committed to the CellRender despite that we have set all required table properties. We just had to move focus away from the table cell as the first action in our event listener
thanks for replies guys and excuse me starting the same therad in java forum (i was not aware of the rules): http://forums.sun.com/thread.jspa?threadID=5445465&tstart=0
anyway, actually i'm interested in the cause of the problem rather than the solution
there are two cases in the EventQueue
here are the events for case 1:
MouseEvent (MOUSE_RELEASED)
MouseEvent (MOUSE_CLICKED)
InvocationEvent
InvocationEvent
InvocationEvent
CausedFocusEvent (FOCUS_LOST; opposite: JButton; source: FormattedNumberField)
CausedFocusEvent (FOCUS_GAINED; opposite: FormattedNumberField; source: JButton)
InvocationEvent
MouseEvent (MOUSE_MOVED)
MouseEvent (MOUSE_EXITED)
and here are the events for case 2:
CausedFocusEvent (FOCUS_LOST; opposite: JButton; source: FormattedNumberField)
CausedFocusEvent (FOCUS_GAINED; opposite: FormattedNumberField; source: JButton)
InvocationEvent
InvocationEvent
...
MouseEvent (MOUSE_RELEASED)
MouseEvent (MOUSE_CLICKED)
InvocationEvent
InvocationEvent
...
MouseEvent (MOUSE_MOVED)
MouseEvent (MOUSE_EXITED)
maybe java does not guarantee the order of the events. if it's true it would be a common problem but it's an unusual and very rare situation. even i can't reproduce this problem in other gui panels. i wonder what may cause this problem.
When I write an event handler that does something with the value of another component, I reference it directly. If your 'LostFocus' handler must run before the contents are valid, and if we can't guarantee it will have run before the button action has started, it might be a good idea to move the code contained within the 'LostFocus' handler into a private method that can be accessed by that handler and the button action, so it can do the work itself. When 'LostFocus' eventually fires, it will be executed again, but this shouldn't matter.
I'm pretty sure the the EventQueue keeps things sequential, but I've seen the debugger change the apparent order when I forget to use invokeLater() from another thread.
I'm using the java swing library to develop a board game called DAO.
The problem is that after the human player makes its move, by clicking on the JButton with the piece image that he wants to play, I call the computer AI routine but inside the mouse event function. By doing this only when the function returns, the computer ends its turn, do the JButtons refresh their Images (setIcon comes in).
I'd like to know how can I force the JButtons to change their image at the moment they are clicked and not only when the mouse event function ends (as I need to handle data inside it).
I've tried all of this
myButtons[i][j].setIcon(xIcon);
myButtons[i][j].revalidate();
myButtons[i][j].repaint();
myButtons[i][j].validate();
None worked.
Thx in advance
You may want to try putting the action performed upon clicking the JButton into a Swing worker. This will allow the task to go on in the background, while the user can still click other buttons, etc.
See http://java.sun.com/docs/books/tutorial/uiswing/concurrency/simple.html.
There is a single thread used for all Swing activity.
Here's the process.
One event appears on the event queue
it is pulled from the queue and executed by The AWT Thread
Any new events created while this is executing are placed on the queue to be held until the currently running AWT event returns.
The event executing returns and the next event on the queue is dequeued and executed.
This means that if you need to do anything that takes more than, say 1/100 of a second or so, you shouldn't do it any thread started from a swing event. Instead, spawn your own thread and return the swing thread to the system so the GUI can be updated.
Now, your thread MUST NOT update any GUI objects! If you need to update a GUI object, use invokeLater to place your code back on the AWT thread.
New Java programmers not conforming to this rule and executing tasks on the AWT thread is almost certainly the biggest reason people think Java is slow.