Java Timer Program - rubix cube - java

I am trying to make a rubix cube timer for my friend. To start the timer you hold down space bar, and once you let go it starts. I am having a problem though, when I hold down the space bar the timer starts at whatever time it is. I want to be able to reset it to 0 but whenever I try to do that everything glitches out. Could anyone tell me how to fix it, or how to do this in a more efficient way? Thanks!
package dev.suns.rubix_timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Timer;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class RubixTimerMain extends JFrame {
private JPanel contentPane;
private JLabel labelTimer;
private Timer timer;
public RubixTimerMain() {
createWindow();
}
public static void main(String[] args) {
new RubixTimerMain();
}
private void createWindow() {
// setUndecorated(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(Toolkit.getDefaultToolkit().getScreenSize());
setLocationRelativeTo(null);
setExtendedState(JFrame.MAXIMIZED_BOTH);
contentPane = new JPanel();
contentPane.setBackground(new Color(201, 77, 83));
contentPane.setLayout(null);
setContentPane(contentPane);
addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
startTimer();
}
}
});
JLabel lblMinimize = new JLabel("-");
lblMinimize.setBounds(1835, -20, 16, 95);
lblMinimize.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
setState(JFrame.ICONIFIED);
}
#Override
public void mouseEntered(MouseEvent e) {
lblMinimize.setForeground(Color.BLACK);
}
#Override
public void mouseExited(MouseEvent e) {
lblMinimize.setForeground(Color.WHITE);
}
});
lblMinimize.setForeground(Color.WHITE);
lblMinimize.setFont(new Font("Segoe UI", Font.PLAIN, 40));
contentPane.add(lblMinimize);
JLabel lblX = new JLabel("X");
lblX.setBounds(1873, 0, 24, 54);
lblX.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
System.exit(0);
}
#Override
public void mouseEntered(MouseEvent e) {
lblX.setForeground(Color.BLACK);
}
#Override
public void mouseExited(MouseEvent e) {
lblX.setForeground(Color.WHITE);
}
});
lblX.setFont(new Font("Segoe UI", Font.PLAIN, 40));
lblX.setHorizontalAlignment(SwingConstants.CENTER);
lblX.setForeground(Color.WHITE);
contentPane.add(lblX);
labelTimer = new JLabel("0.0.0");
labelTimer.setHorizontalAlignment(SwingConstants.CENTER);
labelTimer.setFont(new Font("DINPro-Bold", Font.PLAIN, 200));
labelTimer.setForeground(Color.WHITE);
labelTimer.setBounds(371, 134, 1418, 653);
contentPane.add(labelTimer);
setVisible(true);
}
This is where I have the timer code. I have tried to reset cal to 0 in several different places but it is not working.
private void startTimer() {
new Thread()
{
public void run()
{
while(true)
{
Calendar cal = new GregorianCalendar();
int minutes = cal.get(Calendar.MINUTE);
int seconds = cal.get(Calendar.SECOND);
int milliseconds = cal.get(Calendar.MILLISECOND);
labelTimer.setText(minutes + "." + seconds + "." + milliseconds);
}
}
}.start();
}
}

In order to be able to stop the timer thread you need to have some means of communicating between the main thread and the timer thread. A synchronized member variable of the RubixTimerMain class can do that:
private Boolean isStopped = new Boolean(true);
Then you can add two methods. One stops the timer by setting the variable, the other one checks the current state of the variable.
private void stopTimer(){
synchronized(isStopped){
isStopped = true;
}
}
private boolean isTimerRunning(){
boolean result = false;
synchronized(isStopped){
result = !isStopped;
}
return result;
}
You will want to change the listener event of the space key (in createWindow) like this so that it starts and stops the timing:
addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
if (isTimerRunning()){
stopTimer();
} else {
startTimer();
}
}
}
});
Finally you need to adapt your thread function so that it only runs if the stopped state variable is false. Notice that it uses the isTimerRunning method instead of directly accessing the variable. Also the error of displaying the wrong time is fixed by converting the value of the GregorianCalendar into milliseconds first, then subtracting the recorded start time from the current time.
private void startTimer() {
new Thread()
{
public void run()
{
long timeStart = new GregorianCalendar().getTimeInMillis();
synchronized(isStopped){
isStopped = false;
}
while(isTimerRunning())
{
long timeNow = new GregorianCalendar().getTimeInMillis() - timeStart;
long milliseconds = (timeNow % 1000);
timeNow = (long) Math.floor(timeNow * 0.001f);
long seconds = (timeNow % 60);
timeNow = (long)Math.floor((float)timeNow / 60f);
long minutes = timeNow;
labelTimer.setText(minutes + "." + seconds + "." + milliseconds);
}
}
}.start();
}

