Why does my Java timer program not work on Mac? - java

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++;
}
}

Related

Getting reaction time after pressing a key game

So I am making a game that records your reaction time after you see something pop up on the screen, but I am having trouble with getting that reaction time. I want the user to press the up arrow key once they see a blue ball and I want to record their reaction time once they pressed that button.
Here is my code:
public class Game extends JPanel
{
private JLabel start, main, time;
private ImageIcon constant, react;
final int width = 600;
final int height = 600;
private Timer replace;
private Random random;
private int randTime;
private long startTime;
private long stopTime;
private long reactionTime;
private Action upAction;
public Game()
{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setPreferredSize(new Dimension(width, height));
setBackground(Color.black);
start = new JLabel("Click Up Arrow when you see a blue ball");
start.setForeground(Color.white);
start.setAlignmentX(Component.CENTER_ALIGNMENT);
add(start);
constant = new ImageIcon("constantCircle.png");
main = new JLabel(constant);
main.setAlignmentX(Component.CENTER_ALIGNMENT);
randomTime();
replace = new Timer(randTime, timeListener);
startTime = System.currentTimeMillis();
replace.setRepeats(false);
replace.start();
add(main);
time = new JLabel("0");
time.getInputMap().put(KeyStroke.getKeyStroke("UP"), "upAction");
time.getActionMap().put("upAction", upAction);
add(time);
}
public void randomTime()
{
random = new Random();
int max = 8000;
randTime = random.nextInt(max);
}
ActionListener timeListener = new ActionListener()
{
public void actionPerformed (ActionEvent e)
{
react = new ImageIcon("reactCircle.png");
main.setIcon(react);
}
};
public class UpAction extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
stopTime = System.currentTimeMillis();
reactionTime = stopTime - startTime;
time.setText("" + reactionTime);
}
}
}
I setup a "startTime" using System.currentTimeMillis to get the time after the ball turns blue but I am not sure if that is the correct way to do it.
I also setup a "stopTime" in the "UpAction" class where I want to get the time once the user presses up arrow but I it does not work.
if anything doesn't make sense or isn't clear enough, I'll try my best to elaborate more
I came up with the following GUI.
There are two important principles I want to explain. The first is that creating the GUI is a separate process from updating the GUI. The second is that the game process is a state machine. The game is in six separate states. Here's what I wrote to keep the states in mind.
Sequence of events
Left-click button
Wait 2 - 4 seconds to display the circle.
Capture start time
Left-click button
Capture end time.
Calculate and display reaction time.
Repeat 1 - 6.
So, for the GUI, I created a JFrame and three JPanels; an upper JPanel, a drawing JPanel, and a button JPanel.
I started the Swing application with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
The JFrame has a default BorderLayout, which I used to place the three JPanels. The JFrame method calls must be executed in a specific order. This is the order I use for all my Swing applications.
The upper JPanel contains the instructions and the reaction time display. A JTextArea is great for displaying instructions. I put the JTextArea inside an inner JPanel using a FlowLayout, which I placed in the upper JPanel using a BorderLayout. Nesting layouts like this is a good way to organize the Swing components in a logical manner.
I put the reaction time Swing components in another inner JPanel, which I placed in the upper JPanel.
I created a drawing JPanel so I wouldn't have to bother with an image.
The button JPanel holds the Submit JButton.
I created two controller classes. One controller class, ButtonListener, responds to the JButton left-clicks. The other controller class, TimerListener, creates the delay for drawing the circle.
The ButtonListener state variable allows me to provide different functionality with the same ActionListener. If you wish, you can write separate ActionListener classes, one for each function.
By separating my code into view and controller classes, I could separate my concerns and focus on one part of the application at a time.
Here's the complete runnable code. I made all the classes inner classes so I could post this code as one block.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class ReactionTimeGame implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new ReactionTimeGame());
}
private long reactionTime;
private DrawingPanel drawingPanel;
private JTextField reactionTimeField;
public ReactionTimeGame() {
this.reactionTime = 0L;
}
#Override
public void run() {
JFrame frame = new JFrame("Reaction Time Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createUpperPanel(), BorderLayout.BEFORE_FIRST_LINE);
this.drawingPanel = new DrawingPanel();
frame.add(drawingPanel, BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createUpperPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JPanel innerPanel = new JPanel(new FlowLayout());
String instructions = "This game will test your reaction time. To play "
+ "the game, left-click on the Submit button. After a random time "
+ "from 2 - 4 seconds, a circle will appear. Left-click the "
+ "Submit button again. Your reaction time will be displayed "
+ "above where the circle was.\n\n"
+ "Left-click the Submit button to start each round of the game.";
JTextArea textArea = new JTextArea(7, 40);
textArea.setEditable(false);
textArea.setText(instructions);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
innerPanel.add(textArea);
panel.add(innerPanel, BorderLayout.BEFORE_FIRST_LINE);
innerPanel = new JPanel(new FlowLayout());
JLabel label = new JLabel("Reaction Time:");
innerPanel.add(label);
reactionTimeField = new JTextField(5);
reactionTimeField.setEditable(false);
updateReactionTime();
innerPanel.add(reactionTimeField);
label = new JLabel("seconds");
innerPanel.add(label);
panel.add(innerPanel, BorderLayout.AFTER_LAST_LINE);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton button = new JButton("Submit");
button.addActionListener(new ButtonListener());
panel.add(button);
return panel;
}
public void setReactionTime(long reactionTime) {
this.reactionTime = reactionTime;
}
public void drawCircle() {
drawingPanel.setDrawCircle(true);
drawingPanel.repaint();
}
public void eraseCircle() {
drawingPanel.setDrawCircle(false);
drawingPanel.repaint();
}
public void updateReactionTime() {
double time = 0.001 * reactionTime;
reactionTimeField.setText(String.format("%.3f", time));
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private boolean drawCircle;
public DrawingPanel() {
this.drawCircle = false;
this.setPreferredSize(new Dimension(300, 300));
}
public void setDrawCircle(boolean drawCircle) {
this.drawCircle = drawCircle;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (drawCircle) {
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int radius = Math.min(getWidth(), getHeight()) * 9 / 20;
int diameter = radius + radius;
g.setColor(Color.MAGENTA);
g.fillOval(centerX - radius, centerY - radius, diameter, diameter);
}
}
}
public class ButtonListener implements ActionListener {
private int state;
private long startTime;
private final Random random;
private Timer timer;
public ButtonListener() {
this.state = 1;
this.random = new Random();
}
#Override
public void actionPerformed(ActionEvent event) {
switch (state) {
case 1:
int delay = random.nextInt(2000) + 2000;
timer = new Timer(delay, new TimerListener(this));
timer.start();
state = 2;
break;
case 2:
setEndTime(System.currentTimeMillis());
eraseCircle();
state = 1;
break;
}
}
public int getState() {
return state;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public void setEndTime(long endTime) {
long elapsedTime = endTime - startTime;
setReactionTime(elapsedTime);
updateReactionTime();
}
}
public class TimerListener implements ActionListener {
private final ButtonListener listener;
public TimerListener(ButtonListener listener) {
this.listener = listener;
}
#Override
public void actionPerformed(ActionEvent event) {
Timer timer = (Timer) event.getSource();
timer.stop();
if (listener.getState() == 2) {
listener.setStartTime(System.currentTimeMillis());
drawCircle();
}
}
}
}

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

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

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).

How do I create buttons that reset and pause a timer?

How do I make the two buttons that are displayed reset / pause the timer? The timer works but I want to change the code for the buttons so that they will change the timer instead of outputting to the console. Thank you.
CODE:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class createWindow extends JFrame implements ActionListener
{
public static void main(String[] args)
{
new createWindow();
}//end main
createWindow()
{
super("Frame");
setSize(400,70);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
show();
final JLabel time = new JLabel("Timer");
JButton reset = new JButton("Reset timer");
JButton pause = new JButton("Pause timer");
reset.setActionCommand("resetClicked");
pause.setActionCommand("pauseClicked");
reset.addActionListener(this);
pause.addActionListener(this);
add(pause);
add(time);
add(reset);
long start = System.currentTimeMillis();
while (true)
{
long timer = System.currentTimeMillis() - start;
final int seconds = (int) (timer / 1000);
String display = Integer.toString(seconds);
time.setText(display);
}//end while loop
}//end constructor
#Override
public void actionPerformed(ActionEvent e)
{
String buttonClicked = e.getActionCommand();
if(buttonClicked.equals("resetClicked"))
{
System.out.println("The reset button was clicked"); //Change to reset timer
}
else if(buttonClicked.equals("pauseClicked"))
{
System.out.println("The pause button was clicked"); //Change to pause timer
}
}//end listener
}
Don't use an infinite while loop. This blocks the EDT. Instead use a Swing Timer. This will give you control to start and stop the Timer.
Stopwatch Example
Side Notes:
Don't use JFrame.show as that method is deprecated. Use JFrame.setVisible instead. Also make this call when all components have been added to the frame.
The functionality for the JButtons is sufficiently different to warrant using separate ActionListener instances for each button.
The preferred approach is to use a JFrame instance directly rather then extending it.
Class names in Java begin with uppercase so createWindow would become CreateWindow.

Progress bar to run simultaneously with a function(in another class)

I have created a form on which two components are present, button and progressbar (Netbeans drag and drop).Form contains the main method from where my application starts.I have created another class as well in which i have written a function.What i want is that when i press a button the application goes into the function and the progressbar runs simultaneously with it and when that function is complete with its functionality the the progress bar shows 100% complete.Now this function can take anytime for its completion so i cannot set the max value for the progressbar.So, what to do in this case?Can anyone please provide me with a good example .
JProgressBar.setIndeterminate(true)
Since what sort of a work you are doing inside that so called "Called Function", so it's tough to say, what you want in the scenario, though you can put your lines like progressBar.setValue(someProgress); at regular intervals with it's Indeterminate State to true, and at the end of the function you can simply say that progressBar.setValue(100); and the Indeterminate State will turn to false here, so that it can show that to the end user.
Have a look at this sample program :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ProgressExample
{
public static JProgressBar progressBar;
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Progress Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
JButton button = new JButton("START");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
progressBar.setIndeterminate(true);
WorkingDialog wd = new WorkingDialog();
wd.createAndDisplayDialog();
}
});
contentPane.add(progressBar, BorderLayout.PAGE_START);
contentPane.add(button, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new ProgressExample().createAndDisplayGUI();
}
});
}
}
class WorkingDialog extends JDialog
{
private String message = "HelloWorld";
private int count = 0;
private JTextField tfield;
private Timer timer;
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
if (count == 10)
{
timer.stop();
ProgressExample.progressBar.setIndeterminate(false);
ProgressExample.progressBar.setValue(100);
ProgressExample.progressBar.setStringPainted(true);
dispose();
return;
}
tfield.setText(tfield.getText() + message.charAt(count));
count++;
}
};
public void createAndDisplayDialog()
{
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
setLocationByPlatform(true);
JPanel panel = new JPanel();
tfield = new JTextField(10);
panel.add(tfield);
add(panel);
pack();
setVisible(true);
timer = new Timer(1000, timerAction);
timer.start();
}
}
So , it seems like you are write
ProgressExample.progressBar.setIndeterminate(false);
ProgressExample.progressBar.setValue(100);
ProgressExample.progressBar.setStringPainted(true);
after your while loop.
You can take a look at my answer in a previous SO question, which contains a sample using a JProgressBar which gets updates from another Thread by using a SwingWorker. Whether or not to use a SwingWorker depends a bit on your use case. If the function take some time to run you better use the SwingWorker to avoid blocking the UI.

Categories

Resources