javax.swing.timer subtracts as much as I click on start button - java

First of all hi! This is my first post on stackoverflow! This is my second attempt to program something in Java and the first ever attempt with a gui.
I'm actually having 2 problems. The first being the program and the second understanding a part of the code.
How the program should work:
When pressing start it counts down from 01:00 to 00:00 every minute (01:00 -> 00:59 -> 00:58). When you press stop, it stops counting down (duh) and when you press start again, it starts from 01:00 like the first time.
The program problem:
With that said. This only works the first time I press start. When I press start multiple times it subtracts that amount of times from the clock. Pressed 2 times (01:00 -> 00:58 -> 00:56). Pressed 4 times (01:00 -> 00:56 -> 00:52). etc... This obviously should not be happening.
The understanding problem:
I am having a hard time understanding why the timer requires an ActionListener and why it works when you use 'null'. In some cases it also works when using 'this' (which I also don't understand.).
Java Swing Timer Documentation
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class CountdownClock extends JFrame
{
private int oneSecond = 1000; //Milliseconds
private Timer timer = new Timer(oneSecond * 60, null);
private int timerCount = 59;
public static void main(String args[])
{
new CountdownClock();
}
CountdownClock()
{
this.getContentPane().setLayout(null);
this.setBounds(800, 450, 300, 125);
final JLabel countdownLabel = new JLabel("01:00");
countdownLabel.setBounds(110, 10, 125, 30);
countdownLabel.setFont(new Font("Serif", Font.PLAIN, 30));
JButton startButton = new JButton("Start");
startButton.setBounds(10, 50, 125, 30);
startButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
timer.setRepeats(true);
timer.stop();
countdownLabel.setText("01:00");
timerCount = 59;
timer.start();
timer.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
if (timerCount == 0)
{
timer.stop();
countdownLabel.setText("00:00");
timerCount = 59;
}
else if (timerCount <= 9)
{
countdownLabel.setText("00:0" + String.valueOf(timerCount));
timerCount = timerCount - 1;
}
else
{
countdownLabel.setText("00:" + String.valueOf(timerCount));
timerCount = timerCount - 1;
}
}
});
}
});
JButton stopButton = new JButton("Stop");
stopButton.setBounds(150, 50, 125, 30);
stopButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
timer.stop();
countdownLabel.setText("01:00");
timerCount = 59;
}
});
add(countdownLabel);
add(startButton);
add(stopButton);
setVisible(true);
}
}

This happens because you are adding an ActionListener to the Timer every time that you press the button. So, since a Timer allows multiple listeners, everyone of them gets notified when the timer ticks.
To solve the problems you could just instantiate a new Timer every time you press the start button (timer = new Timer()). Or add the ActionListener just once in your JFrame constructor . Or even remove the listener (but you should save a reference to it somewhere).

Related

How to add a countdown code to a Java app?

I've recently got a project in school.
Create a Java GUI with an image as background and some textbox.
the first textbox is just a text that says: Lunch break at 1pm.
the second textbox is a countdown timer. This timer should appear 5 minutes before the end of the upcoming break, which counts down from 5:00 to 0:00 minutes every second. When reaching 0:00, the timer should respond to a text (e.g. "The
Presentation will start shortly ").
Image as a background: done
Text that says: Lunch break at 1pm: done
Countdown: I'm stuck at this point. I program a countdown timer first on the console. But I really don't know how to include this countdown to a Java GUI.
Do you have any suggestions?
This is my code for the background:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Toolkit;
import javax.swing.JPanel;
import javax.swing.*;
public class Bildhintergrund extends JFrame{
//Background
public Bildhintergrund () {
setTitle(" Bildhintergrund");
setSize(Toolkit.getDefaultToolkit().getScreenSize());
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLayout(new BorderLayout());
setContentPane(new JLabel(new ImageIcon("/path/to/bild.jpg")));
setLayout(new FlowLayout());
JLabel background = new JLabel();
add(background);
//Text
JLabel text = new JLabel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
};
;
JPanel panel = new JPanel();
Dimension size = text.getPreferredSize();
getContentPane().add( text );
text.setFont(text.getFont().deriveFont((float) 58));
text.setText("Lunch break at 1pm");
/*text.setAlignmentX(0);
text.setAlignmentY(0);*/
text.setBounds(300, 300, size.width, size.height);
panel.add(text);
panel.setLayout(null);
add(text);
}
public static void main(String[] args) {
new Bildhintergrund();
}
}
This is my code for the countdown:
{
/*int Time = 5;
String time;
int seconds;
int minutes;*/
int timet= Time * 60; // Convert to seconds
long delay = timet * 1000;
do
{
minutes = timet / 60;
seconds = timet % 60;
time = minutes + ":" + seconds;
System.out.println(GetTimer());
Thread.sleep(1000);
timet = timet - 1;
delay = delay - 1000;
}
while (delay != 0);
System.out.println("Another topic will follow");
}
public static String GetTimer()
{
return time;
}
}
You can use javax.swing.Timer like this example:
javax.swing.Timer timer = new javax.swing.Timer(1000/*timer delay between calling ActionListener.actionPerformed(ActionEvent e) (in milliseconds)*/, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Second over!!!");
//put your code here
}
});
timer.setRepeats(true);//makes timer repeats forever (or until call timer.stop() method)
timer.start();