One problem may be that you're not interacting with labelTimer on the EDT (Event Dispatch Thread).
In Swing, all interactions with UI objects must happen on this thread.
What happens if you make sure your call to setText happens within an invocation of SwingUtilities#invokeLater: https://docs.oracle.com/javase/7/docs/api/javax/swing/SwingUtilities.html#invokeLater(java.lang.Runnable)

Related

Adding resume function to stopwatch

I have programmed a simple stopwatch with three functionalities. First, I have a start button to begin the stopwatch , a pause button to pause the stopwatch and finally a reset button to reset the entire stopwatch.
When I hit the pause button, the stopwatch pauses, say at 10.0 seconds. When I resume the stopwatch (pressing the Start button again), the stopwatch doesn't resume from 10.0 seconds onwards. It resumes from the amount of time I paused and the current time. For example, if I paused for 5 seconds and hit resume, the stopwatch goes from 15.0 seconds onwards.
I am aware there isn't a actual pause function in Swing.Timer. Would there be a way to tackle this so the stopwatch resumes normally?
Any suggestion would be appreciated.
Code:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import javax.swing.Timer;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GuiStopwatch {
public static void main(String[] args) {
JFrame frame = new JFrame("Stopwatch");
frame.setSize(500, 500);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setVisible(true);
JPanel panel = new JPanel();
panel.setLayout(null);
JButton startbtn = new JButton("START");
JButton pausebtn = new JButton("PAUSE");
JButton reset = new JButton("RESET");
JLabel time = new JLabel("Time shows here");
panel.add(startbtn);
panel.add(pausebtn);
panel.add(reset);
panel.add(time);
startbtn.setBounds(50, 150, 100, 35);
pausebtn.setBounds(50, 200, 100, 35);
reset.setBounds(50, 250, 100, 35);
time.setBounds(50, 350, 100, 35);
time.setBackground(Color.black);
time.setForeground(Color.red);
frame.add(panel);
Timer timer = new Timer(1,new ActionListener() {
Instant start = Instant.now();
#Override
public void actionPerformed(ActionEvent e) {
time.setText( Duration.between(start, Instant.now()).getSeconds() + ":" + Duration.between(start, Instant.now()).getNano() );
}
});
startbtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timer.start();
}
});
pausebtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timer.stop();
}
});
reset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
time.setText("0:0");
}
});
Conceptually, the idea is, you want to keep track of the "total running" of the stop watch, this is, all the total duration it has been active.
There's a number of ways you might achieve this, one might be to simply keep a running total which is only updated when the stop watch is stopped or paused. The "duration" of the stop watch is then a sum of the "current duration" of the "current" cycle and the "total previous" duration
Something like...
public class StopWatch {
private LocalDateTime startTime;
private Duration totalRunTime = Duration.ZERO;
public void start() {
startTime = LocalDateTime.now();
}
public void stop() {
Duration runTime = Duration.between(startTime, LocalDateTime.now());
totalRunTime = totalRunTime.plus(runTime);
startTime = null;
}
public void pause() {
stop();
}
public void resume() {
start();
}
public void reset() {
stop();
totalRunTime = Duration.ZERO;
}
public boolean isRunning() {
return startTime != null;
}
public Duration getDuration() {
Duration currentDuration = Duration.ZERO;
currentDuration = currentDuration.plus(totalRunTime);
if (isRunning()) {
Duration runTime = Duration.between(startTime, LocalDateTime.now());
currentDuration = currentDuration.plus(runTime);
}
return currentDuration;
}
}
Okay, so start and stop are essentially the same as pause and resume, but you get the point.
And, a runnable example...
Now, this example runs a Swing Timer constantly, but the StopWatch can paused and resumed at any time, the point is to demonstrate that the StopWatch is actually working correctly ;)
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) throws InterruptedException {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
private JButton btn;
private StopWatch stopWatch = new StopWatch();
private Timer timer;
public TestPane() {
label = new JLabel("...");
btn = new JButton("Start");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
add(btn, gbc);
timer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText(Long.toString(stopWatch.getDuration().getSeconds()));
}
});
timer.start();
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (stopWatch.isRunning()) {
stopWatch.pause();
btn.setText("Start");
} else {
stopWatch.resume();
btn.setText("Pause");
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
public class StopWatch {
private LocalDateTime startTime;
private Duration totalRunTime = Duration.ZERO;
public void start() {
startTime = LocalDateTime.now();
}
public void stop() {
Duration runTime = Duration.between(startTime, LocalDateTime.now());
totalRunTime = totalRunTime.plus(runTime);
startTime = null;
}
public void pause() {
stop();
}
public void resume() {
start();
}
public void reset() {
stop();
totalRunTime = Duration.ZERO;
}
public boolean isRunning() {
return startTime != null;
}
public Duration getDuration() {
Duration currentDuration = Duration.ZERO;
currentDuration = currentDuration.plus(totalRunTime);
if (isRunning()) {
Duration runTime = Duration.between(startTime, LocalDateTime.now());
currentDuration = currentDuration.plus(runTime);
}
return currentDuration;
}
}
}

