I'm not that good with Java Swing and I'm trying to use a timer start the game with a delay in 3 seconds
But at the same time I want to show a dialog (also the game has to wait 3 seconds so the focus needs to be on the dialog)
So my dialog is as follow: got this sample code
So in my gameplay panel I do this:
public class GamePlayPanel extends JPanel implements ActionListener {
// attributes
private JOptionCountDownTimer countDownDialog;
public GamePlayPanel(MainWindow mainWindow) {
// initialization attributes
initLayoutPanel();
this.timer = new Timer(DELAY, this);
// Added a delay of 3 seconds so you can prepare to for the game
this.timer.setInitialDelay(3000);
resetTime();
}
public void startGame() {
this.gamePanel.requestFocus();
this.countDownDialog.startCountDown();
startTimer(); // this is my game timer to record the game time
}
public void restartGame() {
this.countDownDialog.resetCountDown();
startTimer();
this.gamePanel.requestFocus();
}
}
It works fine but if I restart the game the count down timer starts at 0 -> 2 seconds.
Also any better ideas on my class JOptionCountDownTimer? I tried to make it extend a JDialog class but I couldn't get it to work.
Try this out, see if it works for you. You can just grab the dialog class code. All you need to do is pass to it the parent frame, true for modality and seconds you want. You also may want to pretty it up. I'm just providing the functionality
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public class CountDownTimer {
public CountDownTimer() {
final JFrame frame = new JFrame();
JButton button = new JButton("Open Dilaog");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
new CountDownTimerDialog(frame, true, 5);
}
});
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private class CountDownTimerDialog extends JDialog {
private int count;
public CountDownTimerDialog(JFrame parent, boolean modal, int seconds) {
super(parent, modal);
count = seconds;
final JLabel countLabel = new JLabel(String.valueOf(seconds), JLabel.CENTER);
countLabel.setFont(new Font("impact", Font.PLAIN, 36));
JLabel message = new JLabel("Wait to Start Game");
message.setFont(new Font("verdana", Font.BOLD, 20));
JPanel wrapper = new JPanel(new BorderLayout());
wrapper.setBorder(new EmptyBorder(10, 10, 10, 10));
wrapper.add(countLabel);
wrapper.add(message, BorderLayout.SOUTH);
add(wrapper);
Timer timer = new Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (count == -1) {
dispose();
} else {
countLabel.setText(String.valueOf(count));
count--;
}
}
});
timer.setInitialDelay(0);
timer.start();
pack();
setLocationRelativeTo(parent);
setVisible(true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new CountDownTimer();
}
});
}
}
Related
I am creating a Java program using Swing and want to open a JFrame, run a for-loop that stores items in a list of Strings, display graphics while that is happening, and only after that is done call another method. The issue is that even though I call frame.setVisible(true); before running the loop, it only displays after the loop is done. I would use a SwingWorker but I need to stop the main thread from running the next method until after the loop is finished. If someone knows a way to use SwingWorker or knows a fix to this, that would be great. Here is the code I am referring to:
//The JPanel in charge of displaying graphics while the loop is running
FrameRenderer renderer = new FrameRenderer(videoFile, this.getWidth(), this.getHeight());
this.add(renderer);
this.setVisible(true);
//Call the method with the for-loop after this.setVisible is called
List<String> frames = renderer.renderFrames();
//I need this to run after the loop is finished
DisplayFrames display = new DisplayFrames(frames, this.getWidth(), this.getHeight(), this);
this.add(display);
SwingWorker
Worker Threads and SwingWorker
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.border.EmptyBorder;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private JLabel label = new JLabel("...");
public MainPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(32, 64, 32, 64));
add(label);
SwingWorker<Void, String> worker = new SwingWorker<>() {
#Override
protected Void doInBackground() throws Exception {
for (int index = 0; index < 1000; index++) {
publish(Integer.toString(index));
// It's important, if you want to allow the UI to
// update on a single view, you need to allow time
// for this thread to sleep, otherwise, you could
// end up in a siutatio where the only update you
// get is the last one (with a list of all the
// the values you "published"
Thread.sleep(10);
}
return null;
}
#Override
protected void process(List<String> chunks) {
label.setText(chunks.get(chunks.size() - 1));
}
};
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (worker.getState() == SwingWorker.StateValue.DONE) {
label.setText("All done here");
}
}
});
worker.execute();
}
}
}
Swing Timer
How to Use Swing Timers
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
private JLabel label = new JLabel("...");
public MainPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(32, 64, 32, 64));
add(label);
Timer timer = new Timer(10, new ActionListener() {
private int value = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (value >= 1000) {
((Timer)(e.getSource())).stop();
label.setText("All done here");
}
label.setText(Integer.toString(value));
value++;
}
});
timer.start();
}
}
}
i'm new to Java and I'm trying to add a time delay when I press a Jbutton start. I used TimeUnit.SECONDS.sleep() but it didn't work, then i researched and found out about java swing timer, but it didn't work either and I can't figure out why
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("start DONE");
Object step;
for (int i = 1; i < n; i++) {
//code that shows on interface
// then i want a delay here then to carry on with the iteration of for
timer.start();
};
}
});
}
});
You're almost there. But you seem to be misunderstanding what the Timer is actually doing for you.
The Timer is acting as a kind of pseudo loop, with a built in delay. That is, after each time period, it will execute. This means, that each time your ActionListener is triggered, you want to execute the next step in your logic.
For example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.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 JPanel contentPane = new JPanel(new GridBagLayout());
public TestPane() {
setLayout(new BorderLayout());
add(new JScrollPane(contentPane));
JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
private int row = 0;
private int count = 1000;
private DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
#Override
public void actionPerformed(ActionEvent e) {
row = 0;
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
gbc.weightx = 1;
contentPane.removeAll();
contentPane.revalidate();
contentPane.repaint();
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
row++;
if (row >= count) {
((Timer)(e.getSource())).stop();
return;
}
JLabel label = new JLabel(LocalDateTime.now().format(formatter));
contentPane.add(label, gbc);
contentPane.revalidate();
contentPane.repaint();
// This is only required because the layout pass seems
// to be execute in different run cycle, so the label's
// bounds are not been updated yet. We force the layout
// pass so we can scroll to the label, but otherwise
// isn't needed
contentPane.doLayout();
Rectangle bounds = label.getBounds();
bounds.y += bounds.height;
contentPane.scrollRectToVisible(bounds);
}
});
timer.start();
}
});
add(startButton, BorderLayout.NORTH);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
I am trying to program a Rubiks cube timer. Once you click space I want the timer to countdown from 15 seconds, once the 15 seconds is over, start counting up from 0. When you are done solving the cube you click space again, stopping the timer (I want the timer to count to the nearest hundredth). Here is what I have now:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class CubeMain extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
CubeMain frame = new CubeMain();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public CubeMain() {
setTitle("Cube Timer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 600, 490);
contentPane = new JPanel();
final JLabel Timerlbl = new JLabel("");
Timerlbl.setBounds(269, 219, 46, 14);
contentPane.add(Timerlbl);
addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
Timerlbl.setText("Label Change");
}
});
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
}
}
So you know you need some kind of timer. The timer you want for a Swing program is a javax.swing.Timer. This is the basic constructor
Timer(int delay, ActionListener listener);
Where, delay is the delay time between fired actions, and the listener is what listens for those timer action events being fired each interval. A basic implementation would me something like this
public TimerPanel() {
Timer timer = new Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do something
}
});
timer.start();
}
What you could do is have a count variable that you increment and use to set the timerLabel. Then just set your key binding for the SPACE to timer.start() or timer.stop()
Take a look at this, it has the timer. It's pretty much what you need
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public class TimerPanel{
double count = 15.00;
boolean reverse = true;
boolean started = false;
private JLabel timerLabel = new JLabel(String.format("%.2f", count));
private Timer timer;
public TimerPanel() {
timerLabel.setHorizontalAlignment(JLabel.CENTER);
timerLabel.setBorder(new EmptyBorder(20, 20, 20, 20));
JFrame frame = new JFrame();
frame.add(timerLabel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(10, new ActionListener(){
public void actionPerformed(ActionEvent e) {
if (reverse && count > 0) {
count -= 0.01;
timerLabel.setText(String.format("%.2f", count));
if (count <= 0) {
reverse = false;
}
}
if (!reverse){
count += 0.01;
timerLabel.setText(String.format("%.2f", count));
}
}
});
Action spaceAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
if (!started) {
timer.start();
started = true;
} else {
timer.stop();
count = 15.00;
started = false;
reverse = true;
}
}
};
InputMap inputMap = timerLabel.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = timerLabel.getActionMap();
inputMap.put(KeyStroke.getKeyStroke("SPACE"), "spaceAction");
actionMap.put("spaceAction", spaceAction);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new TimerPanel();
}
});
}
}
I'm writing a game and need a 60 second countdown. I would like it to start counting down when I click the "Start" button. I can get it to countdown manually right now, but need it to do so automatically.
This is a Java Applet, not Javascript.
Is there a way I can have this timer go in the background while I use other buttons? I'm using JLabels and JButtons. Can I have two ActionListeners running at the same time?
Use javax.swing.Timer
Run this example. You will see that you can still perform other actions while the time is running. Click the yes or no button, while the time is going
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test extends JApplet {
private JLabel label1 = new JLabel("60");
private JLabel label2 = new JLabel("Yes");
private JButton jbt1 = new JButton("Yes");
private JButton jbt2 = new JButton("No");
private int count = 60;
private Timer timer;
public Test() {
JPanel panel1 = new JPanel(new GridLayout(1, 2));
panel1.add(label1);
panel1.add(label2);
label1.setHorizontalAlignment(JLabel.CENTER);
label2.setHorizontalAlignment(JLabel.CENTER);
JPanel panel2 = new JPanel();
panel2.add(jbt1);
panel2.add(jbt2);
add(panel1, BorderLayout.CENTER);
add(panel2, BorderLayout.SOUTH);
timer = new Timer(1000, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
count--;
if (count == 0) timer.stop();
label1.setText(String.valueOf(count));
}
});
timer.start();
jbt1.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
label2.setText("Yes");
}
});
jbt2.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
label2.setText("No");
}
});
}
}
I wanted to know if there's any easy way to delete the content (text) from a JLabel after 5 seconds. Is that possible? Because I have a JLabel in a JFrame and it shows some internal errors from the program I'm coding and I want the JLabel to show the message for a couple of seconds and then go to blank. Any ideas?
Simplest solution is to use a Swing Timer. It will prevent freezing the GUI and ensure proper Thread access (ie, UI modification is performed on the EDT).
Small demo example:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestLabelDelete {
private JFrame frame;
private JLabel label;
protected void initUI() {
frame = new JFrame(TestLabelDelete.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label = new JLabel("Some text to delete in 5 seconds");
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer t = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText(null);
}
});
t.setRepeats(false);
t.start();
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestLabelDelete testLogin = new TestLabelDelete();
testLogin.initUI();
}
});
}
}
Use Timer. Please see my example.
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.Timer;
public class SourceCodeProgram {
private static void createAndShowGUI() {
// Make sure we have nice window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
// Create and set up the window.
JFrame frame = new JFrame("HelloWorldSwing");
frame.setMinimumSize(new Dimension(200, 300));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add the ubiquitous "Hello World" label.
final JLabel label = new JLabel("Hello World");
frame.getContentPane().add(label);
// Display the window.
frame.pack();
frame.setVisible(true);
Timer timer = new Timer(5000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Clear text or whatever you want
label.setText("New text");
}
});
// start Tick-Tack
timer.start();
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Or you can write a separate class, which can clean label.
class JLabelCleaner {
private JLabel label;
private int waitSeconds;
public JLabelCleaner(int waitSeconds, JLabel label) {
this.label = label;
this.waitSeconds = waitSeconds;
}
public void startCountdownFromNow() {
Timer timer = new Timer(waitSeconds * 1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText("");
}
});
timer.start();
}
}
Now, you can use it whenever you need it in this way:
new JLabelCleaner(5, label).startCountdownFromNow();
Also see:
How to Use Swing Timers
There is an easy solution to this.
JLabel label = new JLabel("error text");
Thread.sleep(5000);
label.setText("");
Hope this helps!
EDIT: If you don't want the program to freeze for 5 secs you'll have to put this inside a Runnable.
It's very easy to do... just create a new thread and write code to clear text on label, and make that thread to sleep for 5sec and then start it.
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class LabelThread {
private JLabel textLabel;
public LabelThread() {
try {
JFrame frame = new JFrame("Label");
frame.setSize(500, 500);
textLabel = new JLabel("Hiiii.... Kill me");
frame.setContentPane(textLabel);
frame.setVisible(true);
MyThread thread = new MyThread();
MyThread.sleep(5000);
thread.start();
} catch (InterruptedException ex) {
}
}
class MyThread extends Thread{
#Override
public void run() {
System.out.print("Running thread");
textLabel.setText("");
}
}
public static void main(String args[]){
LabelThread labelThread = new LabelThread();
}
}