Why does my Java timer program not work on Mac?

Is there any reasons due to using java on Mac that my code below wouldn't work? It is working on Windows. However it will not display the GUI on a Mac, I have tried updating java and restarting the machine. It still doesn't display the GUI with the timer.Is it possible it could be the program (Eclipse) that i am using to code in?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerApplication extends JFrame implements ActionListener{
private javax.swing.Timer timer;
private JTextField seconds;
private JTextField minutes;
private int nTimeDelay = 50;
private int ticks = 0;
public static void main(String[] args) {
TimerApplication frame = new TimerApplication();
frame.setSize(300, 100);
frame.createGUI();
frame.setVisible(true);
}
private void createGUI(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container window = getContentPane();
window.setLayout(new FlowLayout());;
seconds = new JTextField();
minutes = new JTextField();
window.add(minutes);
window.add(seconds);
timer = new javax.swing.Timer(50, this);
timer.start();
ticks=0;
}
#Override
public void actionPerformed(ActionEvent event) {
if(event.getSource()==timer)
{
minutes.setText(String.format("%02d", (ticks*(nTimeDelay)/1000) / 60));
seconds.setText(String.format("%02d",(ticks*(nTimeDelay)/1000) % 60));
ticks++;
}
}
}
This smells like a multi-threading bug.
I think that there is inadequate synchronization between the "main" thread which initializes the TimerApplication and assigns a value to timer, and the Swing event dispatcher thread (EDT) that will be executing the calls to tour actionPerformed method. This means that it is possible for the actionPerformed call to never see the value that was assigned to timer in the other thread.
Net result: event.getSource() == timer would always be false.
One way to correct this would be make the following changes:
synchronized (this) {
timer = new javax.swing.Timer(50, this);
timer.start();
ticks = 0;
}
and
synchronized (this) {
if (event.getSource() == timer) {
minutes.setText(String.format("%02d", ticks * nTimeDelay / 1000 / 60));
seconds.setText(String.format("%02d", ticks * nTimeDelay / 1000 % 60));
ticks++;
}
}

How and where to use javax.swing Timer

