I'm using the swing Timer to make a countdown clock in Netbeans:
public void startTimer() {
System.out.println(right + "value");
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.out.println("action");
timerLabel.setText("" + seconds);
--seconds;
System.out.println(seconds);
if (seconds == -1 && seconds < 0) {
System.out.print("zero");
//displayTimer.stop();
wrong();
dispose();
}
}
};
displayTimer = new Timer(1000, listener);
displayTimer.setInitialDelay(100);
displayTimer.start();
if (right == null) {
System.out.println("null");
} else if (right == true) {
System.out.println("truehere");
displayTimer.stop();
right = null;
seconds = 20;
displayTimer.setDelay(10000);
displayTimer.setInitialDelay(100);
displayTimer.start();
} else if (right == false) {
System.out.print("wrong");
//displayTimer.stop();
seconds = 20;
}
}
I just use System.out.print to test the program, it's not a part of the real program.
I call the stop() method but the timer continues to count. Also, I create a new timer by displayTimer = new javax.swing.Timer(10000, listener); but it counts twice as fast. Can anyone help?
EDIT:
Here is my timer (sort of SSCCE):
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Scanner;
import javax.swing.*;
public class JavaApplication8 {
public static void startTimer() {
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
int seconds = 20;
seconds--;
System.out.println(seconds);
if (seconds == -1 && seconds < 0) {
System.out.print("zero");
}
}
};
Timer displayTimer = new Timer(1000, listener);
displayTimer.setInitialDelay(100);
displayTimer.start();
}
public static void main(String[] args) {
System.out.println("Type win to win!");
startTimer();
String read;
Boolean right;
int seconds;
Scanner scanIn = new Scanner(System.in);
read = scanIn.nextLine();
if (read.equals("win")){
right = true;
}
else{
right = false;
}
if (right == true) {
System.out.println("correct");
//displayTimer.stop();
right = null;
seconds = 20;
//displayTimer.setDelay(10000);
//displayTimer.setInitialDelay(100);
//displayTimer.start();
} else if (right == false) {
System.out.print("incorrect");
//displayTimer.stop();
seconds = 20;
right = null;
}
}
}
it doesn't work right in that the seconds don't show up, but it does show 20 times which is what I want. This is just in its own application, in my real program it is easier to see the problem.
I've noticed that the first time the game runs it works fine. Then I click play again (resets the whole game) and it goes twice as fast. Maybe I'm not resetting something correctly? Here is my reset code:
// Reset Everything
PlayFrame.seconds = 20;
PlayFrame.winnings = 0;
PlayFrame.right = false;
//PlayFrame.displayTimer.stop();
PlayFrame.questionLabel.setText(null);
PlayFrame.count = 0;
WelcomeFrame WFrame = new WelcomeFrame();
WFrame.setVisible(true);
setVisible(false);
PlayFrame P = new PlayFrame();
P.dispose();
if (PlayFrame.seconds == -1 && PlayFrame.seconds < 0){
PlayFrame.displayTimer.stop();
}
}
Its just pseudo code to see how timer can be started and stopped.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.Timer;
public class TimerOnJLabel extends JFrame {
private static final long serialVersionUID = 1L;
long start = System.currentTimeMillis();
long elapsedTimeMillis;
int sec = 5;
Timer timer;
public TimerOnJLabel() {
super("TooltipInSwing");
setSize(400, 300);
getContentPane().setLayout(new FlowLayout());
final JLabel b1;
final JRadioButton jrb = new JRadioButton();
b1 = new JLabel("Simple tooltip 1");
ActionListener timerTask = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
elapsedTimeMillis = System.currentTimeMillis();
b1.setText("Timer : " + (elapsedTimeMillis-start)/1000+" ::::: " +sec);
System.out.println("Timer working: " + sec);
if(--sec == 0){
timer.stop();
System.out.println("Timer Stopped");
}
}
};
timer = new Timer(1000, timerTask);
System.out.println("Timer Started");
timer.start();
getContentPane().add(b1);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
}
public static void main(String args[]){
new TimerOnJLabel();
}
}
I hope this help.
Related
I'm trying to make a timer that will count up from 00h:00m:00s, with the ability to pause and restart the count from its current time.
Heres the solution I currently have: It will always restart the timer from 0 instead of continuing where it left off. Also, for another inexplicable reason, the hours always display as 07 instead of 00. Does anyone know how I could fix these issues, to have it start counting up from its previous value, and display the correct amount of hours elapsed?
private final SimpleDateFormat date = new SimpleDateFormat("KK:mm:ss");
private long startTime = 0;
private final ClockListener clock = new ClockListener();
private final Timer normalTimer = new Timer(53, clock);
startTimerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(startTime == 0) {
startTime = System.currentTimeMillis();
}
else {
startTime += (System.currentTimeMillis() - startTime);
}
normalTimer.start();
}
});
stopTimerButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
normalTimer.stop();
}
});
private void updateClock(){
Date elapsed = new Date(System.currentTimeMillis() - startTime);
timerText.setText(date.format(elapsed));
}
private class ClockListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
updateClock();
}
}
Introduction
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section.
Your code wasn't runnable, so I created the following GUI.
When you press the "Start" button, the timer starts counting. 37 seconds.
2 minutes, 7 seconds.
1 hour, 6 minutes, 11 seconds.
Pressing the "Pause button pauses the count. Pressing the "Restart" button resumes the count. You can pause and resume the count as many times as you want.
Pressing the "Stop" button stops the counter. You can press the "Reset" button to reset the counter before starting again.
Explanation
When creating a Swing application, using the model-view-controller (MVC) pattern helps to separate your concerns and allows you to focus on one part of the application at a time.
Creating the application model made creating the GUI much easier. The application model is made up of one or more plain Java getter/setter classes.
The CountupTimerModel class keeps long fields to hold the duration in milliseconds and the previous duration. This way, I don't have to pause and restart the Swing Timer.
The duration is the difference between the current time and the start time. I use the System.currentTimeMillis() method to calculate the duration.
The GUI is fairly straightforward.
I made the JButton ActionListeners lambdas. I made the TimerListener a separate class to move the code out of that particular lambda.
Code
Here's the complete runnable code. I made the additional classes inner classes so I could post the code as one block.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class CountupTimerGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CountupTimerGUI());
}
private final CountupTimerModel model;
private JButton resetButton, pauseButton, stopButton;
private JLabel timerLabel;
public CountupTimerGUI() {
this.model = new CountupTimerModel();
}
#Override
public void run() {
JFrame frame = new JFrame("Countup Timer GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createDisplayPanel(), BorderLayout.NORTH);
frame.add(createButtonPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createDisplayPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
Font font = panel.getFont().deriveFont(Font.BOLD, 48f);
timerLabel = new JLabel(model.getFormattedDuration());
timerLabel.setFont(font);
panel.add(timerLabel);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 5, 5, 5));
Font font = panel.getFont().deriveFont(Font.PLAIN, 16f);
resetButton = new JButton("Reset");
resetButton.setFont(font);
panel.add(resetButton);
resetButton.addActionListener(event -> {
model.resetDuration();
timerLabel.setText(model.getFormattedDuration());
});
pauseButton = new JButton("Restart");
pauseButton.setFont(font);
panel.add(pauseButton);
pauseButton.addActionListener(event -> {
String text = pauseButton.getText();
if (text.equals("Pause")) {
model.pauseTimer();
pauseButton.setText("Restart");
} else {
model.startTimer();
pauseButton.setText("Pause");
}
});
Timer timer = new Timer(200,
new CountupListener(CountupTimerGUI.this, model));
stopButton = new JButton("Start");
stopButton.setFont(font);
panel.add(stopButton);
stopButton.addActionListener(event -> {
String text = stopButton.getText();
if (text.equals("Start")) {
model.resetDuration();
model.startTimer();
timer.start();
resetButton.setEnabled(false);
stopButton.setText("Stop");
} else {
model.stopTimer();
timer.stop();
resetButton.setEnabled(true);
stopButton.setText("Start");
}
});
Dimension d = getLargestJButton(resetButton, pauseButton, stopButton);
resetButton.setPreferredSize(d);
pauseButton.setPreferredSize(d);
stopButton.setPreferredSize(d);
pauseButton.setText("Pause");
return panel;
}
private Dimension getLargestJButton(JButton... buttons) {
Dimension largestDimension = new Dimension(0, 0);
for (JButton button : buttons) {
Dimension d = button.getPreferredSize();
largestDimension.width = Math.max(largestDimension.width, d.width);
largestDimension.height = Math.max(largestDimension.height,
d.height);
}
largestDimension.width += 10;
return largestDimension;
}
public JButton getResetButton() {
return resetButton;
}
public JButton getPauseButton() {
return pauseButton;
}
public JButton getStopButton() {
return stopButton;
}
public JLabel getTimerLabel() {
return timerLabel;
}
public class CountupListener implements ActionListener {
private final CountupTimerGUI view;
private final CountupTimerModel model;
public CountupListener(CountupTimerGUI view, CountupTimerModel model) {
this.view = view;
this.model = model;
}
#Override
public void actionPerformed(ActionEvent event) {
model.setDuration();
view.getTimerLabel().setText(model.getFormattedDuration());
}
}
public class CountupTimerModel {
private boolean isRunning;
private long duration, previousDuration, startTime;
public CountupTimerModel() {
resetDuration();
}
public void resetDuration() {
this.duration = 0L;
this.previousDuration = 0L;
this.isRunning = true;
}
public void startTimer() {
this.startTime = System.currentTimeMillis();
this.isRunning = true;
}
public void pauseTimer() {
setDuration();
this.previousDuration = duration;
this.isRunning = false;
}
public void stopTimer() {
setDuration();
this.isRunning = false;
}
public void setDuration() {
if (isRunning) {
this.duration = System.currentTimeMillis() - startTime
+ previousDuration;
}
}
public String getFormattedDuration() {
int seconds = (int) ((duration + 500L) / 1000L);
int minutes = seconds / 60;
int hours = minutes / 60;
StringBuilder builder = new StringBuilder();
if (hours > 0) {
builder.append(hours);
builder.append(":");
}
minutes %= 60;
if (hours > 0) {
builder.append(String.format("%02d", minutes));
builder.append(":");
} else if (minutes > 0) {
builder.append(minutes);
builder.append(":");
}
seconds %= 60;
if (hours > 0 || minutes > 0) {
builder.append(String.format("%02d", seconds));
} else {
builder.append(seconds);
}
return builder.toString();
}
}
}
I want to display in my JPanel a JLabel with timer in this mode, for example:
03:50 sec
03:49 sec
....
....
00:00 sec
So I have build this code:
#SuppressWarnings("serial")
class TimeRefreshRace extends JLabel implements Runnable {
private boolean isAlive = false;
public void start() {
Thread t = new Thread(this);
isAlive = true;
t.start();
}
public void run() {
int timeInSecond = 185
int minutes = timeInSecond/60;
while (isAlive) {
try {
//TODO
} catch (InterruptedException e) {
log.logStackTrace(e);
}
}
}
}//fine autoclass
And with this code, I can start the JLabel
TimeRefreshRace arLabel = new TimeRefreshRace ();
arLabel.start();
So I have the time in secondo for example 180 second, how can I create the timer?
Here is an example, how to build a countdown label. You can use this pattern to create your component.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
import javax.swing.WindowConstants;
public class TimerTest {
public static void main(String[] args) {
final JFrame frm = new JFrame("Countdown");
final JLabel countdownLabel = new JLabel("03:00");
final Timer t = new Timer(1000, new ActionListener() {
int time = 180;
#Override
public void actionPerformed(ActionEvent e) {
time--;
countdownLabel.setText(format(time / 60) + ":" + format(time % 60));
if (time == 0) {
final Timer timer = (Timer) e.getSource();
timer.stop();
}
}
});
frm.add(countdownLabel);
t.start();
frm.pack();
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.setVisible(true);
}
private static String format(int i) {
String result = String.valueOf(i);
if (result.length() == 1) {
result = "0" + result;
}
return result;
}
}
You could within your try block call the Event Dispatcher Thread (EDT) and update your UI:
try {
SwingUtils.invokeLater(new Runnable() {
#Override
public void run() {
this.setText(minutes + " left");
}
}
//You could optionally block your thread to update your label every second.
}
Optionally, you could use a Timer instead of an actual thread, so your TimerRefreshRace will have its own timer which periodically fires an event. You would then use the same code within your try-catch block to update the UI.
I have two classes (Sampling and Stacker). The Sampling class (my Main class) is extends JFrame and has a JButton with an ActionListener to open the Stacker class.
The problem is when the button is clicked, the Stacker class will open but only a frame without any components. When I switch the main method into the Stacker class, the program works fine. What is the problem?
Here is the code:
The Sampling class:
public class Sampling extends JFrame implements ActionListener
{
private JButton openStacker;
Stacker st;
public Sampling()
{
setSize(300,300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
dispose();
st = new Stacker();
}
public static void main (String args[])
{
new Sampling();
}
}
The Stacker game class:
public class Stacker extends JFrame implements KeyListener
{
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5,5};
int layer = 19;
int deltax[] = {0,0};
boolean press = false;
boolean forward = true;
boolean start = true;
public Stacker()
{
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400,580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton [m][n];
setLayout(new GridLayout(n,m));
for (int y = 0;y<n;y++)
{
for (int x = 0;x<m;x++)
{
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
this.addKeyListener(this);
this.setVisible(true);
go();
}
public void go()
{
int tmp = 0;
Component temporaryLostComponent = null;
do{
if (forward == true)
{
forward();
} else {
back();
}
if (deltax[1] == 10-length[1])
{
forward = false;
} else if (deltax[1] == 0)
{
forward = true;
}
draw();
try
{
Thread.sleep((long) time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}while(press == false);
if (layer>12)
{
time= 150-(iteration*iteration*2-iteration);
} else
{
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0)
{
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line "+(18-layer)+"!");
repeat();
}
last = deltax[1];
start = false;
go();
}
public int check()
{
if (start == true)
{
return length[1];
}
else if (last<deltax[1])
{
if (deltax[1]+length[1]-1 <= last+length[0]-1)
{
return length[1];
}
else
{
return length[1]-Math.abs((deltax[1]+length[1])-(last+length[0]));
}
}
else if (last>deltax[1])
{
return length[1]-Math.abs(deltax[1]-last);
}
else
{
return length[1];
}
}
public void forward()
{
deltax[0] = deltax[1];
deltax[1]++;
}
public void back()
{
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw()
{
for (int x = 0;x<length[1];x++)
{
b[x+deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0;x<length[1];x++)
{
b[x+deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat()
{
if(JOptionPane.showConfirmDialog(null, "PLAY AGAIN?","WARNING",JOptionPane.YES_NO_OPTION)== JOptionPane.YES_OPTION)
{
dispose();
new Stacker();
}else{
System.exit(0);
}
}
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
press = true;
}
}
public void keyReleased(KeyEvent arg0)
{
}
public void keyTyped(KeyEvent arg0)
{
}
}
Just to put all my comments into an answer, and give you somewhere to start with:
Comment 1:
Take out go(); see that happens. I tested it and it will work. If you leave it there, even the frame's close button is jammed. You're blocking the edt with the while->Thread.sleep junk. You'll want to do some refactoring. You're code it hard to follow and I have no idea what you're trying to do, so I didn't even attempt it
Comment 2:
If you're wondering why it works when you just run the main from the Stacker class, it's probably because you are running it outside the EDT,
public static void main(String[] args) { new Stacker(); }. What happens when you click the button, that action is performed within the EDT, and hence your new Stacker() will be run on the EDT. In which case the EDT gets blocked by your while loop. If you try run the program from the Stacker class, but wrap it in a SwingUtilities.invokeLater, you will also notice the program fails to work. Swing programs should be run on the EDT though.
Comment 2: Read the first few sections on Concurrency with Swing
So what you can do is use a Swing Timer (which operates on the EDT) for the game loop. What I did was refactor your code a bit. It doesn't operate the way you want it to yet, only because I didn't really understand the logic of your code. So I couldn't get it to work. What I did though, is put some of the logic into the Timer.
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
And when the go() method is called, it just starts the timer by calling timer.start(). Basically what you need to know about the timer, is that every tick (the milliseconds you pass it), the actionPerformed will be called. So you can update the game state in that method, just like you did in the while loop each iteration.
Take some time to go over How to Use Swing Timers
To get the game working properly, you still need to make some adjustments, but this should give you a head start.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Sampling extends JFrame implements ActionListener {
private JButton openStacker;
Stacker st;
public Sampling() {
setSize(300, 300);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
setLocationRelativeTo(null);
openStacker = new JButton("Start Stacker!");
add(openStacker);
openStacker.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
dispose();
st = new Stacker();
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Sampling();
}
});
}
}
class Stacker extends JFrame implements KeyListener {
int iteration = 1;
double time = 200;
int last = 0;
int m = 10;
int n = 20;
JButton b[][];
int length[] = {5, 5};
int layer = 19;
int deltax[] = {0, 0};
boolean press = false;
boolean forward = true;
boolean start = true;
Timer timer = new Timer((int)time, new ActionListener(){
public void actionPerformed(ActionEvent event) {
if (forward == true) {
forward();
} else {
back();
}
if (deltax[1] == 10 - length[1]) {
forward = false;
} else if (deltax[1] == 0) {
forward = true;
}
draw();
}
});
public Stacker() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400, 580);
this.setUndecorated(false);
this.setLocationRelativeTo(null);
b = new JButton[m][n];
setLayout(new GridLayout(n, m));
for (int y = 0; y < n; y++) {
for (int x = 0; x < m; x++) {
b[x][y] = new JButton(" ");
b[x][y].setBackground(Color.DARK_GRAY);
add(b[x][y]);
b[x][y].setEnabled(false);
}//end inner for
}
this.setFocusable(true);
this.pack();
JPanel panel = (JPanel)getContentPane();
panel.addKeyListener(this);
this.setVisible(true);
panel.requestFocusInWindow();
go();
}
public void go() {
int tmp = 0;
Component temporaryLostComponent = null;
timer.start();
if (layer > 12) {
time = 150 - (iteration * iteration * 2 - iteration);
} else {
time = time - 2.2;
}
iteration++;
layer--;
press = false;
tmp = check();
length[0] = length[1];
length[1] = tmp;
if (layer == -1) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Congratulations! You beat the game!");
repeat();
}
if (length[1] <= 0) {
JOptionPane.showMessageDialog(temporaryLostComponent, "Game over! You reached line " + (18 - layer) + "!");
repeat();
}
last = deltax[1];
start = false;
//go();
}
public int check() {
if (start == true) {
return length[1];
} else if (last < deltax[1]) {
if (deltax[1] + length[1] - 1 <= last + length[0] - 1) {
return length[1];
} else {
return length[1] - Math.abs((deltax[1] + length[1]) - (last + length[0]));
}
} else if (last > deltax[1]) {
return length[1] - Math.abs(deltax[1] - last);
} else {
return length[1];
}
}
public void forward() {
deltax[0] = deltax[1];
deltax[1]++;
}
public void back() {
deltax[0] = deltax[1];
deltax[1]--;
}
public void draw() {
for (int x = 0; x < length[1]; x++) {
b[x + deltax[0]][layer].setBackground(Color.DARK_GRAY);
}
for (int x = 0; x < length[1]; x++) {
b[x + deltax[1]][layer].setBackground(Color.CYAN);
}
}
public void repeat() {
if (JOptionPane.showConfirmDialog(null, "PLAY AGAIN?", "WARNING", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
dispose();
new Stacker();
} else {
System.exit(0);
}
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
System.out.println("Pressed");
press = true;
}
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
}
Notice the SwingUtilities.invokeLater in the main. That's how you can start up the program on the EDT. The link on Concurrency In Swing will give you more information.
I have a GUI with a form for people to fill up and I would like to put a countdown timer at the top right hand corner of the page
Heres the method for the timer to get the remaining time. Say my form class is FillForm and the timer method is found in Timer.
How do I put a dynamic (constantly updating) timer inside of the GUI?
public String getRemainingTime() {
int hours = (int)((this.remainingTime/3600000) % 60);
int minutes = (int)((this.remainingTime/60000) % 60);
int seconds = (int)(((this.remainingTime)/1000) % 60);
return(format.format(hours) + ":" + format.format(minutes)+
":" + format.format(seconds));
}
GUI is built using NetBeans GUI builder.
Try This :
import javax.swing.Timer;
Timer timer=new Timer(1000,new ActionListener(){
public void actionPerformed(ActionEvent e)
{
//code here
}
});
timer.start();
//timer.stop()
Every one Seconds Timer Execute.
Try This Demo :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.Timer;
class Counter {
private static int cnt;
static JFrame f;
public static void main(String args[]) {
f=new JFrame();
f.setSize(100,100);
f.setVisible(true);
ActionListener actListner = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
cnt += 1;
if(cnt%2==0)
{
f.setVisible(true);
}
else
{
f.setVisible(false);
}
}
};
Timer timer = new Timer(500, actListner);
timer.start();
}
}
You should abstract your timer into a UI component. JLabel seems the most suited as it is a text that you want to display.
public class TimerLabel extends JLabel {
// Add in your code for 'format' and 'remainingTime'.
// Note that the first time that 'getText' is called, it's called from the constructor
// if the superclass, so your own class is not fully initialized at this point.
// Hence the 'if (format != null)' check
public TimerLabel() {
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
public String getRemainingTime() {
int hours = (int) ((this.remainingTime / 3600000) % 60);
int minutes = (int) ((this.remainingTime / 60000) % 60);
int seconds = (int) (((this.remainingTime) / 1000) % 60);
return (format.format(hours) + ":" + format.format(minutes) + ":" + format.format(seconds));
}
#Override
public String getText() {
if (format != null) {
return getRemainingTime();
} else {
return "";
}
}
"Could i add this into a Swing.JPanel or something?"
Just put it in the constructor of your form class. Declare the Timer timer; as a class member and not locally scoped so that you can use the start() method like in a button's actionPerformed. Something like
import javax.swing.Timer;
public class GUI extends JFrame {
public Timer timer = null;
public GUI() {
timer = new Timer (500, new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (timerGetsToZero) {
((Timer)e.getSource()).stop();
} else {
timeLabel.setText(getRemainingTime());
}
}
});
}
private void startButtonActionPerformed(ActionEvent e) {
timer.start();
}
}
I am trying to make a stopwatch using swing, but it is not working. Here is my code. The Jlabel clock is always displaying -1, which should only happen if it is stopped. Am I using the invokelater properly?
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class sidePanel extends JApplet implements ActionListener{
JPanel pane;
JLabel clock;
JButton toggle;
Timer timer;
StopWatch stopWatch;
public void init()
{
pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
clock = new JLabel("00:00");
toggle = new JButton("Start/Stop");
toggle.addActionListener(this);
pane.add(clock);
pane.add(toggle);
timer = new Timer(500, this);
timer.setRepeats(true);
stopWatch = new StopWatch();
add(pane);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == toggle)
{
if(timer.isRunning())
{
stopWatch.endTime = System.currentTimeMillis();
timer.stop();
}
else
{
stopWatch.startTime = System.currentTimeMillis();
timer.start();
}
}
if(e.getSource() == timer)
{
long time = stopWatch.getElapsedTime();
sidePanel.this.clock.setText(String.valueOf(time));
}
}
private class StopWatch{
private long startTime =0;
private long endTime =0;
public boolean isRunning = false;
public void start(){
startTime = System.currentTimeMillis();
isRunning = true;
}
public void end(){
endTime = System.currentTimeMillis();
isRunning = false;
}
public long getElapsedTime()
{
long currentTime = System.currentTimeMillis();
if(isRunning)
return (currentTime - startTime)/1000;
else
return -1;
}
}
}
Working code
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class sidePanel extends JApplet implements ActionListener{
JPanel pane;
JLabel clock;
JButton toggle;
Timer timer;
//StopWatch stopWatch;
boolean pressed = false;
long startTime =0;
long endTime =0;
public void init()
{
pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
clock = new JLabel("00:00");
toggle = new JButton("Start/Stop");
toggle.addActionListener(this);
pane.add(clock);
pane.add(toggle);
timer = new Timer(500, this);
timer.setRepeats(true);
//stopWatch = new StopWatch();
add(pane);
}
long cur;
long end;
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == toggle)
{
if(!pressed)
{
timer.start();
startTime = System.currentTimeMillis();
pressed = true;
}
else
{
timer.stop();
pressed = false;
}
}
if(timer.isRunning())
{
endTime = System.currentTimeMillis();
clock.setText(String.valueOf((endTime-startTime)/1000));
}
}
}
Your StopWatch class run once and then terminates...
public void run() {
// Start here
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run() {
long time = getElapsedTime();
sidePanel.this.clock.setText(String.valueOf(time));
}
});
// End here...
}
A thread will terminate when it exists it's run method, in this case, your StopWatch's run method.
What you need to do to is maintain a loop until the isRunning becomes false
public void run() {
while (isRunning) {
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run() {
long time = getElapsedTime();
sidePanel.this.clock.setText(String.valueOf(time));
}
});
// Because we really don't want to bombboard the Event dispatching thread
// With lots of updates, which probably won't get rendered any way,
// We put in a small delay...
// This day represents "about" a second accuracy...
try {
Thread.sleep(500);
} catch (Exception exp) {
}
}
}
It would much simpler to use a javax.swing.Timer though...
private Timer timer;
public void init()
{
pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
clock = new JLabel("00:00");
toggle = new JButton("Start/Stop");
toggle.addActionListener(this);
pane.add(clock);
pane.add(toggle);
timer = new Timer(500, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
long time = getElapsedTime();
sidePanel.this.clock.setText(String.valueOf(time));
}
});
timer.setRepeats(true);
add(pane);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == toggle)
{
if(timer.isRunning())
{
endTime = System.currentTimeMillis();
timer.stop();
}
else
{
startTime = System.currentTimeMillis();
timer.start();
}
}
}
You can then strip out the functionality from you StopWatch (ie the getElapsedTime())