• Post Reply Bookmark Topic Watch Topic
  • New Topic

Pattern for GUI's with threads  RSS feed

Jerry Pulley
Ranch Hand
Posts: 221
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In answering another post, I ran afoul of the single-thread rule: code which modifies GUI components must run in the AWT event thread. Evidently this applies to AWT-only programs as well as Swing. I eventually came up with this approach and I'd like to invite comments - does anyone have a better way?
Many introductory thread examples use bouncing balls or moving particles displayed on a <code>Canvas</code>, with one thread per ball. These examples get around the single-thread rule by not doing any GUI manipulations directly from the worker threads. Instead they arrange for paint events to be posted to the event queue, so that the actual GUI work is performed from the proper thread. (They never seem to point this out, either...) Granted that's a great way to design a program, but what if <code>paint</code> isn't what you want but instead you must do some kind of GUI update that isn't available via the event route but only by a direct method call (like <code>TextField.setText</code>)?
You need then to use <code>EventQueue.invokeLater</code> or <code>invokeAndWait</code> to insert your desired modifications into the AWT event thread. These methods take a <code>Runnable</code> object (you don't make a thread out of this object, it's another use of <code>Runnable</code>) and execute its <code>run</code> method in the appropriate thread.
This program involves two threads that increment separate counters and update text fields in the GUI. Only one of the counting threads is to run at one time; a GUI button toggles between them. The threads synchronize on a common monitor object, and there's back and forth communication between them and the GUI to keep track of who's running. <code>notify</code> must be called from the thread owning the lock, so that determines the placement of the lock control calls.
What do you think? Have you done this before and found a better way? What I don't like is the tight coupling between the <code>Frame</code> and the threads.<pre><code>
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
public class Test9009 {
TextField field1;
TextField field2;
Button btn;
Intermediary runningThread;
Object monitor = new Object();
Test9009() {
Frame theFrame = new Frame();
theFrame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
System.exit( 0 );
field1 = new TextField( 10 );
field2 = new TextField( 10 );
btn = new Button( "Toggle running thread" );
btn.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e ) {
theFrame.add( field1, BorderLayout.WEST );
theFrame.add( field2, BorderLayout.EAST );
theFrame.add( btn, BorderLayout.NORTH );
theFrame.setSize( 300, 75 );
Intermediary t1 = new Intermediary( this, field1 );
Intermediary t2 = new Intermediary( this, field2 );
new Thread( t1 ).start();
new Thread( t2 ).start();
void setRunningThread( Intermediary t ) {
runningThread = t;
public static void main( String[] args ) {
Test9009 me = new Test9009();
class Intermediary implements Runnable {
Incrementer incrementer;
boolean paused = false;
Test9009 mainFrame;
Intermediary( Test9009 mf, TextField fld ) {
mainFrame = mf;
incrementer = new Incrementer( fld );
public void pause() {
paused = true;
public void run() {
synchronized (mainFrame.monitor) {
while (true) {
try {
if (paused) {
paused = false;
EventQueue.invokeAndWait( incrementer );
mainFrame.setRunningThread( this );
Thread.currentThread().sleep( 100 );
} catch (InterruptedException e) {
} catch (InvocationTargetException e) {
class Incrementer implements Runnable {
private TextField myField;
private int myCounter;
Incrementer( TextField fld ) {
myField = fld;
public void run() {
myField.setText( "" + myCounter++ );
P.S. Credit to Barry Andrews for raising this problem; my interest in it was sparked by his post.

[This message has been edited by Jerry Pulley (edited October 08, 2000).]
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!