Why is my looping GUI timer not showing up?

I'm trying to make a GUI timer without using javax.swing.Timer(kind of a strange task), but I am having trouble making it work. It's supposed to sleep the thread for 1 second, add 1 to seconds, and repeat(infinitely). When I run my program, the icon shows up, but the window does not appear. I'm guessing my error is in the Thread.sleep(1000); line or in that area, but I'm not sure why it doesn't work. Is Thread.sleep(millis)not compatible with swing applications? Do I have to multithread? Here's my program:
import java.awt.*;
import javax.swing.*;
public class GUITimer extends JFrame {
private static final long serialVersionUID = 1L;
private int seconds = 0;
public GUITimer() {
initGUI();
pack();
setVisible(true);
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void initGUI(){
JLabel title = new JLabel("Timer");
Font titleFont = new Font(Font.SERIF, Font.BOLD, 32);
title.setFont(titleFont);
title.setHorizontalAlignment(JLabel.CENTER);
title.setBackground(Color.BLACK);
title.setForeground(Color.WHITE);
title.setOpaque(true);
add(title, BorderLayout.NORTH);
JLabel timeDisplay = new JLabel(Integer.toString(seconds));//this label shows seconds
add(timeDisplay, BorderLayout.CENTER);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
seconds++;
initGUI();
}
public static void main(String[] args) {
try {
String className = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(className);
}
catch (Exception e) {}
EventQueue.invokeLater(new Runnable() {
public void run() {
new GUITimer();
}
});
}
}
EDIT:
I noticed when I print seconds in my method initGUI() to console, it prints them incrementally by one second correctly. So when it looks like:
private void initGUI() {
System.out.println(seconds);
//...
it prints the value of seconds after every second(How the JLabel should). This shows that my loop is working fine, and my Thread.sleep(1000) is OK also. My only problem now, is that the frame is not showing up.
Your main window does not appear, because you called infinite recursion inside constructor. GUITimer will not be created and this lock main thread.
You need use multithreading for this aim. Main thread for drawing time, second thread increment and put value to label
For example:
import javax.swing.*;
import java.awt.*;
public class GUITimer extends JFrame
{
private static final long serialVersionUID = 1L;
private int seconds = 0;
private Thread timerThread;
private JLabel timeDisplay;
public GUITimer()
{
initGUI();
pack();
setVisible(true);
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void initGUI()
{
JLabel title = new JLabel("Timer");
Font titleFont = new Font(Font.SERIF, Font.BOLD, 32);
title.setFont(titleFont);
title.setHorizontalAlignment(JLabel.CENTER);
title.setBackground(Color.BLACK);
title.setForeground(Color.WHITE);
title.setOpaque(true);
add(title, BorderLayout.NORTH);
timeDisplay = new JLabel(Integer.toString(seconds));//this label shows seconds
add(timeDisplay, BorderLayout.CENTER);
}
public void start()
{
seconds = 0;
timerThread = new Thread(new Runnable()
{
#Override
public void run()
{
while(true)
{
timeDisplay.setText(Integer.toString(seconds++));
try
{
Thread.sleep(1000L);
}
catch(InterruptedException e) {}
}
}
});
timerThread.start();
}
public void stop()
{
timerThread.interrupt();
}
public static void main(String[] args)
{
try
{
GUITimer timer = new GUITimer();
timer.start();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
The core issue is, you're blocking the UI by continuously calling initGUI, which will eventually fail with a StackOverFlowException, as the method calls never end
The preference would be to use a Swing Timer, but since you've stated you don't want to do that, a better solution would be to use a SwingWorker, the reason for this - Swing is NOT thread safe and SwingWorker provides a convenient mechanism for allowing us to update the UI safely.
Because both Swing Timer and Thead.sleep only guarantee a minimum delay, they are not a reliable means for measuring the passage of time, it would be better to make use of Java 8's Date/Time API instead
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label = new JLabel("00:00:00");
private TimeWorker timeWorker;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(label, gbc);
JButton button = new JButton("Start");
add(button, gbc);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (timeWorker == null) {
timeWorker = new TimeWorker(label);
timeWorker.execute();
button.setText("Stop");
} else {
timeWorker.cancel(true);
timeWorker = null;
button.setText("Start");
}
}
});
}
}
public class TimeWorker extends SwingWorker<Void, Duration> {
private JLabel label;
public TimeWorker(JLabel label) {
this.label = label;
}
#Override
protected Void doInBackground() throws Exception {
LocalDateTime startTime = LocalDateTime.now();
Duration totalDuration = Duration.ZERO;
while (!isCancelled()) {
LocalDateTime now = LocalDateTime.now();
Duration tickDuration = Duration.between(startTime, now);
publish(tickDuration);
Thread.sleep(500);
}
return null;
}
#Override
protected void process(List<Duration> chunks) {
Duration duration = chunks.get(chunks.size() - 1);
String text = format(duration);
label.setText(text);
}
public String format(Duration duration) {
long hours = duration.toHours();
duration = duration.minusHours(hours);
long minutes = duration.toMinutes();
duration = duration.minusMinutes(minutes);
long millis = duration.toMillis();
long seconds = (long)(millis / 1000.0);
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
}
}
}

