26
CS12420 – Swing and threads Lynda Thomas [email protected]

CS12420 – Swing and threads Lynda Thomas [email protected]

Embed Size (px)

Citation preview

Page 1: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

CS12420 – Swing and threads

Lynda Thomas

[email protected]

Page 2: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

Thread

• Thread of control– The idea was covered by Chris

• Can have multiple ones in one program

• See example Bouncer in this directory

Page 3: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk
Page 4: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

In fact,

• We have already been using multiple threads, because

• When you use event handling code, this is handled by a different thread

Page 5: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

Concurrency and Swing tutorial

http://java.sun.com/docs/books/tutorial/ uiswing/concurrency/index.html

A well-written Swing program uses concurrency to create a user interface that never "freezes" — the program is always responsive to user interaction, no matter what it's doing

Page 6: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

A Swing programmer deals with the following kinds of threads:

• Initial threads, the threads that execute initial application code.

• The event dispatch thread, where all event-handling code is executed. Most code that interacts with the Swing framework must also execute on this thread.

• Worker threads, also known as background threads, where time-consuming background tasks are executed.

The programmer does not need to provide code that explicitly creates these threads: they are provided by the runtime or the Swing framework.

But the programmer works with them!

Page 7: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

BUT what have we been doing?

• Initial threads, the threads that execute initial application code.

• The event dispatch thread, where all event-handling code is executed. Most code that interacts with the Swing framework must also execute on this thread.

• Worker threads, also known as background threads, where time-consuming background tasks are executed.

We have created our GUIs here!

We would have done complex

stuff here – since all we had

Should have done it here

Should have done it here

Page 8: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

…what you ?need? to know (cookbook style)

1. invokeLater()

2. SwingWorker

And a couple of other things

1. Threads for animation

2. Double Buffering

Page 9: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

1. invokeLater()

Swing components should be created, queried, and manipulated on the event-dispatching thread

We have not been doing this.

public static void invokeLater(Runnable runnable) – Causes runnable to have its run method called

in the dispatch thread of the EventQueue. This will happen after all pending events are processed.

Page 10: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

So…

• Look at the new Bank in this directory

• It calls invokeLater() to be sure that the GUI is built in the right thread - we should ask the event dispatch thread to build our user interface rather than doing it ourself

• Code next slide

Page 11: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

NEW:

public static void main(String args[]) { new BankSwingMVC();}

public BankSwingMVC() {try {

SwingUtilities.invokeLater(new Runnable() { public void run() {

buildBankSwing(); }

} );

} catch (Exception e) {

S.o.p("invokeLater exception"+e); } }

public void buildBankSwing() {setTitle("Bank"); setDefaultCloseOperation(…..);buttonPanel = new ButtonPanel(this);add ("North",buttonPanel); textPanel = new TextPanel();add ("Center",textPanel); pack(); setVisible(true);

}

OLD:

public static void main(String args[]) { new BankSwingMVC();}

//constructor builds a window

public BankSwingMVC() {setTitle("Bank"); setDefaultCloseOperation(…..);buttonPanel = new ButtonPanel(this);add("North",buttonPanel); textPanel = new TextPanel();add("Center",textPanel); pack();setVisible(true);

}

……

Page 12: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

2. SwingWorker

• Time consuming code needs to be placed in a separate thread so that your GUI can still operate while it is running

• Since Java 1.6 this has been formalised in a SwingWorker thread

• First let’s run the code to see WHY THIS IS A PROBLEM

• Life-no-threads – doesn’t work properly• No update• Can’t stop• Can’t even quit

Page 13: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

How apply to Life

• There are 3 subdirectories here:– Life-no-threads – doesn’t work properly– Life-home-made-threads – an old solution– Life-properlythreads – PROPER WAY OF DOING IT

– I’m actually going to go over the older solution, because it is easier to see the forest for the trees

– see next slide

Page 14: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

