|
CS 580 Client-Server Programming Fall Semester, 2002 Threads & GUI |
|
|---|---|---|
|
© 2002, All Rights Reserved, SDSU & Roger Whitney San Diego State University -- This page last updated 24-Sep-02 |
Threads & GUIs
Swing & VisualWorks GUIs maintain an event queues
Only the GUI thread should add events to the queue
Odd things may happen if
Swing Solution
Use SwingUtilities.invokeLater to run a thread to change a GUI element
For more information see:
Example
A window with:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SwingApplication {
private static String labelPrefix = "Number of button clicks: ";
private int numClicks = 0;
private UnSafeGUIAccess clock;
private JLabel label;
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
UIManager.getCrossPlatformLookAndFeelClassName());
} catch (Exception e) { }
//Create the top-level container and add contents to it.
JFrame frame = new JFrame("SwingApplication");
SwingApplication app = new SwingApplication();
Component contents = app.createComponents();
frame.getContentPane().add(contents, BorderLayout.CENTER);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);
}
public Component createComponents() {
label = new JLabel(labelPrefix + "0 ");
JButton button = new JButton("I'm a Swing button!");
button.setMnemonic(KeyEvent.VK_I);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addClicks( 1);
}
});
label.setLabelFor(button);
clock = new UnSafeGUIAccess( this );
clock.start();
clock.secondsToSleep( 2);
JPanel pane = new JPanel();
pane.setBorder(BorderFactory.createEmptyBorder(
30, //top
30, //left
10, //bottom
30) //right
);
pane.setLayout(new GridLayout(0, 1));
pane.add(button);
pane.add(label);
return pane;
}
public synchronized void addClicks(int clicksToAdd) {
numClicks = numClicks + clicksToAdd;
label.setText(labelPrefix + numClicks);
}
}
Unsafe
Thread
This
thread directly modifies a GUI element
See
gui.addClicks( 1);
public class UnSafeGUIAccess extends Thread {
private SwingApplication gui;
int sleepMillseconds;
public UnSafeGUIAccess(SwingApplication owner) {
gui = owner;
secondsToSleep( 1);
}
public void run() {
try {
while (true) {
sleep( sleepMillseconds);
gui.addClicks( 1);
}
} catch (InterruptedException interrupt) {
//On interrupt end thread
}
}
public void secondsToSleep(int seconds ) {
sleepMillseconds = seconds * 1000;
}
}
Safe
Thread
import javax.swing.SwingUtilities;
public class SafeGUIAccess extends Thread {
private SwingApplication gui;
int sleepMillseconds;
public SafeGUIAccess(SwingApplication owner) {
gui = owner;
secondsToSleep( 1);
}
public void run() {
try {
while (true) {
sleep( sleepMillseconds);
Runnable click = new Runnable() {
public void run() {
gui.addClicks( 1);
}
};
SwingUtilities.invokeLater(click);
}
} catch (InterruptedException interrupt) {
//On interrupt end thread
}
}
public void secondsToSleep(int seconds ) {
sleepMillseconds = seconds * 1000;
}
}
VisualWorks
Unsafe Example
Smalltalk defineClass: #VisualWorksApplication
superclass: #{UI.ApplicationModel}
indexedType: #none
private: false
instanceVariableNames: 'clicks sleepSeconds '
classInstanceVariableNames: ''
imports: ''
category: 'Examples-cs580'!
!VisualWorksApplication class methodsFor: 'interface specs'!
windowSpec
"UIPainter new openOnClass: self andSelector: #windowSpec"
<resource: #canvas>
^#(#{UI.FullSpec}
#window:
#(#{UI.WindowSpec}
#label: 'VW Application'
#bounds: #(#{Graphics.Rectangle} 682 378 956 576 ) )
#component:
#(#{UI.SpecCollection}
#collection: #(
#(#{UI.ActionButtonSpec}
#layout: #(#{Graphics.Rectangle} 57 22 138 45 )
#name: #ActionButton1
#model: #buttonPressed
#label: 'Smalltalk button'
#defaultable: true )
#(#{UI.LabelSpec}
#layout: #(#{Core.Point} 12 63 )
#name: #Label1
#label: 'Number of button clicks:' )
#(#{UI.InputFieldSpec}
#layout: #(#{Graphics.Rectangle} 136 63 214 87 )
#name: #InputField1
#model: #clicks
#isReadOnly: true
#type: #number ) ) ) )
Unsafe
Example Instance methods
buttonPressed
^self addClicks: 1
clicks
^clicks
initialize
super initialize.
clicks := 0 asValue.
sleepSeconds :=2.
self startClock
addClicks: anInteger
clicks value: (clicks value + anInteger)
processPriority
^60
startClock
clock :=
[
[(Delay forSeconds: sleepSeconds) wait.
self addClicks: 1] repeat]
forkAt: self processPriority
VisualWorks
Safe Example
Change
the previous startClock method to the following:
startClock
clock :=
[
[(Delay forSeconds: sleepSeconds) wait.
Processor performUIBlock: [self addClicks: 1]]
repeat]
forkAt: self processPriority
Copyright ©, All rights reserved.
2002 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.
Previous   
visitors since 24-Sep-02
   Next