Which objects do I attach the Timer class event listener to, in Java?

I am trying to create a whack a mole game. I have used swing to create background and add mole images with event listeners which increment a score each time they are clicked, but I am having problems setting whether they should be visible or not. I thought the best way to do this would be to use a timer to set/reset a boolean (vis). Randomizing the period for which the images are visible would be ideal. I have tried using a swing timer several times but doesn't seem to be working. Where do I instantiate the timer, and to what do I attach the event listener which executes the code after the timer has counted down?
package whackmole;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class WhackAMole extends JFrame {
public WhackAMole() {
createAndShowGUI();
}
static int score = 0;
public static JLabel scoreDisplay;
boolean vis;
public static void main(String[] args) throws Exception {
// run asynchronously
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setMinimumSize(new Dimension(600, 600));
Holes holes = new Holes(frame);
frame.getContentPane().add(holes);
holes.setLayout(null);
frame.pack();
frame.setVisible(true);
scoreDisplay = new JLabel("Score: " + score);
scoreDisplay.setBounds(239, 11, 84, 38);
holes.add(scoreDisplay);
Mole mole = new Mole(68, 92, true);
mole.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
score++;
scoreDisplay.setText("Score: " + score);
}
});
holes.add(mole);
Mole mole2 = new Mole(181, 320, false);
mole2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
score++;
scoreDisplay.setText("Score: " + score);
}
});
holes.add(mole2);
Mole mole3 = new Mole(414, 439, true);
mole3.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
score++;
scoreDisplay.setText("Score: " + score);
}
});
holes.add(mole3);
Mole mole4 = new Mole(297, 203, false);
mole4.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
score++;
scoreDisplay.setText("Score: " + score);
}
});
holes.add(mole4);
}
}
In this context, you can instantiate your Timer with a fixed rate and a class that implements ActionListener.
public class Example extends JPanel implements ActionListener {
private static final int RATE = 1000 / 8; // ~8 Hz
private final Timer timer = new Timer(RATE, this);
}
In this complete example, GameButton is a subclass of JToggleButton, and the implementation of ActionListener simply toggles the state of a randomly selected GameButton.
private final List<GameButton> buttons = new ArrayList<GameButton>(MAX);
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if (src == timer) {
int index = random.nextInt(game.max());
GameButton gb = buttons.get(index);
gb.setSelected(!gb.isSelected());
}
...
}
To distinguish states, the example uses Unicode glyphs, but you can use setIcon() and setSelectedIcon().

