This question already has an answer here:
I don't know how to display timer when stopped
(1 answer)
Closed 6 years ago.
I'm trying to display the current time in a JFrame. How can I refresh the text in the JLabel without opening a separate frame each time it has to update?
Here's all of my code so far...
Test
public class Test{
static String timeDisplay = "";
public static class time extends Thread{
static int timeHours = 7;
static int timeMins = 30;
static int timeSecs = 0;
#Override
public void run(){
while(true){
try{
time.sleep(1000);
timeSecs++;
if(timeSecs == 60){
timeMins++;
timeSecs = 0;
}
if(timeMins == 60){
timeHours++;
timeMins = 0;
}
if(timeHours < 10){
if(timeMins < 10){
if(timeSecs < 10){
timeDisplay = "0" + timeHours + ":" + "0" + timeMins + ":" + "0" + timeSecs;
}
else{
timeDisplay = "0" + timeHours + ":" + "0" + timeMins + ":" + timeSecs;
}
}
else{
if(timeSecs < 10){
timeDisplay = "0" + timeHours + ":" + timeMins + ":" + "0" + timeSecs;
}
else{
timeDisplay = "0" + timeHours + ":" + timeMins + ":" + timeSecs;
}
}
}
else{
if(timeMins < 10){
if(timeSecs < 10){
timeDisplay = timeHours + ":" + "0" + timeMins + ":" + "0" + timeSecs;
}
else{
timeDisplay = timeHours + ":" + "0" + timeMins + ":" + timeSecs;
}
}
else{
if(timeSecs < 10){
timeDisplay = timeHours + ":" + timeMins + ":" + "0" + timeSecs;
}
else{
timeDisplay = timeHours + ":" + timeMins + ":" + timeSecs;
}
}
}
System.out.println(timeDisplay);
//CountDown time = new CountDown(timeDisplay);
}
catch(Exception e){
System.out.println("Something went wrong :(");
}
}
}
}
public static void main(String[] args){
time time = new time();
time.start();
try {
TimeUnit.SECONDS.sleep(1);
CountDown window = new CountDown(timeDisplay);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(500, 500);
window.setVisible(true);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
CountDown
public class CountDown extends JFrame{
private static final long serialVersionUID = 1L;
static JLabel label = new JLabel();
public CountDown(String time){
super("Title");
setLayout(new FlowLayout());
add(label);
label.setText("Current Time: " + time);
Handler eventHandler = new Handler();
}
private class Handler implements ActionListener{
public void actionPerformed(ActionEvent event){
String string = "";
if(event.getSource()==""){
string = String.format("label 1: %s", event.getActionCommand());
}
}
}
}
My intentions for this program was to make a frame that displayed the current time. It's using local time from the program, not the actual time. Thanks in advance, and feel free to let me know if I should change anything in my code to make it better.
You should first create an instance of CountDown and then call one of its method setting the text of the label.
In CountDown you have to call the JLabel.setText. method to set the label's text:
public void displayTime(String time){
label.setText("Current Time: " + time);
}
...and instead of System.out.println(time) call
time.displayTime(timeDisplay);
Instead of using a simple thread , you'd better use a java.util.Timer or even better a javax.swing.Timer that is better suited for gui objects.
Another remark: class names begin by an upper case letter while methods or variables begin by a lower case method.
Finally what has your handler to do here. You don't register it and it seems useless.
The API Docs will be your friend. Take a look at the documentation for JLabel, particularly the method setText(). You can use this method again in your event handler to change the text of your label.
But another problem you have is that you are neither firing nor registering for events, so that actionPerformed function you have written is never being called. If second-accuracy is good enough, you could simplify your code greatly, using javax.swing.Timer. Without changing your code where unnecessary, this should get you on the right path:
public class CountDown extends JFrame{
private static final long serialVersionUID = 1L;
private JLabel label = new JLabel(); // note: understand static keyword before using it.
private long startTime = System.currentTimeMillis(); // gets the current time in milliseconds, when your class is initialized.
public CountDown(String time){
super("Title");
setLayout(new FlowLayout());
add(label);
// label.setText("Current Time: " + time); "time" was never in scope here.
Handler eventHandler = new Handler();
new Timer(1000, eventHandler).start(); // will execute ~1/sec
}
private class Handler implements ActionListener{
public void actionPerformed(ActionEvent event){
// NOTE: here, you could put all of your logic that was previously
// in your Thread to determine the time, then use the result
// with label.setText();
long currentTime = System.currentTimeMillis();
long upTime = currentTime - startTime; // this is how many milliseconds your JFrame has been up and running.
// TODO: formate upTime however you desire.
label.setText( <whatever_you_calculate_directly_above> );
}
}
}
}
You will also need to rewrite your main method to initialized your Frame. That should do it.
public static void main( String[] args){
JFrame frame = new CountDown();
frame.setVisible(true);
}
If your main method is in a separate file, you will need to import CountDown near the beginning of that file.
Related
I am writing a java application that will hash a series of input values repeatedly until a condition is met. I have accomplished this by nesting a series of if/else statements inside a while loop. I want to be able to print the hash rate to the terminal every 3 seconds while the application is actively hashing, and not repeatedly until the condition is met. I have tried using ExecutorService and scheduling a TimerTask but neither worked the way I wanted them to as they both kept on executing after the condition that should have stopped them was met. I know I am missing something but I don't know what ):
I've included a small snippet, feel free to ask for any information you may think is relevant.
Any help would be greatly appreciated!
I tried using a TimerTask like this:
while(iterator) {
if (difficulty == 1) {
if (!hash.startsWith("0")) {
long updatedTime = System.nanoTime();
Nonce++;
long deltaN = updatedTime - startTime;
long deltaS = (deltaN / 1000000000);
long hashRate = (Nonce / deltaS);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
System.out.println("Current hash rate: " + hashRate + " " + "hash/s");
}
}, 0, 3000);
} else {
System.out.println("Valid hash found! " + hash);
iterator = false;
}
}
}
EDIT: What this will be when finished is essentially a cheesy 'block chain' I will be using for illustrative purposes as a teaching tool, with that in mind I have included the rest of the 'miner' method below:
public void miner(long index, long currentTimeMillis, long data, long Nonce, String previousBlockHash, int difficulty) throws InterruptedException {
this.index = index;
this.currentTimeMillis = currentTimeMillis;
this.pszTimeStamp = pszTimeStamp;
this.Nonce = Nonce;
this.previousBlockHash = previousBlockHash;
this.difficulty = difficulty;
this.data = data;
boolean iterator = true;
String blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
String hash = SHA256.generateHash(blockHeader);
long startTime = System.nanoTime();
TimeUnit.SECONDS.sleep(2);
while (iterator) {
blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
hash = SHA256.generateHash(blockHeader);
if (difficulty == 1) {
if (!hash.startsWith("0")) {
long updatedTime = System.nanoTime();
Nonce++;
long deltaN = updatedTime - startTime;
long deltaS = (deltaN / 1000000000);
long hashRate = (Nonce / deltaS);
System.out.println("Current hash rate: " + hashRate
} else {
System.out.println("\n");
System.out.println("Hash found! \n");
System.out.println("Mined block hash: \n" + hash);
}
} else if (difficulty == 2) {
...........
All of the parameters the 'miner' method takes are passed to it by a launching class which includes the main function. My goal is to be able to print the hash rate while it searches for a 'valid' hash every few seconds instead of it printing thousands of times per second.
I have a few suggestions:
I personally would prefer using break inside a while(true) loop instead of of a loop variable. I feel that it makes the code more readable;
You are re declaring the Timer inside the loop, which means that a new timer is created each iteration of the loop. You need to create the timer once, outside the loop.
The Timer variable needs to be final to allow you to call timer.cancel() inside the run function of the TimerTask. If you plan on terminating the timer outside the run function, then the Timer variable need not be final.
import java.util.*;
public class Test{
static double Nonce;
public static void main(String... args) throws Exception{
final Timer timer = new Timer();
timer.schedule(new TimerTask(){
public void run(){
//calcualte hashRate by any formula
double hashRate = Nonce/100.0;
//check if the timer needs to continue, else call timer.cancel()
System.out.println(hashRate);
}
}, 0, 500);
while(true){
Thread.sleep(100);
Nonce++;
if(Nonce == 100){
timer.cancel(); //or terminate the timer outside the loop
break;
}
}
}
}
Please let me know if you need any help.
Edit:
A few things I have noticed:
The class variable Nonce cannot be static, otherwise it will be shared amongst all instances of the class.
The name of the variable cannot be Nonce in the function declaration, otherwise the local copy will be used whenever you use Nonce within the miner function.
If you do not calculate the hashRate directly, then deltaS can be zero, which may lead to a divide by 0 error.
Please let me know if you need any clarification.
public class ChainBuilder extends MainChain {
private long index;
private long currentTimeMillis;
private long data;
private int difficulty;
private String pszTimeStamp;
private String previousBlockHash;
private String currentHash;
private String genesisHash;
public long Nonce; //Nonce cannot be be static, otherwise it will cause issues if more than one object is created.
public static long startTime;
.......
public void miner(long index, long currentTimeMillis, long data, long _Nonce /*You cannot use Nonce here*/, String previousBlockHash, int difficulty) throws InterruptedException {
this.index = index;
this.currentTimeMillis = currentTimeMillis;
this.pszTimeStamp = pszTimeStamp;
this.Nonce = _Nonce; /*In this scope, Nonce refers to the local variable, and this.Nonce refers to the class variable.
If you use Nonce in this scope, then the class variable will not be changed.*/
this.previousBlockHash = previousBlockHash;
this.difficulty = difficulty;
this.data = data;
boolean iterator = true;
String blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
String hash = SHA256.generateHash(blockHeader);
startTime = System.nanoTime();
TimeUnit.SECONDS.sleep(2);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
long endTime = System.nanoTime();
long deltaN = endTime - startTime;
//long deltaS = (deltaN / 1_000_000_000);
long hashRate = (1_000_000_000 * Nonce / deltaN); /*calculate the hashRate directly, because if deltaN < 1_000_000_000,
then deltaS will be 0, giving a divide by zero error.*/
System.out.println("Current hash rate: " + hashRate + " " + "hash/s");
}
}, 0, 3000);
while (iterator) {
blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
hash = SHA256.generateHash(blockHeader);
if (difficulty == 1) {
if (!hash.startsWith("0")) {
Nonce++;
} else {
System.out.println("Hash found!");
timer.cancel();
.......
Okay, so what worked for me was declaring the relevant variables static, putting the start of the timer before loop, and cancelling upon the discovery of a valid hash, like so:
public class ChainBuilder extends MainChain {
private long index;
private long currentTimeMillis;
private long data;
private int difficulty;
private String pszTimeStamp;
private String previousBlockHash;
private String currentHash;
private String genesisHash;
public static long deltaS;
public static long deltaN;
public static long Nonce;
public static long startTime;
public static long endTime;
public static long hashRate;
.......
public void miner(long index, long currentTimeMillis, long data, long Nonce, String previousBlockHash, int difficulty) throws InterruptedException {
this.index = index;
this.currentTimeMillis = currentTimeMillis;
this.pszTimeStamp = pszTimeStamp;
this.Nonce = Nonce;
this.previousBlockHash = previousBlockHash;
this.difficulty = difficulty;
this.data = data;
boolean iterator = true;
String blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
String hash = SHA256.generateHash(blockHeader);
startTime = System.nanoTime();
TimeUnit.SECONDS.sleep(2);
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
System.out.println("Current hash rate: " + hashRate + " " + "hash/s");
}
}, 0, 3000);
while (iterator) {
blockHeader = (index + currentTimeMillis + data + Nonce + previousBlockHash + difficulty);
hash = SHA256.generateHash(blockHeader);
if (difficulty == 1) {
if (!hash.startsWith("0")) {
endTime = System.nanoTime();
Nonce++;
deltaN = endTime - startTime;
deltaS = (deltaN / 1000000000);
hashRate = (Nonce / deltaS);
} else {
System.out.println("Hash found!");
timer.cancel();
.......
This question already has answers here:
Dynamic Clock in java
(7 answers)
Closed 4 years ago.
I am creating a program that gets the time and displays it in a JFrame (it also updates the background to be the color #[HOUR][MIN][SEC] like on rhysperry.co.nf ). My problem is the timer seams to only update every 2-4 seconds(on lower end machines). I have the code and am wondering how I would go about optimizing an already small program.
Please tolerate bad coding practices as I still don't fully understand Java.
Here is my code - Window.java:
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
public class Window {
/**
* Simple color changing clock based on the website the website rhysperry.co.nf
*
* #author Rhys Perry
*/
public static void main(String[] args) throws IOException, FontFormatException, InterruptedException {
//Import font
InputStream in = Window.class.getResourceAsStream("Lato-Hairline.ttf");
Font font = Font.createFont(Font.TRUETYPE_FONT, in).deriveFont(50f);
//Initialise the Frame, Panel and label
JFrame frame= new JFrame("Hex Clock");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
JLabel label = new JLabel();
label.setFont(font);
label.setPreferredSize(new Dimension(200, 350));
label.setForeground(Color.WHITE);
//Merge Frame, Panel and "This is a test")Label. Make window visible
panel.add(label);
frame.add(panel);
frame.setSize(700, 400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//Setup calendar
Calendar calendar;
//Initialise some variables to do with time management
String formattedhour;
String formattedmin;
String formattedsec;
//Main loop to get the time and update the background ad Label
while(true) {
//Get hours, minutes and seconds
calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
if (hour < 10) { formattedhour = "0" + hour; } else { formattedhour = hour + "";}
int min = calendar.get(Calendar.MINUTE);
if (min < 10) { formattedmin = "0" + min; } else { formattedmin = min + "";}
int sec = calendar.get(Calendar.SECOND);
if (sec < 10) { formattedsec = "0" + sec; } else { formattedsec = sec + "";}
//Format and update the necessary components
String time = formattedhour + ":" + formattedmin + " " + formattedsec;
label.setText(time);
String hex = "#" + formattedhour + formattedmin + formattedsec;
panel.setBackground(Color.decode(hex));
panel.repaint();
}
}
}
You can use javax.swing.Timmer instead. It executes a task repeatedly after interval of time. https://docs.oracle.com/javase/7/docs/api/javax/swing/Timer.html
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
}
};
Timer timer = new Timer(10 ,taskPerformer);
timer.start();
I am truely sorry if asking the same question twice is considered spamming as I already asked about backward timer a hour ago.
But now new problem with it is though I couldn't get anyone's attention to that question again. I have successfully coded the timer thanks to you guys but then I tried to convert seconds tot he hh:mm:ss format but it didn't work. Instead of continuosely going till it is 00:00:00. It just shows the time that I coded it and that's it.
Here's my code.
import java.util.Timer;
import java.util.TimerTask;
public class countdown extends javax.swing.JFrame {
public countdown() {
initComponents();
Timer timer;
timer = new Timer();
timer.schedule(new DisplayCountdown(), 0, 1000);
}
class DisplayCountdown extends TimerTask {
int seconds = 5;
int hr = (int)(seconds/3600);
int rem = (int)(seconds%3600);
int mn = rem/60;
int sec = rem%60;
String hrStr = (hr<10 ? "0" : "")+hr;
String mnStr = (mn<10 ? "0" : "")+mn;
String secStr = (sec<10 ? "0" : "")+sec;
public void run() {
if (seconds > 0) {
lab.setText(hrStr+ " : "+mnStr+ " : "+secStr+"");
seconds--;
} else {
lab.setText("Countdown finished");
System.exit(0);
}
}
}
public static void main(String args[]) {
new countdown().setVisible(true);
}
Move your calculations
int hr = seconds/3600;
int rem = seconds%3600;
int mn = rem/60;
int sec = rem%60;
String hrStr = (hr<10 ? "0" : "")+hr;
String mnStr = (mn<10 ? "0" : "")+mn;
String secStr = (sec<10 ? "0" : "")+sec;
into the run method.
public String getCountDownStringInMinutes(int timeInSeconds)
{
return getTwoDecimalsValue(timeInSeconds/3600) + ":" + getTwoDecimalsValue(timeInSeconds/60) + ":" + getTwoDecimalsValue(timeInSeconds%60);
}
public static String getTwoDecimalsValue(int value)
{
if(value>=0 && value<=9)
{
return "0"+value;
}
else
{
return value+"";
}
}
I'm having some trouble getting a JButton to update repeatedly (used with a timer) in a do-while loop. I'm working on a simple game, played on a 10 * 10 grid of tile objects which correspond to a JButton arrayList with 100 buttons.
This part of the program handles simple pathfinding (i.e. if I click on character, then an empty tile, the character will move through each tile on its way to the destination). There is a delay between each step so the user can see the character's progress.
In the current state of things, the movement is correct, but the JButton is only updated when the character reaches the destination, not on intermediate steps.
public void move(int terrainTile)
{
int currentPosition = actorList.get(selectedActor).getPosition();
int movementValue = 0;
int destination = terrainTile;
int destinationX = destination / 10;
int destinationY = destination % 10;
do
{
currentPosition = actorList.get(selectedActor).getPosition(); // Gets PC's current position (before move)
System.out.println("Old position is " + currentPosition);
int currentX = currentPosition / 10;
int currentY = currentPosition % 10;
if(actorList.get(selectedActor).getCurrentAP() > 0)
{
movementValue = 0;
if(destinationX > currentX)
{
movementValue += 10;
}
if(destinationX < currentX)
{
movementValue -= 10;
}
if(destinationY > currentY)
{
movementValue += 1;
}
if(destinationY < currentY)
{
movementValue -= 1;
}
int nextStep = currentPosition + movementValue;
myGame.setActorIdInTile(currentPosition, -1); //Changes ActorId in PC current tile back to -1
scrubTiles(currentPosition);
actorList.get(selectedActor).setPosition(nextStep); // Sets new position in actor object
System.out.println("Actor " + selectedActor + " " + actorList.get(selectedActor).getName() + " position has been updated to " + nextStep);
myGame.setActorIdInTile(nextStep, selectedActor); // Sets ActorId in moved to Tile
System.out.println("Tile " + nextStep + " actorId has been updated to " + selectedActor);
buttons.get(nextStep).setIcon(new ImageIcon(actorList.get(selectedActor).getImageName()));
// If orthagonal move AP-4
if(movementValue == 10 || movementValue == -10 || movementValue == 1 || movementValue == -1)
{
actorList.get(selectedActor).reduceAP(4);
}
// If diagonal move AP-6
else
{
actorList.get(selectedActor).reduceAP(6);
}
System.out.println(actorList.get(selectedActor).getName() + " has " + actorList.get(selectedActor).getCurrentAP() + " AP remaining");
try
{
Thread.sleep(500); // one second
}
catch (Exception e){}
buttons.get(nextStep).repaint();
}
else
{
System.out.println(actorList.get(selectedActor).getName() + " has insufficient AP to move");
break;
}
}while(destination != (currentPosition + movementValue));
What I've tried:
buttons.get(nextStep).repaint(); (Tried putting a command to repaint the button after setting the imageIcon. No change.
buttons.get(nextStep).revalidate(); (No 100% sure what this does - it came up as a potential solution, but doesn't work.
Steps 1 & 2 combined
Looked into the swing timer class - movement doesn't occur everytime an actionEvent is fired, (only if character is selected and target tile is empty) so not sure how I could get this to work
Any help would be greatly appreciated!
I really dont' know exactly what you wanted to know in your comments, though +1 to the answer above, seems to me that's the real cause. Have a look at this example program, simply add your call to the move(...) method inside the timerAction, seems like that can work for you. Here try this code :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridExample
{
private static final int SIZE = 36;
private JButton[] buttons;
private int presentPos;
private int desiredPos;
private Timer timer;
private Icon infoIcon =
UIManager.getIcon("OptionPane.informationIcon");
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
buttons[presentPos].setIcon(null);
if (desiredPos < presentPos)
{
presentPos--;
buttons[presentPos].setIcon(infoIcon);
}
else if (desiredPos > presentPos)
{
presentPos++;
buttons[presentPos].setIcon(infoIcon);
}
else if (desiredPos == presentPos)
{
timer.stop();
buttons[presentPos].setIcon(infoIcon);
}
}
};
public GridExample()
{
buttons = new JButton[SIZE];
presentPos = 0;
desiredPos = 0;
}
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Grid Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new GridLayout(6, 6, 5, 5));
for (int i = 0; i < SIZE; i++)
{
final int counter = i;
buttons[i] = new JButton();
buttons[i].setActionCommand("" + i);
buttons[i].addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
desiredPos = Integer.parseInt(
(String) buttons[counter].getActionCommand());
timer.start();
}
});
contentPane.add(buttons[i]);
}
buttons[presentPos].setIcon(infoIcon);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(1000, timerAction);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new GridExample().createAndDisplayGUI();
}
});
}
}
This is because you are doing your do { } while in the UI thread. To solve this, you should use a SwingWorker, or a javax.swing.Timer
I have a milliseconds and i convert it hh:mm:ss now i want to make it to automatically decrease value overtime.. something like countdown timer
for example, when user sees it, 2:11 0 -> 2:10 59 -> 2:10 58 ...
Below is my code..
Timer t = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
int s = ((TIMER/1000) % 60);
int m = (((TIMER/1000) / 60) % 60);
int h = ((((TIMER/1000) / 60) /60) % 60);
timing.setText(hour + " hours, " + min + " minutes" + sec + " seconds");
timing.repaint();
}
}
t.start();
is it possible?
final Timer t = new Timer(1000, new ActionListener() {
private long time = 10 * 1000; //10 seconds, for example
public void actionPerformed(ActionEvent e) {
if (time >= 0) {
long s = ((time / 1000) % 60);
long m = (((time / 1000) / 60) % 60);
long h = ((((time / 1000) / 60) / 60) % 60);
timing.setText(h + " hours, " + m + " minutes " + s + " seconds");
time -= 1000;
}
}
});
t.start();
As Peter mentioned in his answer, you shouldn't relay on decreasing a number, since there are not guarantees that actionPerformed is invoked right in every second. The below is a working example, which stops the timer on finishing (detailed and therefor code):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test extends JFrame {
private JTextField text;
private Timer timer;
private JButton start;
public Test() {
super("Countdown timer");
text = new JTextField("2", 8);
start = new JButton("Start");
start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent click) {
final long current = System.currentTimeMillis();
try {
final long limit = Integer.parseInt(text.getText().trim())* 1000; // X seconds
timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent event) {
long time = System.currentTimeMillis();
long passed = time - current;
long remaining = limit - passed;
if(remaining <= 0) {
text.setText("2");
timer.stop();
} else {
long seconds = remaining/1000;
long minutes = seconds/60;
long hours = minutes/60;
text.setText(String.format("%02d:%02d:%02d", hours, minutes, seconds%60));
}
}
});
timer.start();
} catch(NumberFormatException nfe) {
// debug/report here
nfe.printStackTrace();
}
}});
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.add(text);
panel.add(new JLabel(" seconds"));
panel.add(start);
add(panel);
}
public static void main(String [] args) throws Exception {
Test frame = new Test();
frame.setDefaultCloseOperation(Test.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
The TIMER value is never decremented by the timer event. Therefore the same time will always be displayed every 1000 milliseconds.
Edit: Assuming "timing" is a Swing component the call to repaint should be unnecessary.
A safer option is to take the actual clock time. The reason for this is that your application can stop for pewriods of time. esp if you machine is busy. This means a countdown timer might not be called as often as you expect. If you use the System.currentTimeMillis() the time will always be right no matter what happens.