I was reading different threads on the subject which suggested the Swing Timer class or SwingUtilities.InvokeLater
...but I am having a lot of trouble wrapping my head around them.
I used atomicInteger to create my countdown timer and it works fine in the console. However, When I try to incorporate it in Swing, it only updates the starting and ending value (e.g. set a 5 sec countdown will display in the frame: "5" -> after 5 seconds -> "0".
Is there any simple way for me to keep and "refresh" my atomicInteger countdown label, or the only way is using the Swing Timer class?
Thank you for your patience!
ps. not homework, just trying to make myself a custom timer to study. (ie. procrastinating)
I hope this class is enough, please let me know if you need the frame/panel code as well.
private class ClickListener implements ActionListener{
public void actionPerformed(ActionEvent e){
int t_study = 5;
atomicDown.set(t_study);
if (e.getSource() == b_study){
while(atomicDown.get() > 0){
t_study = atomicDown.decrementAndGet();
l_studyTime.setText(Integer.toString(t_study));
try {
Thread.sleep(1000);
}
catch (InterruptedException e1) {
System.out.println("ERROR: Thread.sleep()");
e1.printStackTrace();
}
}
}
else if(e.getSource() == b_exit){
System.exit(0);
}
else
System.out.println("ERROR: button troll");
}
}
Thread.sleep(1000);
Don't block the EDT (Event Dispatch Thread) - the GUI will 'freeze' when that happens. Instead of calling
Thread.sleep(n)
implement a Swing Timer
for repeating tasks or a SwingWorker
for long running tasks.
See Concurrency in Swing for more details - Andrew Thompson 2012-04-05 02:41
After turning the code snippet into an SSCCE, this is what I get (which seems to work - as best as I understand the original code).
I have not changed the variable names. Please learn common Java naming conventions1 for class, method & attribute names & use it consistently.
b_study
should be more along the lines of studyButton
or similar. Some will note that 'button' should not be part of the name, but when you have a GUI with both a 'Study' button & label, I don't see any other logical way to separate them.import java.awt.event.*;
import javax.swing.*;
import java.util.concurrent.atomic.AtomicInteger;
class TimerTicker {
public static final int STUDY_TIME = 15;
AtomicInteger atomicDown = new AtomicInteger(STUDY_TIME);
JButton b_study;
JButton b_exit;
JLabel l_studyTime;
TimerTicker() {
JPanel gui = new JPanel();
b_study = new JButton("Study");
ClickListener listener = new ClickListener();
b_study.addActionListener(listener);
gui.add(b_study);
b_exit = new JButton("Exit");
b_exit.addActionListener(listener);
gui.add(b_exit);
l_studyTime = new JLabel("" + atomicDown.get());
gui.add(l_studyTime);
JOptionPane.showMessageDialog(null, gui);
}
private class ClickListener implements ActionListener {
Timer timer;
public void actionPerformed(ActionEvent e){
if (e.getSource() == b_study) {
ActionListener countDown = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (!(atomicDown.get() > 0)) {
timer.stop();
// reset the count.
atomicDown.set(STUDY_TIME);
} else {
l_studyTime.setText(
Integer.toString(
atomicDown.decrementAndGet()));
}
}
};
timer = new Timer(1000,countDown);
timer.start();
} else if(e.getSource() == b_exit) {
System.exit(0);
} else {
System.out.println("ERROR: button troll");
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TimerTicker();
}
});
}
}
Exit
button was irrelevant to something appearing in a JOptionPane
), but I wanted to stay close to the existing GUI controls and logic - Andrew Thompson 2012-04-05 04:47