Please help, I'm trying to use javax.swing.Timer in my program. I have looked at lots of examples, but it still doesn't make sense to me. I am writing a program that has the user guessing the price. What I can't seem to figure out is how to have a timer that counts down from 30 seconds after the "new Game" button is clicked. If the user has not guessed the correct answer, then I want the game to display "You lose", but I also want the timer to stop if they get the correct answer in under 30 seconds and display that time. I believe I'm suppose to use
timer = new Timer(Speed, this);
timer.start();
timer.end();
but, I'm not sure what else I need for the timer or where to place these within my code. Any help would be much appreciated. Below is the code for my program...
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class ClockGame extends JFrame {
//Declare fields for GUI components
private JTextField guessField;
private JButton newGameButton;
private JLabel messageLabel;
private JLabel guessLabel;
private ImageIcon clockImage;
private int countTotal;
private Random rand;
private JLabel title;
private int number;
private Timer timer;
public ClockGame() {
//Build GUI
super ("Clock Game");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set layout
this.setLayout(new BorderLayout());
//Create the main panel
JPanel mainPanel = new JPanel();
//Create components and place them in the panel
rand = new Random();
guessLabel = new JLabel("Guess: ");
guessField = new JTextField(20);
messageLabel = new JLabel(" Click New Game to Begin");
clockImage = new ImageIcon("clock.jpg");
newGameButton = new JButton("New Game");
title = new JLabel("The Clock Game", clockImage, SwingConstants.CENTER);
//Set font for clockGameLabel
title.setFont(new Font("Calibri", Font.BOLD, 24));
//Set messageLabel Color
messageLabel.setOpaque(true);
messageLabel.setBackground(Color.yellow);
newGameButton.addActionListener(new ButtonListener());
guessField.addActionListener(new AnswerListener());
//Add components to the panel
mainPanel.add(guessLabel);
mainPanel.add(guessField);
mainPanel.add(newGameButton);
this.add(title, BorderLayout.NORTH);
this.add(messageLabel, BorderLayout.SOUTH);
//Add the panel to this JFrame
this.add(mainPanel, BorderLayout.CENTER);
//Sizes this JFrame so that it is just big enough to hold the components
this.setSize(340,225);
//Make the JFrame visible on the screen
this.setVisible(true);
}
private class AnswerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//Code to check to see if answer is correct
int sum = number;
int answer = Integer.parseInt(guessField.getText());
Color purple = new Color(153, 153, 253);
countTotal++;
if (sum < answer)
{
messageLabel.setText("Too High");
messageLabel.setBackground(Color.red);
}
else if (sum > answer)
{
messageLabel.setText("Too Low");
messageLabel.setBackground(purple);
}
else
{
messageLabel.setText("Correct! It took you " + countTotal + " tries, in " +
timer + " seconds");
messageLabel.setBackground(Color.yellow);
}
}
}
private class ButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
number = rand.nextInt(1001);
messageLabel.setText(" The price is between $1 and $1000, begin.");
messageLabel.setBackground(Color.green);
countTotal = 0;
}
}
public static void main(String[] args) {
ClockGame frame = new ClockGame();
}
}
timer.end();
There is no end() method. First you need to read the API for the appropriate method to use.
counts down from 30 seconds after the "new Game" button is clicked.
So in the ActionListener you add to the button you need to start the Timer and schedule it to fire every second. When the Timer fires you decrement your count by 1.
I also want the timer to stop if they get the correct answer
So when they get the correct answer you stop the Timer. So in your code where you update the text of the label you stop the Timer.
If the user has not guessed the correct answer, then I want the game to display "You lose",
So when the timer count reaches 0, you 1) stop the timer and 2) display the message.
In the constructor of you class you would actually create the Timer, so that the above methods in your class have a reference to the Timer so it can be started and stopped as required.
What you really need to do is forget about your game and learn how to use a Timer. So you create a frame with a label and two buttons. The label will display the initial count of 30. Then you have a "Start" button that decrements the label by 1 each time the Timer fires. Then you have a "Stop" button that stops the Timer so the count is not decremented.
Once you understand the basic concept of starting and stopping the Timer, then you add the code to your real program.
Well to begin... you would need a JLabel that is assigned to print "You lose" and another one that prints the Time that it took the player to answer the question. Add these to your Frame however you want.
JLabel outcome = new JLabel(); //setText to win or lose.
JLabel countdown = new JLabel(); //setTime as Timer counts down.
After you have instantiated these Labels. The Timer needs to be instantiated.
Timer timer = new Timer(1000, new ActionListener() { //Change parameters to your needs.
int count = 30;
public void actionPerformed(ActionEvent e) {
count--;
if(count == 0) //They lose
{
countdown.setText("CountDown: " + count);
outcome.setText("You Lose");
timer.stop(); //ends the countdown.
}
else if(userGotAnswer) // You need to create a boolean value that changes when a user gets the answer right.
{
countdown.setText("CountDown: " + count);
outcome.setText("You win");
timer.stop(); //ends the countdown
}
else
{
countdown.setText("CountDown: " + count); //default
}
}
});
Then call
timer.start();
when you want the timer to start.

Java Label Timer and Saving

