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