Basic algorithm for when runningpublic void runalot() { int i=0; s=“first iteration" ;

while (true) { calc(); if (!change()) {

s="stable in "+i+" moves"; repaint(); break;} if (i==100){

s="100 times still changing";repaint();break;}

copy(); i++; s=i+" iterations";

try{ Thread.sleep(20); } catch (Exception e) {

System.out.println("exception "+e);}

repaint(); } }

forever{ calculate next generation copy into current generation slowdown paint screen}

Page 15: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

The problem is that runalot() is resource intensive

particularly calc() which looks at every square many times

for every square (all 100 of them) look at ALL its neighbours and decide

if it lives in next generation

While it is running nothing else can happenSo, instead, it needs to be in its own thread

DOESN’T WORK:public void actionPerformed(ActionEvent e){ if (e.getSource()==b1) c.step(); if (e.getSource()==b2) c.clear(); if (e.getSource()==b3) c.runalot(); if (e.getSource()==b4)

c.stopit(); }….class NewCanvas extends JPanelimplements MouseListener {//lots deletedpublic void runalot() { int i=0; s="1 iteration" ; while (true) { calc(); if (!change()) {

s="stable in "+i+" moves"; repaint(); break;}

if (i==100){s="100 times still

changing";repaint();break;}

copy(); i++; s=i+" iterations"; try{ Thread.sleep(20); } catch (Exception e) {

System.out.println("exception "+e);}

//tried it with the above and without still won't repaint or stop!

repaint(); } }

Page 16: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

OLD (homemade solution WORKS)://lots deleted//in the actionPerformed() : if (e.getSource()==b3){

runningThread=new Thread(c); runningThread.start();}

class NewCanvas extends JPanelimplements MouseListener, Runnable{//lots deletedpublic void run(){ //calling start() calls run() int i=0; s=“first iteration" ;

keepGoing=true; try{while (keepGoing) { calc(); if (!change()) {

s="stable in "+i+" moves"; repaint(); break;} if (i==100) {

s="100 still changing"; repaint(); break;} copy(); i++; s=i+" iterations";

Thread.sleep(200); repaint(); } } catch (InterruptedException e) {

}}

DOESN’T WORK:public void actionPerformed(ActionEvent e){ if (e.getSource()==b1) c.step(); if (e.getSource()==b2) c.clear(); if (e.getSource()==b3) c.runalot(); if (e.getSource()==b4)

c.stopit(); }….class NewCanvas extends JPanelimplements MouseListener {//lots deletedpublic void runalot() { int i=0; s=first iteration" ; while (true) { calc(); if (!change()) {

s="stable in "+i+" moves"; repaint(); break;}

if (i==100){s="100 times still

changing";repaint();break;}

copy(); i++; s=i+" iterations"; try{ Thread.sleep(20); } catch (Exception e) {

System.out.println("exception "+e);}

//tried it with the above and without still won't repaint or stop!

repaint(); } }

Page 17: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

CORRECT SOLUTION Java6 and later:class NewCanvas extends JPanel implements MouseListener { //no need for Runnable lots deletedpublic void startCalc(){ // This method has work to do and so properly creates a SwingWorker, that is, // gets another thread to do that work see ***** below for how kicked off class Calculator extends SwingWorker<List<String>, String> { public List<String> doInBackground() { int i=0; s=“starting" ; keepGoing=true; try{ while (keepGoing) { board.calc(); i++; if (!board.isChange()) {s="stable in "+i+" moves"; repaint(); break;} if (i>=100) //had to make this >= {s="100 times still changing";repaint();break;}

board.copy(); s=“iteration “+ I; // Call the inherited publish method and publish an intermediate result. //This method prepares intermediate results ready for the event dispatch thread (EDT).

// When ready the EDT will call the process method with the list of messages. publish(s);

i++; Thread.sleep(200); } } catch (InterruptedException e) { } return null; } // Overrides the inherited process method called by the EDT when it is ready with a list of intermediate data protected void process(List<String> messagesSoFar) { for (String message : messagesSoFar) { System.out.println(message); repaint(); } } } // ***** //Create the worker object and then schedule to run it on a worker thread Calculator worker = new Calculator(); worker.execute(); }

Page 18: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

• Read more at : http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html