How to put timer into a GUI?

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();
}
}

Multithreading program not working

I am trying to make this work. I create a window, with one text field and button, then I run the run() method which should refresh text in textfield, and when I click on button it should iterate number by 1. I want to make this work simultaneously but I am stuck. It just iterates the number but do not refresh a value in textfield.Could you please help me somehow? I thought its easy to learn about Threads but...no :-D Here is the code.
Window class
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
#SuppressWarnings("serial")
public class Okno extends JFrame implements ActionListener,Runnable {
private JFrame o = new JFrame();
private static JTextField t = new JTextField();
private JTextField t2 = new JTextField();
private static int x = 0;
protected JButton b = new JButton("KLIK");
Okno() {
o.setVisible(true);
o.setBounds(0, 0, 300, 200);
o.setLayout(null);
o.setDefaultCloseOperation(EXIT_ON_CLOSE);
t.setBounds(10, 10, 60, 20);
t2.setBounds(80, 10, 60, 20);
b.setBounds(50, 80, 60, 30);
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
while (true) {
Okno.work();
System.out.println("Klik");
}
}
});
o.add(t);
o.add(b);
o.add(t2);
}
public static int iter(){
x++;
return x;
}
public static void work(){
try {
iter();
System.out.println(x);
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
}
#Override
public void run() {
while(true){
try {
Thread.sleep(1200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.setText(Integer.toString(x));
System.out.println("RUN");
}
}
}
Main Class
public class ThreadDemo {
public static void main(String args[]) {
Okno o = new Okno();
while(true){
o.run();
}
}
}
Swing is single threaded. Calling Thread.sleep prevents UI updates. Use a Swing Timer instead.
From GETah's answer to java stopwatch that updates gui every second:
Something along these lines should do it:
import java.awt.EventQueue;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JLabel;
/** #see https://stackoverflow.com/a/11058263/230513 */
public class Clock {
private Timer timer = new Timer();
private JLabel timeLabel = new JLabel(" ", JLabel.CENTER);
public Clock() {
JFrame f = new JFrame("Seconds");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(timeLabel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
timer.schedule(new UpdateUITask(), 0, 1000);
}
private class UpdateUITask extends TimerTask {
int nSeconds = 0;
#Override
public void run() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
timeLabel.setText(String.valueOf(nSeconds++));
}
});
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
final Clock clock = new Clock();
}
});
}
}
The timeLabel will always display the number of seconds the timer
has been running.
You will need to correctly format it to display "hh:mm:ss"; one approach is shown here.
Create a container and add the label to it so that you can display it as part of the GUI.
Compare the result to this alternate using javax.swing.Timer.

Categories