Unable to dispatch an ActionEvent

F

Florence HENRY

Hello,

I'm trying to fire an ActionEvent since a secondary thread in a java
application. I tried to somplify the code as mush as possible, but I
can't figure out why it does not work.

Here is the code :

// SimulateButton.java

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;

public class SimulateButton implements ActionListener {

public Component createComponents() {
JButton b1 = new JButton("Button 1");
b1.addActionListener(this);
b1.setActionCommand("button 1 pressed");

Simulateur simulateur = new Simulateur("test");
simulateur.start();

return b1;
}

private static void createAndShowGUI() {
JFrame frame = new JFrame("");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SimulateButton simul = new SimulateButton();
Component contents = simul.createComponents();
frame.getContentPane().add(contents);
frame.pack();
frame.setVisible(true);
}

public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}

public void actionPerformed(ActionEvent ae) {
System.err.println(ae.getActionCommand());
}

}

// Simulateur.java

import java.awt.Toolkit;
import java.awt.event.ActionEvent;

public class Simulateur extends Thread {

public Simulateur(String str) {
super(str);
}

public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(i + " " + getName());
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
"simulated button"));
try {
sleep(1000);
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}

At the execution, I get :

$ java SimulateButton
0 test
unable to dispatch event:
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=simulated
button,when=0,modifiers=] on Thread[test,6,main]
1 test
unable to dispatch event:
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=simulated
button,when=0,modifiers=] on Thread[test,6,main]
2 test
unable to dispatch event:
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=simulated
button,when=0,modifiers=] on Thread[test,6,main]
DONE! test

Could someone explain to me why I cannot fire this ActionEvent ?
Thanks
 
C

Chris Smith

Florence HENRY said:
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
"simulated button"));
At the execution, I get :

$ java SimulateButton
0 test
unable to dispatch event:
java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=simulated
button,when=0,modifiers=] on Thread[test,6,main]

[...]

The source for your ActionEvent is being set to an instance of Thread.
There's no way for the event queue to know that you intend for this
event to apply to the JButton you created in your other class. You
should keep a reference to the JButton and use it as an event source.

(Not tested, though. There may be other problems as well.)

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
F

Florence HENRY

Chris Smith said:
The source for your ActionEvent is being set to an instance of Thread.
There's no way for the event queue to know that you intend for this
event to apply to the JButton you created in your other class. You
should keep a reference to the JButton and use it as an event source.

(Not tested, though. There may be other problems as well.)

Unfortunately, it still doesn't work. I modified the code this way :

public class Simulateur extends Thread {
JButton b1;

public Simulateur(String str, JButton b1) {
super(str);
this.b1 = b1;
}

public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(i + " " + getName());
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
new ActionEvent(b1, ActionEvent.ACTION_PERFORMED,
// ^^ b1 instead of "this"
"simulated button"));
try {
sleep(1000);
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}

But the action is not handled by the button : no corresponding message
appear.

In addition, something is worrying me : I was told that for
multi-threading applications, it was necessary (to be thread-safe) that
the secondary thread does not touch at all at the graphical interface.

How then a secondary thread can send a signal to the event dispatching
thread, if it is necessary to keep a reference on an object ?
 
M

Matt Humphrey

Florence HENRY said:
Unfortunately, it still doesn't work. I modified the code this way :

public class Simulateur extends Thread {
JButton b1;

public Simulateur(String str, JButton b1) {
super(str);
this.b1 = b1;
}

public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(i + " " + getName());
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(
new ActionEvent(b1, ActionEvent.ACTION_PERFORMED,
// ^^ b1 instead of "this"
"simulated button"));
try {
sleep(1000);
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}

But the action is not handled by the button : no corresponding message
appear.

In addition, something is worrying me : I was told that for
multi-threading applications, it was necessary (to be thread-safe) that
the secondary thread does not touch at all at the graphical interface.

That's not quite true. Other threads may keep references to GUI objects and
use these references either to invoke repaint or as part of some larger
update that takes place within an invokeLater Runnable. It's only that they
shouldn't attempt to modify the GUI components from the non-GUI thread. (As
a matter of design, I prefer to not have GUI Component references in other
threads and rather have the GUI Components be listeners to model changes.)

http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
F

Florence HENRY

Matt Humphrey said:
As a matter of design, I prefer to not have GUI Component references in
other threads and rather have the GUI Components be listeners to model
changes.

I would prefer too. But I cannot manage to do it. My initial problem was
the communication between the GUI-thread nad the non-GUI one.

For the GUI-thread -> non-GUI thread, it is quite easy with a put() and
get() method on a lock.

My problem arises when I need the result of the time-consuming task
performed by the non-GUI thread. How to alert the GUI-thread that the
result is ready ?

That's why I had the idea to fire an ActionEvent (by the non-GUI thread)
that would be handled by the GUI-thread.

So, you said that you managed to have the GUI Components be listeners to
model changes. Could you please explain me how this works ?

thanks for the pointer.
 
M

Matt Humphrey

Florence HENRY said:
I would prefer too. But I cannot manage to do it. My initial problem was
the communication between the GUI-thread nad the non-GUI one.

For the GUI-thread -> non-GUI thread, it is quite easy with a put() and
get() method on a lock.

My problem arises when I need the result of the time-consuming task
performed by the non-GUI thread. How to alert the GUI-thread that the
result is ready ?

That's why I had the idea to fire an ActionEvent (by the non-GUI thread)
that would be handled by the GUI-thread.

So, you said that you managed to have the GUI Components be listeners to
model changes. Could you please explain me how this works ?

In MVC it's normal for the view to have access to the model, but not for the
model to have access to the view. I create my GUI Components (especially
custom frames, dialogs, visualizations, etc) with a reference to the model
that they represent. During update and rendering the GUI queries out the
state of the model. If the model has threads the query operations engage
whatever locking is necessary. The model is accompanied by an interface
that describes the kinds of changes that can occur to it. This can be as
simple as "model updated" to very refined, including special information for
the state of any model threads. Model threads would trigger listener methods
asynchronously. The GUI implements the interface (usually as a part of
itself) and registers itself as a listener to the model. When the thread
updates the model, the model announces the change to its listeners. The
listener must be aware that the method can be invoked asynchronously and
(for GUIs) call invokeLater on whatever code the GUI needs to actually
accomodate the update.

This design achieves my goal of keeping the model completely independent of
the view and it gives me a good framework for verifying thread safety.

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
C

Christian Kaufhold

Florence HENRY said:
I'm trying to fire an ActionEvent since a secondary thread in a java
application. I tried to somplify the code as mush as possible, but I
can't figure out why it does not work.

For JButton (and generally Swing-related events), events are not dis-
patched by the event-queue.

In your specific case, "doClick" may be appropriate.


Christian
 
F

Florence HENRY

Christian Kaufhold said:
For JButton (and generally Swing-related events), events are not dis-
patched by the event-queue.

In your specific case, "doClick" may be appropriate.

Thanks, but I took here the JButton for example. In my real case, there
is no button. I am just trying to understand how to communicate between
threads.
 
N

Nigel Wade

Florence said:
I would prefer too. But I cannot manage to do it. My initial problem was
the communication between the GUI-thread nad the non-GUI one.

For the GUI-thread -> non-GUI thread, it is quite easy with a put() and
get() method on a lock.

My problem arises when I need the result of the time-consuming task
performed by the non-GUI thread. How to alert the GUI-thread that the
result is ready ?

Have a look at the SwingWorker class in the Swing Tutorial. It contains a
good example of how to achieve this.

http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html#SwingWorker
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top