• The example code is at: http://java.sun.com/products/jfc/tsc/articles/threads/src/Example1.java

• If you need this you will know (GUI will seize up)• You should know about this idea, so you can look

it up when needed• And you should use the ‘invokeLater’ stuff in 1.

Page 19: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

In this lecture (so far) 2 things

• How to properly set up GUI using invokeLater()

• How to use SwingWorker so that your GUI doesn’t freeze

Here endeth the things about Swing that could be on a

CS124 exam

Page 20: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

A couple of other odds and ends

Page 21: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

1. Animation

• You may also need to use a new thread for animation

• Animation is basically just drawing different images (think on paper) in a loop (draw, cover, redraw, etc)

• Needs thread because otherwise the calls to repaint()

get stacked up and then you will not see the

multiple images

• See code in sample-animation-code directory

Page 22: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

//This is an example of how to run an animation

//It uses a class called NewCanvas to display the animation

public class Main extends JFrame implements ActionListener{

private NewCanvas c; //panel for animation

private JPanel p; //panel for button

private JButton b; //push button

///////////////////////////////////////////////////////////

public static void main(String args[]) {

new Main();

}

//////////////////The next bit is actually separate from the animation

//////////////////use the invokeLater()

public Main() {

try{

SwingUtilities.invokeLater(new Runnable()

{public void run() {

build();

}});

}

catch (Exception e) {

System.out.println("invokeLater exception"+e);

}

}

public void build(){

//deleted

}

///////////////////////////////////////////////////////when button pressed

public void actionPerformed(ActionEvent e){

if (e.getSource()==b){

c.move(); //run the animation

}

}

}

//This is the class that actually displays the animation

//puts a picture of aber in background and runs 3 faces

public class NewCanvas extends JPanel implements Runnable {

private MediaTracker mTracker;

private Image backgroundImage; //needed for background

private Image animateImage[]=new Image[3]; //needed for the images

private Thread animator; //need to run this in separate thread

private int current=0; //which image for animation

//set up

public NewCanvas() {

//all mediatracker stuff deleted

repaint();

current=0;

}

//called when button pressed

public void move(){

animator=new Thread(this);

animator.start(); //CALLS run()

}

//do the animation

public void run(){

for (int j=0;j<6;j++) { //LOOP!!!!

try {

Thread.sleep(200);

} catch (InterruptedException e) {

break;

}

current=(current+1)%3;

repaint(); //calls paintComponent()

}

}

//draw the image

public void paintComponent(Graphics g) {

Page 23: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

2. Double Buffering

• Double buffering• Change a picture all at once instead of redrawing a

bit at a time• Several years ago this was really important

because of speed• Still matters for games – these examples don’t

really show benefit• run BadUpdateFrame and GoodUpdateFrame

Page 24: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

BadUpdateFrame.java

import javax.swing.*;public class BadUpdateFrame extends SimpleFrame {

private UpdatePanel uppane;private Drawing drawing;public BadUpdateFrame() { drawing = new Drawing(); uppane = new UpdatePanel(drawing); add(uppane); pack();}public void badDemo() {

uppane.repaint();drawing.flipLines();uppane.repaint();drawing.flipLines();uppane.repaint();drawing.flipLines();

}…… //deleted

}

GoodUpdateFrame.java

/* create 2 drawings:

drawing1 and drawing2

/*

public void goodDemo() { uppane.repaint(); drawing2.flipLines(); uppane.setDrawing(drawing2); uppane.repaint(); drawing1.copy(drawing2); drawing1.flipLines(); uppane.setDrawing(drawing1); uppane.repaint();}*/

Page 25: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

There is more about this in later modules!

Page 26: CS12420 – Swing and threads Lynda Thomas ltt@aber.ac.uk

What have I taught that could be on an exam?

• What is a design pattern?• What is the MVC design pattern?• What is the Observer/Observable design pattern?• Why do we need SwingWorker threads?• What does invokeLater() do?• What does a Listener class do and how do you use it?• Suppose I want to put a button in a Swing application,

what are the three things that I need to do?