180 likes | 287 Views
Java Applets- Using SwingWorker. Dave Price and Chris Loftus Computer Science Department University of Wales, Aberystwyth. Talk overview. Handling computationally complex work in a JApplet or other Swing based application. SwingWorker – Java 5 Approach SwingWorker – Java 6 Approach.
E N D
Java Applets- Using SwingWorker Dave Price and Chris Loftus Computer Science Department University of Wales, Aberystwyth
Talk overview • Handling computationally complex work in a JApplet or other Swing based application. • SwingWorker – Java 5 Approach • SwingWorker – Java 6 Approach
Doing computational complex work in an Applet • Interface can “freeze” • Need thus to do computation on another thread • Can use SwingWorker • Was extra download with Java 5 • Now part of Java 6, but with redesigned interface
SwingWorker in Java 5 import java.awt.*; import javax.swing.*; import java.awt.event.*; // This example by Dave Price inspired by code from Lynda Thomas // The example shows how to use SwingUtilities.invokeAndWait // to build a user interface. // It also shows how to do computationally intensive // work in a separate thread use the SwingWorker class. // NOTE: This uses the non-jvm versions of SwingWorker which // developers had to download and compile with their classes. // Java 6 now includes an implementation of SwingWorker // but with slightly different methods and usage etc. // Note: This also includes a button that tries to directly // cause computationally intensive code to run and thus, // if used, causes the whole Swing interface to lock up, indeed // it can even cause the browser to freeze. // There is also another interesting "feature". If a user // clicks the "run" button multiple times you end up // with multiple SwingWorker threads, each trying to update // the displayed counter text. Try doing this and watch effect. // Clicking the stop button after multiple run clicks fixes // it though as all threads spot that they are supposed to stop.
public class JTestSwing extends JApplet implements ActionListener { JPanel buttonPanel; NewPanel myMessageSpace; JButton runButton, runWrongButton, stopButton; public void init() { // In this init method we ask the event dispatch thread // to build our user interface rather than doing it ourself try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { buildTestGui(); } }); } catch (Exception e) { System.err.println("Attempt to use invokeAndWait threw exception " + e); } }
public void buildTestGui() { // This method builds our user interface buttonPanel=new JPanel(); runButton=new JButton("run"); runWrongButton=new JButton("runWrong"); stopButton=new JButton("stop"); buttonPanel.add(runButton); buttonPanel.add(runWrongButton); buttonPanel.add(stopButton); runButton.addActionListener(this); runWrongButton.addActionListener(this); stopButton.addActionListener(this); getContentPane().add("North",buttonPanel); myMessageSpace=new NewPanel("Click to make live!"); myMessageSpace.setMinimumSize(new Dimension(50,200)); myMessageSpace.setBorder(BorderFactory.createLineBorder(Color.black,6)); getContentPane().add("Center",myMessageSpace); setVisible(true); }
public void actionPerformed(ActionEvent e){ // This checks which button was pressed and calls // the appropriate method if (e.getSource()==runButton) myMessageSpace.startCalc(); if (e.getSource()==runWrongButton) myMessageSpace.sillyCalc(); if (e.getSource()==stopButton){ myMessageSpace.stopit(); } } //class for the message area class NewPanel extends JPanel { private String s; private boolean keepGoing; public NewPanel(String initstring) { setBackground(Color.white); s=initstring; }
public void paintComponent(Graphics g) { super.paintComponent(g); g.drawString(s,70,20); } public void startCalc(){ // This method has work to do and so // properly creates a SwingWorker, that is, // another thread to do that work SwingWorker worker = new SwingWorker() { public Object construct() { return doCalc(); } }; // now tell that thread to do its work worker.start(); } public void sillyCalc(){ // This foolish method tries to directly do the work. // This is running in the event dispatch thread which thus gets // stuck in this code and thus the Swing interface freezes // Note: this can even make the whole browser become unusable so // that you have to kill it! doCalc(); }
Object doCalc() { // Now the work itself. This runs // for ever until something manages to // set keepGoing to be false int i=0; keepGoing=true; try{ while (keepGoing) { s="counter "+i+" now"; repaint(); i++; Thread.sleep(200); } } catch (InterruptedException e) { return null; } return null; } public void stopit(){ // Someone has now pressed stop button so we can // set keepGoing false which other threads will spot // and thus hopefully stop what they are doing keepGoing=false; s="stopped"; repaint(); } } }
SwingWorker in Java 6 import java.awt.*; import javax.swing.*; import java.awt.event.*; // This example by Dave Price inspired by code from Lynda Thomas // The example shows how to use SwingUtilities.invokeAndWait // to build a user interface. // It also shows how to do computationally intensive // work in a separate thread use the SwingWorker class. // Note: Java 6 now includes an implementation of SwingWorker // but with slightly different methods and usage etc. // to the previous version of SwingWorker which // developers had to download and compile with their classes. // Note: This also includes a button that tries to directly // cause computationally intensive code to run and thus, // if used, causes the whole Swing interface to lock up, indeed // it can even cause the browser to freeze. // There is also another interesting "feature". If a user // clicks the "run" button multiple times you end up // with multiple SwingWorker threads, each trying to update // the displayed counter text. Try doing this and watch effect. // Clicking the stop button after multiple run clicks fixes // it though as all threads spot that they are supposed to stop.
public class JTestSwing extends JApplet implements ActionListener { JPanel buttonPanel; NewPanel myMessageSpace; JButton runButton, runWrongButton, stopButton; public void init() { // In this init method we ask the event dispatch thread // to build our user interface rather than doing it ourself try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { buildTestGui(); } }); } catch (Exception e) { System.err.println("Attempt to use invokeAndWait threw exception " + e); } }
public void buildTestGui() { // This method builds our user interface buttonPanel=new JPanel(); runButton=new JButton("run"); runWrongButton=new JButton("runWrong"); stopButton=new JButton("stop"); buttonPanel.add(runButton); buttonPanel.add(runWrongButton); buttonPanel.add(stopButton); runButton.addActionListener(this); runWrongButton.addActionListener(this); stopButton.addActionListener(this); getContentPane().add("North",buttonPanel); myMessageSpace=new NewPanel("Click to make live!"); myMessageSpace.setMinimumSize(new Dimension(50,200)); myMessageSpace.setBorder(BorderFactory.createLineBorder(Color.black,6)); getContentPane().add("Center",myMessageSpace); setVisible(true); }
public void actionPerformed(ActionEvent e){ // This checks which button was pressed and calls // the appropriate method if (e.getSource()==runButton) myMessageSpace.startCalc(); if (e.getSource()==runWrongButton) myMessageSpace.sillyCalc(); if (e.getSource()==stopButton){ myMessageSpace.stopit(); } } //class for the message area class NewPanel extends JPanel { private String s; private boolean keepGoing; public NewPanel(String initstring) { setBackground(Color.white); s=initstring; }
public void paintComponent(Graphics g) { super.paintComponent(g); g.drawString(s,70,20); } public void startCalc(){ // This method has work to do and so // properly creates a SwingWorker, that is, // another thread to do that work SwingWorker worker = new SwingWorker<Void,Void>() { public Void doInBackground() { return doCalc(); } }; // now tell that thread to do its work worker.execute(); } public void sillyCalc(){ // This foolish method tries to directly do the work. // This is running in the event dispatch thread which thus gets // stuck in this code and thus the Swing interface freezes // Note: this can even make the whole browser become unusable so // that you have to kill it! doCalc(); }
Void doCalc() { // Now the work itself. This runs // for ever until something manages to // set keepGoing to be false int i=0; keepGoing=true; try{ while (keepGoing) { s="counter "+i+" now"; repaint(); i++; Thread.sleep(200); } } catch (InterruptedException e) { return null; } return null; } public void stopit(){ // Someone has now pressed stop button so we can // set keepGoing false which other threads will spot // and thus hopefully stop what they are doing keepGoing=false; s="stopped"; repaint(); } } }
The “Real” differences The comments differ as follows: 13,15c13 < // NOTE: This uses the non-jvm versions of SwingWorker which < // developers had to download and compile with their classes. < // Java 6 now includes an implementation of SwingWorker --- > // Note: Java 6 now includes an implementation of SwingWorker 16a15,16 > // to the previous version of SwingWorker which > // developers had to download and compile with their classes.
The “Real” differences 122,123c122,123 < SwingWorker worker = new SwingWorker() { < public Object construct() { --- > SwingWorker worker = new SwingWorker<Void,Void>() { > public Void doInBackground() { 130c130 < worker.start(); --- > worker.execute(); 144c144 < Object doCalc() { --- > Void doCalc() {
Conclusions • If you build the GUI on the thread that is executing in the init() method things can go wrong • If you directly execute computationally intensive code in the Swing GUI thread then your whole JApplet (or Java Application) can lock up, possibly meaning you have to kill the whole browser or JVM.