I made a puzzle game in java Applet, and I need to add a timer that runs for 5 minutes where the player has to solve the puzzle within this time, if not a dialog box will appear asking to retry, so then I need the timer to start again.
Can someone tell me how can I code this.
public void init (){
String MINUTES = getParameter("minutes");
if (MINUTES != null) remaining = Integer.parseInt(MINUTES) * 600000;
else remaining = 600000; // 10 minutes by default
// Create a JLabel to display remaining time, and set some PROPERTIES.
label = new JLabel();
// label.setHorizontalAlignment(SwingConstants.CENTER );
// label.setOpaque(false); // So label draws the background color
// Now add the label to the applet. Like JFrame and JDialog, JApplet
// has a content pane that you add children to
count.add(label);
Puzframe.add(count,BorderLayout.SOUTH);
// Obtain a NumberFormat object to convert NUMBER of minutes and
// seconds to strings. Set it up to produce a leading 0 if necessary
format = NumberFormat.getNumberInstance();
format.setMinimumIntegerDigits(2); // pad with 0 if necessary
// Specify a MouseListener to handle mouse events in the applet.
// Note that the applet implements this interface itself
// Create a timer to call the actionPerformed() method immediately,
// and then every 1000 milliseconds. Note we don't START the timer yet.
timer = new Timer(1000, this);
timer.setInitialDelay(0); //
timer.start(); }
public void start() { resume(); }
//The browser calls this to stop the applet. It may be restarted later.
//The pause() method is defined below
void resume() {
// Restore the time we're counting down from and restart the timer.
lastUpdate = System.currentTimeMillis();
timer.start(); // Start the timer
}`
//Pause the countdown
void updateDisplay() {
long now = System.currentTimeMillis(); // current time in ms
long elapsed = now - lastUpdate; // ms elapsed since last update
remaining -= elapsed; // adjust remaining time
lastUpdate = now; // remember this update time
// Convert remaining milliseconds to mm:ss format and display
if (remaining < 0) remaining = 0;
int minutes = (int)(remaining/60000);
int seconds = (int)((remaining)/1000);
label.setText(format.format(minutes) + ":" + format.format(seconds));
label.setForeground(new Color(251,251,254));
label.setBackground(new Color(0,0,0));
// If we've completed the countdown beep and display new page
if (remaining == 0) {
// Stop updating now.
timer.stop();
}
count.add(label);
Puzframe.add(label,BorderLayout.SOUTH); }
This what I have so far, but my problem is that it doesn't appear in my game. I'm calling the updateDisplay() from actionPerformed
Use Swing Timer it is made for such a scenario
//javax.swing.Timer
timer = new Timer(4000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(mainFrame,
"End Of Game",
"5 minutes has passed",
JOptionPane.ERROR_MESSAGE);
}
});
I prepared a simple example to demonstrate it
Example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SwingControlDemo {
private JFrame mainFrame;
private JPanel controlPanel;
private Timer timer;
public SwingControlDemo(){
prepareGUI();
}
public static void main(String[] args){
SwingControlDemo swingControlDemo = new SwingControlDemo();
swingControlDemo.showEventDemo();
}
private void prepareGUI(){
mainFrame = new JFrame("Java SWING Examples");
mainFrame.setSize(400,400);
mainFrame.setLayout(new GridLayout(3, 1));
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
}
});
controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
mainFrame.add(controlPanel);
mainFrame.setVisible(true);
//javax.swing.Timer
timer = new Timer(4000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(mainFrame,
"End Of Game",
"5 minutes has passed",
JOptionPane.ERROR_MESSAGE);
}
});
}
private void showEventDemo(){
JButton okButton = new JButton("Start Game");
okButton.setActionCommand("OK");
okButton.addActionListener(new ButtonClickListener());
controlPanel.add(okButton);
mainFrame.setVisible(true);
}
private class ButtonClickListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
timer.start();
String command = e.getActionCommand();
if( command.equals( "OK" )) {
System.out.println("Timer started");
}
}
}
}
Related
A Swing based Timer is recommended for updating GUI components - because the calls to the components are automatically on the Event Dispatch Thread (the correct thread for updating Swing or AWT based components).
The Swing Timer though, has a tendency to 'drift' off time. If you create a timer that fires every second, after an hour or so, it might have drifted a few seconds above or below the elapsed time.
When using a Swing Timer to update a display which must be accurate (e.g. a countdown timer / stop watch), how do we avoid this time drift?
The trick here is to keep track of the elapsed time, check it frequently, and update the GUI when the actual time required ('one second' in this case) has passed.
Here is an example of doing that. Pay attention to the comments in the code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class NonDriftingCountdownTimer {
private JComponent ui = null;
private Timer timer;
private JLabel outputLabel;
NonDriftingCountdownTimer() {
initUI();
}
/** Keeps track of the start time and adjusts the count
* based on the ELAPSED time.
* This should be used with a short time between listener calls. */
class TimerActionListener implements ActionListener {
long start = -1l;
int duration;
int count = 0;
TimerActionListener(int duration) {
this.duration = duration;
}
#Override
public void actionPerformed(ActionEvent e) {
long time = System.currentTimeMillis();
if (start<0l) {
start = time;
} else {
long next = start+(count*1000);
if (time>next) {
count++;
outputLabel.setText((duration-count)+"");
if (count==duration) {
timer.stop();
JOptionPane.showMessageDialog(
outputLabel, "Time Is Up!");
}
}
}
}
}
public final void initUI() {
if (ui!=null) return;
ui = new JPanel(new BorderLayout(4,4));
ui.setBorder(new EmptyBorder(4,4,4,4));
JPanel controlPanel = new JPanel();
ui.add(controlPanel, BorderLayout.PAGE_START);
final SpinnerNumberModel durationModel =
new SpinnerNumberModel(10, 1, 1200, 1);
JSpinner spinner = new JSpinner(durationModel);
controlPanel.add(spinner);
JButton startButton = new JButton("Start");
ActionListener startListener = (ActionEvent e) -> {
int duration = durationModel.getNumber().intValue();
TimerActionListener timerActionListener =
new TimerActionListener(duration);
if (timer!=null) { timer.stop(); }
// Note the short time of fire. This will allow accuracy
// to within 1/50th of a second (without gradual drift).
timer = new Timer(20, timerActionListener);
timer.start();
};
startButton.addActionListener(startListener);
controlPanel.add(startButton);
outputLabel = new JLabel("0000", SwingConstants.TRAILING);
outputLabel.setFont(new Font(Font.MONOSPACED, Font.BOLD, 200));
ui.add(outputLabel);
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
NonDriftingCountdownTimer o = new NonDriftingCountdownTimer();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 4 years ago.
I am working on this program that calculates the Beats per Minute (BPM) when you click the button. When you click two times, it is supposed to display the current BPM, and display the new one with every click after that. What the problem is, though, is that the display isn't changing. What do I need to do?
Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class BPM extends JPanel implements ActionListener {
JLabel label;
public String display;
public int bpm;
public int buttonPressed;
public int time1;
public int time2;
public int time3;
public int counter[];
public void addComponents(Container pane) {
JPanel buttons = new JPanel();
JButton bpmButton = new JButton("Click");
bpmButton.setSize(new Dimension(100, 50));
bpmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
buttonPressed++;
counter = new int[2];
if (buttonPressed == 1) {
counter[0] = (int)(System.currentTimeMillis());
} else if (buttonPressed == 2) {
counter[1] = (int)(System.currentTimeMillis());
calculateTimeBetweenClicks();
setTime();
} else {
counter[0] = counter[1];
counter[1] = (int)(System.currentTimeMillis());
calculateTimeBetweenClicks();
setTime();
}
}
});
display = "0";
label = new JLabel(display, SwingConstants.CENTER);
label.setFont(label.getFont().deriveFont(100.0f)); // original 45
pane.add(label, BorderLayout.PAGE_START);
pane.add(bpmButton, BorderLayout.CENTER);
}
// Calculates the difference between the two saved clicks
public void calculateTimeBetweenClicks() {
if (buttonPressed == 1) {
time1 = counter[0];
} else {
time1 = counter[0];
time2 = counter[1];
}
time3 = time2 - time1;
}
// Calculates the BPM and changes the display accordingly
public void setTime() {
bpm = 60000 / time3;
display = "" + bpm + "";
label.setText(display);
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
public static void createAndShowGUI() {
// Creates the window
JFrame frame = new JFrame("BPM Calculator");
frame.setPreferredSize(new Dimension(300, 200)); // original (250, 130)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Adds the components to the content pane
BPM window = new BPM();
window.addComponents(frame.getContentPane());
//Displays the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
// Turns off bold text
UIManager.put("swing.boldMetal", Boolean.FALSE);
// Allows the components to be used and interacted with
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The problem is in your addComponents method, you are creating a new array on each and every button click (so you end up with a new and empty array). This is throwing off your calculation. Simply move the instantiation of your array to somewhere outside of the ActionListener like this...
public void addComponents(Container pane) {
JPanel buttons = new JPanel();
counter = new int[2]; //Move this line to here...
JButton bpmButton = new JButton("Click");
bpmButton.setSize(new Dimension(100, 50));
bpmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
buttonPressed++;
if (buttonPressed == 1) {
counter[0] = (int)(System.currentTimeMillis());
} else if (buttonPressed == 2) {
counter[1] = (int)(System.currentTimeMillis());
calculateTimeBetweenClicks();
setTime();
} //Removed the else - see edit below :-)
}
});
Additional
Your code as-is seems to get a litle confused after the 2nd click (the first BPM calculation) as it seems to take that 2nd click as the first click of the next set of 2 clicks if you get what I mean. I'm not sure if this is intended behaviour, but if not, I would reset everything in the calculateTimeBetweenClicks method after you've calculated the correct bpm ready for a new set of 2 clicks...
// Calculates the difference between the two saved clicks
public void calculateTimeBetweenClicks() {
if (buttonPressed == 1) {
time1 = counter[0];
} else {
time1 = counter[0];
time2 = counter[1];
//Reset here ready for next 2 clicks...
counter[0]=0;
counter[1]=0;
buttonPressed = 0;
}
time3 = time2 - time1;
}
I want to use a Timer in a while loop. That is, I want to run the body of a while loop multiple times when it includes a timer within it. However, whenever I do this, the body of the while loop seems to execute and increment before the timer has fired the required amount of times. It is supposed to fire 15 times before the while loop increments, but it seems to be running through the while loop immediately before the timer fires the required amount of times, which I do not understand.
I know it isn't a problem with anything else because when I just run the code through once (i.e., without a while loop), it runs fine. The idea is that a JLabel is supposed to be removed and replaced every 1300ms until 15 images are displayed. Once it displays the 15 images, it moves onto the next row of the 2D array, of which there are 60 rows in total.
Any help would be appreciated. I have put the code below.
public class Game implements KeyListener, ActionListener{
private Preparation prep;
private Window window;
private JLabel earthLabel;
private JPanel panel;
private Timer timer;
private JLabel[] arrayOfAllSpaceshipsLabels;
private int[] arrayOfAllSpaceshipsIndexes;
private JLabel currentShipLabel;
private int numberOfBlocks;
private int firings;
private int[][] blocks = new int[60][15] //the values in this array have been initalized in another class that is too big and not relevant to my problem
public Game(){
window = new Window("Space Game");
runBlock();
}
private void runBlock() {
int blocksLength = blocks.length;
numberOfBlocks = 0;
while(numberOfBlocks < blocksLength){
firings = 0;
timer = new Timer(1333, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (firings == 15){
panel.removeAll();
panel.revalidate();
panel.repaint();
timer.stop();
System.out.println("Block finished");
return;
}
panel.removeAll(); /*(currentShipLabel);*/
panel.revalidate();
panel.repaint();
currentShipLabel = arrayOfAllSpaceshipsLabels[blocks[numberOfBlocks][firings]];
panel.add(currentShipLabel);
panel.validate();
firings++;
}
});
timer.start();
}
numberOfBlocks++;
}
}
public class Window extends JFrame{
private JPanel panel;
public Window(String title){
SwingUtilities.isEventDispatchThread();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//this.setBackground(Color.BLACK);
panel = new JPanel();
this.add(panel);
this.pack();
this.setSize(500,500); //my edit
panel.setBackground(Color.BLACK);
this.setVisible(true);
}
public JPanel getPanel() {
// TODO Auto-generated method stub
return panel;
}
}
As you have noticed, creating and starting a Timer does not prevent your loop from continuing.
To solve your problem you have to "move" your while loop into the timer action:
private void runBlock() {
int blocksLength = blocks.length;
numberOfBlocks = 0;
timer = new Timer(1333, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (firings == 15){
if (numberOfBlocks == blocksLength)
panel.removeAll();
panel.revalidate();
panel.repaint();
timer.stop();
System.out.println("Block finished");
return;
} else {
firings = 0;
numberOfBlocks++;
}
}
panel.removeAll(); /*(currentShipLabel);*/
panel.revalidate();
panel.repaint();
currentShipLabel = arrayOfAllSpaceshipsLabels[blocks[numberOfBlocks][firings]];
panel.add(currentShipLabel);
panel.revalidate();
firings++;
}
});
timer.start();
}
I need a timer implemented in my application, which will do a countdown from 10 sec - 0 sec.
and, display the countdown in a JLabel.
Here's my implementation;
...
Timer t = new Timer(1000, new List());
t.start();
}
class List implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
int sec = 0;
label.setText(""+sec);
// Do a if- condition check to see if the clock has reached to, and then stop
}
}
I was expecting the JLabel to start counting from 0 - 10 and then stop. But it doesn't. The JLabel set the value 0 and it doesn't get incremented.
UPDATE 1
t = new Timer(1000, new Listner());
t.start();
}
class Listner implements ActionListener{
private int counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
lable.setText(""+ (counter++));
if (counter == 10)
t.removeActionListener(this);
}
}
You are not storing nor incrementing secs anywhere so I don't see how it should get updated, try with
Timer timer;
void start() {
timer = new Timer(1000,new List());
}
class List implements ActionListener {
private counter = 0;
#Override
public void actionPerformed(ActionEvent e) {
label.setText(""+counter++);
if (counter == 10)
timer.removeActionListener(this);
}
}
Mind that you need to store a reference to the timer somewhere to be able to remove the listener from it once countdown finished.
Well each time the timer is called it declares the int variable sec to 0. Hence the Label doesnt get updated.
You should declare the sec variable as a global variable and then in the actionPerformed method increment its value each time it is called.
public int sec = 0;
class List implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
sec++;
label.setText(""+sec);
// Do a if- condition check to see if the clock has reached to, and then stop
}
}
A complete example
public class ATimerExample {
Timer timer;
int counter = 0;
public ATimerExample() {
final JFrame frame = new JFrame("somethgi");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JLabel label = new JLabel("0");
JPanel panel = new JPanel();
panel.add(label, BorderLayout.SOUTH);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText(String.valueOf(counter));
counter++;
if (counter == 10) {
//timer.removeActionListener(this);
timer.stop();
}
}
});
timer.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ATimerExample();
}
});
}
}
Since java reads the time in milliseconds, it should be 10000 instead of 1000. try your code and see if that works. I had the same problem when I wanted 30 seconds. And instead of writing Timer t = new Timer(30000, new List()); t.start();
I wrote Timer t = new Timer(3000, new List());
t.start();
That made my program to stop every after 3 seconds. I would suggest, you use 10000 instead of 1000.
Remember to do: t.stop() in your List class. Thanks
I'm wanting to create a stopwatch so to speak in order to score my game. Lets say I have a variable: int sec = 0. When the game starts I want a g.drawString to draw the time to the applet. So for example each second, sec will increment by 1.
How do I go about making it g.drawString(Integer.toString(sec), 40, 400) increment by 1 and draw each second?
Thanks.
EDIT:
I've figured out how to increment it and print it to the screen by using ActionListener and putting g.drawString in there but it prints ontop of each other. If I put g.drawString into the paint method and only increment sec by 1 in the ActionListener there is a a flicker. Should I use Double Buffering? If so how do I go about doing this?
import java.awt.event.*;
import javax.swing.*;
public class StopWatch extends JLabel
implements MouseListener, ActionListener {
private long startTime; // Start time of stopwatch.
// (Time is measured in milliseconds.)
private boolean running; // True when the stopwatch is running.
private Timer timer; // A timer that will generate events
// while the stopwatch is running
public StopWatch() {
// Constructor.
super(" Click to start timer. ", JLabel.CENTER);
addMouseListener(this);
}
public void actionPerformed(ActionEvent evt) {
// This will be called when an event from the
// timer is received. It just sets the stopwatch
// to show the amount of time that it has been running.
// Time is rounded down to the nearest second.
long time = (System.currentTimeMillis() - startTime) / 1000;
setText("Running: " + time + " seconds");
}
public void mousePressed(MouseEvent evt) {
// React when user presses the mouse by
// starting or stopping the stopwatch. Also start
// or stop the timer.
if (running == false) {
// Record the time and start the stopwatch.
running = true;
startTime = evt.getWhen(); // Time when mouse was clicked.
setText("Running: 0 seconds");
if (timer == null) {
timer = new Timer(100,this);
timer.start();
}
else
timer.restart();
}
else {
// Stop the stopwatch. Compute the elapsed time since the
// stopwatch was started and display it.
timer.stop();
running = false;
long endTime = evt.getWhen();
double seconds = (endTime - startTime) / 1000.0;
setText("Time: " + seconds + " sec.");
}
}
public void mouseReleased(MouseEvent evt) { }
public void mouseClicked(MouseEvent evt) { }
public void mouseEntered(MouseEvent evt) { }
public void mouseExited(MouseEvent evt) { }
} // end StopWatchRunner
A small applet to test the component:
/*
A trivial applet that tests the StopWatchRunner component.
The applet just creates and shows a StopWatchRunner.
*/
import java.awt.*;
import javax.swing.*;
public class Test1 extends JApplet {
public void init() {
StopWatch watch = new StopWatch();
watch.setFont( new Font("SansSerif", Font.BOLD, 24) );
watch.setBackground(Color.white);
watch.setForeground( new Color(180,0,0) );
watch.setOpaque(true);
getContentPane().add(watch, BorderLayout.CENTER);
}
}