java - Updating GUI through threads -
i'm new threads , haven't written java in long time bear me here. have simple gui. has counter, status label, , 2 buttons, start , stop respectively.
what wanted update status label using counter
thread. when hit start supposedly starts counter @ 0 , increments every second
, , when choose hit stop
should suspend
current thread , wait
start button pressed again. whenever hit stop suspends waits second , resumes counting. when in reality want stay suspended. i'm not sure why it's doing that, tried searching before posting here got nothing. feel free criticize on you'd like.
here's have:
updated per @madprogrammer's answer.
import java.awt.font; import java.awt.gridbagconstraints; import java.awt.gridbaglayout; import java.awt.event.actionevent; import java.awt.event.actionlistener; import javax.swing.jbutton; import javax.swing.jframe; import static javax.swing.jframe.exit_on_close; import javax.swing.jlabel; import javax.swing.swingutilities; public class main extends jframe { jlabel countlabel = new jlabel("0"); jlabel statuslabel = new jlabel("task not completed."); jbutton startbutton = new jbutton("start"); jbutton stopbutton = new jbutton("stop"); counterthread worker = new counterthread("worker", countlabel, statuslabel); public static void main(string[] args) { swingutilities.invokelater(new runnable() { @override public void run() { new main("counter demo"); } }); } public main(string title) { super(title); setlayout(new gridbaglayout()); countlabel.setfont(new font("serif", font.bold, 28)); gridbagconstraints gc = new gridbagconstraints(); gc.fill = gridbagconstraints.none; gc.gridx = 0; gc.gridy = 0; gc.weightx = 1; gc.weighty = 1; add(countlabel, gc); gc.gridx = 0; gc.gridy = 1; gc.weightx = 1; gc.weighty = 1; add(statuslabel, gc); gc.gridx = 0; gc.gridy = 2; gc.weightx = 1; gc.weighty = 1; add(startbutton, gc); gc.gridx = 0; gc.gridy = 3; gc.weightx = 1; gc.weighty = 1; add(stopbutton, gc); startbutton.addactionlistener(new actionlistener() { public void actionperformed(actionevent arg0) { worker.start(); //notify(); } }); stopbutton.addactionlistener(new actionlistener() { public void actionperformed(actionevent arg0) { worker.suspend(); } }); setsize(200, 400); setdefaultcloseoperation(exit_on_close); setvisible(true); } public class counterthread implements runnable { public thread t; public string threadname; boolean suspended = false; jlabel countlabelname; jlabel statuslabelname; counterthread(string name, jlabel clabel, jlabel slabel) { this.threadname = name; this.countlabelname = clabel; this.statuslabelname = slabel; } public void run() { try { // simulate doing useful. (int = 0; <= 10; i++) { synchronized (this) { if (suspended) { wait(); } } final int count = i; swingutilities.invokelater(new runnable() { public void run() { countlabelname.settext(integer.tostring(count)); } }); thread.sleep(1000); } } catch (interruptedexception e) { } swingutilities.invokelater(new runnable() { public void run() { statuslabelname.settext("completed."); } }); this.start(); } public boolean getstatus() { return t == null; } public void start() { if (getstatus()) { //t = new thread(new counterthread(this.threadname, this.countlabelname, this.statuslabelname)); t = new thread(this); t.start(); } } public void suspend() { statuslabelname.settext("task paused"); suspended = true; } //create object purpose synchronize synchronized void resume() { statuslabelname.settext("task has resumed"); suspended = false; this.notify(); } } }
basically...
synchronized(this) { if(suspended) { if(getstatus()) wait(); resume(); } }
getstatus
returning false
it's skipping wait
call (because t != null
.
i'm not sure why need check this, might have enum
or other flag returns more meaningful state (like running
, stopped
, paused
... ever)
i able make work doing like...
synchronized(this) { if(suspended) { wait(); } }
instead.
having said though. i'd consider using swing timer
work , trigger it's updates within context of edt
updated after original code modified
even suggested answer it's still behaving same way, suspends brief second , resumes right away
you modified code original post, adding
t = new thread(new counterthread(this.threadname, this.countlabelname, this.statuslabelname));
to start
method, ui code has reference counterthread
it's interacting with, have 2 instances of same class, 1 running in background ticking away , 1 ui code interacting with.
so when ui calls suspend
, it's not changing suspended
state of instance running
import java.awt.font; import java.awt.gridbagconstraints; import java.awt.gridbaglayout; import java.awt.event.actionevent; import java.awt.event.actionlistener; import javax.swing.jbutton; import javax.swing.jframe; import static javax.swing.jframe.exit_on_close; import javax.swing.jlabel; import javax.swing.swingutilities; public class main extends jframe { jlabel countlabel = new jlabel("0"); jlabel statuslabel = new jlabel("task not completed."); jbutton startbutton = new jbutton("start"); jbutton stopbutton = new jbutton("stop"); int holder; counterthread worker = new counterthread("worker", countlabel, statuslabel); public static void main(string[] args) { swingutilities.invokelater(new runnable() { @override public void run() { new main("counter demo"); } }); } public main(string title) { super(title); setlayout(new gridbaglayout()); countlabel.setfont(new font("serif", font.bold, 28)); gridbagconstraints gc = new gridbagconstraints(); gc.fill = gridbagconstraints.none; gc.gridx = 0; gc.gridy = 0; gc.weightx = 1; gc.weighty = 1; add(countlabel, gc); gc.gridx = 0; gc.gridy = 1; gc.weightx = 1; gc.weighty = 1; add(statuslabel, gc); gc.gridx = 0; gc.gridy = 2; gc.weightx = 1; gc.weighty = 1; add(startbutton, gc); gc.gridx = 0; gc.gridy = 3; gc.weightx = 1; gc.weighty = 1; add(stopbutton, gc); startbutton.addactionlistener(new actionlistener() { public void actionperformed(actionevent arg0) { worker.start(); } }); stopbutton.addactionlistener(new actionlistener() { public void actionperformed(actionevent arg0) { worker.suspend(); } }); setsize(200, 400); setdefaultcloseoperation(exit_on_close); setvisible(true); } public class counterthread implements runnable { public thread t; public string threadname; boolean suspended = false; jlabel countlabelname; jlabel statuslabelname; counterthread(string name, jlabel clabel, jlabel slabel) { this.threadname = name; this.countlabelname = clabel; this.statuslabelname = slabel; } public void run() { try { // simulate doing useful. (int = 0; <= 10; i++) { synchronized (this) { if (suspended) { wait(); } } final int count = i; swingutilities.invokelater(new runnable() { public void run() { countlabelname.settext(integer.tostring(count)); } }); thread.sleep(1000); } } catch (interruptedexception e) { } swingutilities.invokelater(new runnable() { public void run() { statuslabelname.settext("completed."); } }); this.start(); } public boolean getstatus() { return t == null; } public void start() { if (getstatus()) { //t = new thread(new counterthread(this.threadname, this.countlabelname, this.statuslabelname)); t = new thread(this); t.start(); } } public void suspend() { statuslabelname.settext("task paused"); suspended = true; } //create object purpose synchronize synchronized void resume() { statuslabelname.settext("task has resumed"); suspended = false; this.notify(); } } }
also, don't see how using swing timer me in case, since there's no actual delay wait
then don't understand how timer
works
import java.awt.font; import java.awt.gridbagconstraints; import java.awt.gridbaglayout; import java.awt.event.actionevent; import java.awt.event.actionlistener; import javax.swing.jbutton; import javax.swing.jframe; import static javax.swing.jframe.exit_on_close; import javax.swing.jlabel; import javax.swing.swingutilities; import javax.swing.timer; public class main extends jframe { jlabel countlabel = new jlabel("0"); jlabel statuslabel = new jlabel("task not completed."); jbutton startbutton = new jbutton("start"); jbutton stopbutton = new jbutton("stop"); int holder; timer timer; int count = 0; public static void main(string[] args) { swingutilities.invokelater(new runnable() { @override public void run() { new main("counter demo"); } }); } public main(string title) { super(title); setlayout(new gridbaglayout()); countlabel.setfont(new font("serif", font.bold, 28)); gridbagconstraints gc = new gridbagconstraints(); gc.fill = gridbagconstraints.none; gc.gridx = 0; gc.gridy = 0; gc.weightx = 1; gc.weighty = 1; add(countlabel, gc); gc.gridx = 0; gc.gridy = 1; gc.weightx = 1; gc.weighty = 1; add(statuslabel, gc); gc.gridx = 0; gc.gridy = 2; gc.weightx = 1; gc.weighty = 1; add(startbutton, gc); gc.gridx = 0; gc.gridy = 3; gc.weightx = 1; gc.weighty = 1; add(stopbutton, gc); timer = new timer(1000, new actionlistener() { @override public void actionperformed(actionevent e) { count++; countlabel.settext(integer.tostring(count)); } }); startbutton.addactionlistener(new actionlistener() { public void actionperformed(actionevent arg0) { timer.start(); } }); stopbutton.addactionlistener(new actionlistener() { public void actionperformed(actionevent arg0) { if (timer.isrunning()) { timer.stop(); stopbutton.settext("resume"); } else { timer.restart(); stopbutton.settext("stop"); } } }); setsize(200, 400); setdefaultcloseoperation(exit_on_close); setvisible(true); } }
now, there pause , resume issues taken care off
Comments
Post a Comment