Let me explain what I am trying to do.
I have two classes extending JFrame, the StartJFrame and TestingJFrame. In the main method, I start up a StartJFrame. It has a single button, start. When that is pressed, I have it set up to hide that frame and start up the TestingJFrame. Right now I don't have anything in the TestingJFrame.
In that screen, I want to have a label in the bottom right corner that is a timer, starting on 45 seconds and counting down to 0. I also need to have some code run every 10th of a second, and collect some data. There will be two buttons in the TestingJFrame, Yes and No. When one of them is pressed, it should stop the timer and save the information.
The data is basically just doubles. I am only going to be collecting data once per run of the program. I have a UserData class that holds some information about the test subject, and a list of doubles, it is added to every 10th of a second. I have a general idea how to save the data in java.
My question is, how should I set up the timer, so that it will count down from 45 seconds, and when it reaches 0 or the user presses the yes or no button it will call a function to save the data? I think I can handle the saving data part.
Sorry if this is really easy, I'm new to Java (from c#) and Swing has been confusing me a bit.
The first part (show the count down and stopping the timer) is relatively easy...
public class TimerTest01 {
public static void main(String[] args) {
new TimerTest01();
}
public TimerTest01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
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 Timer timer;
private long startTime;
public TestPane() {
setLayout(new GridLayout(0, 1));
label = new JLabel("...");
label.setHorizontalAlignment(JLabel.CENTER);
final JButton btn = new JButton("Start");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (timer.isRunning()) {
timer.stop();
btn.setText("Start");
} else {
startTime = System.currentTimeMillis();
timer.restart();
btn.setText("Stop");
}
repaint();
}
});
add(label);
add(btn);
timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long endTime = (startTime + 45000);
long timeLeft = endTime - System.currentTimeMillis();
if (timeLeft < 0) {
timer.stop();
label.setText("Expired");
btn.setText("Start");
} else {
label.setText(Long.toString(timeLeft / 1000));
}
repaint();
}
});
}
}
}
Take a look at Swing Timer for more info
The second part of you question is to vague to reliably provide you with an answer. Where is the data coming from? How is collected??
You can use javax.swing.Timer to setup your timer. You can have a look at the official tutorial too.

JOptionPane : Display button "Ok" after a certain amount of time

I would like to display the button "OK" of this JOptionPane only after a certain amount of time (let's say for example 5 sec). (My aim is actually to let finish some thread work behind this other thread)
JOptionPane jop2 = new JOptionPane();
jop2.showMessageDialog(null, "Please wait 5s", "WAIT", JOptionPane.INFORMATION_MESSAGE);
I don't know at all how to do that, could you provide me some code working which will answer to this problem?
Thank you very much in advance!
There is no specific way to do this using JOptionPane. You will have to create a custom dialog and reveal the OK button after a fixed time. You could use one pass of a Swing timer.
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
button.setVisible(true);
}
};
Timer timer = new Timer(0, taskPerformer);
timer.setInitialDelay(5000);
timer.setRepeats(false);
timer.start();
It sounds like what you're looking for is a combination of the SwingWorker and the ProgressMonitor. The SwingWorker will preform your long running task (the 5 second one), and inform the user of how it's progressing using the ProgressMonitor. An example showing you how to get the two working together can be found here:
getting the cancel event of Java ProgressMonitor
Of course, if you're convinced you want to take the approach of displaying the continue button once the work is done, here's an example that should get you started in the right direction. You'll use a SwingWorker to alert your Dialog that the long running background task has completed.
import java.awt.*;
import java.awt.Dialog.ModalityType;
import java.awt.event.*;
import javax.swing.*;
public class TempProject extends Box{
public TempProject(){
super(BoxLayout.Y_AXIS);
//Contains the content of the Alert Dialog
Box info = Box.createVerticalBox();
info.add(new Label("Please wait 5 seconds"));
final JButton continueButton = new JButton("Continue");
info.add(continueButton);
//The alert to wait 5 seconds
final JDialog d = new JDialog();
d.setTitle("WAIT");
d.setModalityType(ModalityType.APPLICATION_MODAL);
d.setContentPane(info);
d.pack();
//The action of the "Continue Button"
continueButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
d.dispose();
}
});
continueButton.setVisible(false);
//Thread That Does Work
final SwingWorker sw = new SwingWorker<Integer, Integer>()
{
protected Integer doInBackground() throws Exception {
//Do long running thread work here
int i = 0;
while (i++ < 100) {
System.out.println(i);
Thread.sleep(100);
}
return null;
}
#Override
protected void done(){
// What to do when the long runnng thread is done
continueButton.setVisible(true);
}
};
//Button to start the long running task
JButton button = new JButton("Click Me");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
sw.execute();
d.setVisible(true);
}});
add(button);
}
public static void main(String args[])
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setContentPane(new TempProject());
frame.setPreferredSize(new Dimension(500, 400));
frame.pack();
frame.setVisible(true);
}
});
}
}
you could use something like this to stop the code for 5 seconds
try {
Thread.sleep(5000); // do nothing for 5000 miliseconds (5 seconds)
} catch (InterruptedException e) {
e.printStackTrace();
}

Categories

Resources