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");
}
});
}
}
Related
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 have this class and I want to switch focus to the Game class right after it was invoked. I might've not understand the purpose of focus but when I press start I have to click on the game canvas itself so I can use the keyboard . In other words: How can I make it so I don't have to click on it to use the keyboard?
package com.runner.panels;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import com.runner.main.Game;
import com.runner.main.Main;
public class PlayPanel extends JPanel{
private static final long serialVersionUID = 1L;
public PlayPanel(){
//setting the layout of the playpanel to null
setLayout(null);
//setting up the info panel : high score, meters ran, pause button etc...
JPanel info = new JPanel();
info.setBounds(0,0,1200,50);
add(info);
//back button
JButton back = new JButton("Back");
info.add(back);
Game game = new Game();
game.setBounds(0,50,1200,521);
game.setBackground(Color.black);
add(game);
back.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) Main.mainp.getLayout();
cl.show(Main.mainp, "Menu");
}
});
}
}
Off topic: (kinda)
The fact that you are doing Main.mainp.getLayout();, calling the panel statically tells me you have poor design and should be looking into other options like an Model-view-controller pattern, an Observer pattern, or at the very least passing a reference of of the Main to the panel, instead of using static objects/calls.
Back on topic
Sounds like a common KeyListener problem. Generally to gain focus you call requestFocusInWindow(). But you still have to worry about other components stealing the focus way after the fact.
I would instead recommend using Key Bindings instead of KeyListener. You have more control over the focus. For instance, by using
InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("SPACE"), "hitSpace");
panel.getActionMap().put("hitSpace", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
// do something.
}
});
The panel will have immediate access to the action once you show it from the CardLayout. If you happen to use any other components that would steal the focus away from the panel, the action is still accessible because of the WHEN_IN_FOCUSED_WINDOW input map
Here's a simple example. Type A if it is on panel A, you will see it print. If you type B, it won't print because panel A is in the window. Also if you try and press the button in the panel to steal the focus, you can still type and it will still print. Same goes for panel B
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Main {
CardLayout layout = new CardLayout();
JPanel panel = new JPanel(layout);
JPanel p1 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
JPanel p2 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
JButton b1 = new JButton("panelA");
JButton b2 = new JButton("panelB");
public Main() {
addKeyBind(p1, "pressA", "A");
addKeyBind(p2, "pressB", "B");
p1.add(new JButton("Button for Panel A"));
p2.add(new JButton("Button for Panel B"));
panel.add(p1, "panelA");
panel.add(p2, "panelB");
b1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
show("panelA");
}
});
b2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
show("panelB");
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(b1);
buttonPanel.add(b2);
JFrame frame = new JFrame();
frame.add(panel);
frame.add(buttonPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void show(String panelName) {
layout.show(panel, panelName);
}
private void addKeyBind(JComponent comp, String name, final String stroke) {
InputMap im = comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(stroke), name);
comp.getActionMap().put(name, new AbstractAction(){
public void actionPerformed(ActionEvent e) {
System.out.println(stroke + " pressed");
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Main();
}
});
}
}
Take some time to go over the link I gave you for Key Bindings to learn more.
Back off-topic
Take a look at #AndrewThompson's comment about the null layouts. Learn how to use the LayoutManagers
I believe your problem would be fixed if you add
setFocusable(true);
to your PlayPanel constructor (works for me).
Also, if you want a specific Panel in your GUI to have focus when you start your application, follow the link in the comment of "user3218114", as this will explain how to implement this functionality with Listeners.
Good luck!
You don't need to do anything. The container should be focusable for that.
Here is a code to demonstrate.
package one;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
public class PlayPanel extends Canvas {
public static void main(String... args) {
PlayPanel p = new PlayPanel();
p.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
p.msg = "Focus gained";
p.repaint();
}
#Override
public void focusLost(FocusEvent e) {
p.msg = "Focus Lost";
p.repaint();
}
});
p.setBackground(Color.GRAY);
JFrame f = new JFrame();
f.add(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 200);
f.setLocation(300, 300);
f.setVisible(true);
}
String msg = "NO FOCUS";
public void paint(Graphics g) {
g.drawString(msg, 50, 50);
}
}
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();
}
});
}
}
My question is similar to this one: JTable Cell Update doesn't work.
However, I am using JDialog instead of a JTable specified in above link. I have a custom class which extends JDialog. I use JEditorPane as a text-component in that dialog and create simple OK, Cancel buttons. Now the problem is, when I enter something in the JEdiorPane and presses OK button, the value is not applied to the text-component until I move the focus out of a JDialog or hit tab/ENTER.
I want the container to be notified that I am done with editing as soon as I press the OK button. In short I want to explicitly have a feature similar to stopCellEditing(). How can I do that?
See this example which seems to work correctly and does the same thing as you described:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TestEditorPaneDialog {
public void init() {
final JFrame frame = new JFrame();
JButton clickMe = new JButton("Click me");
clickMe.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
showDialog(frame);
}
});
frame.add(clickMe);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
showDialog(frame);
}
private void showDialog(final JFrame frame) {
final JDialog dialog = new JDialog(frame, true);
final JEditorPane pane = new JEditorPane();
pane.setText("Type something here");
JPanel south = new JPanel();
JPanel buttons = new JPanel(new GridLayout(1, 0, 10, 10));
JButton ok = new JButton("OK");
ok.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
JOptionPane.showMessageDialog(frame, "You have typed in: " + pane.getText());
}
});
JButton cancel = new JButton("Cancel");
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
buttons.add(ok);
buttons.add(cancel);
south.add(buttons);
dialog.add(new JScrollPane(pane));
dialog.add(south, BorderLayout.SOUTH);
dialog.setSize(250, 150);
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestEditorPaneDialog().init();
}
});
}
}
Im learning about Java Swing components and I want to do that when I push button, Java Swing would add label from another class into JFrame screen. Its just simple example for start.
I want to learn how to use and add swing components from another class.
There can be some stupid mistakes, but dont judge me, im new ^^
Frame class add button
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Frame extends JFrame{
private JButton btn;
private boolean regCompl = false;
public Frame(){
super("The title Macas");
setLayout(new FlowLayout());
btn = new JButton("Push for Registration");
btn.addActionListener(
new ActionListener(){
#Override
public void actionPerformed(ActionEvent event) {
regCompl = true;
}
}
);
add(btn);
if(regCompl == true){
RegComplete regObj = new RegComplete(this);
}
}// end of constructor
}
RegComplete Class add label to screen after button are pressed.
import javax.swing.JButton;
import javax.swing.JLabel;
public class RegComplete {
Frame frame;
private JLabel label;
public RegComplete(Frame fm){
this.frame = fm;
label = new JLabel("Hello world Mac4s");
fm.add(label);
}
}
You have to create Object inside the action Listener
btn = new JButton("Push for Registration");
btn.addActionListener(
new ActionListener(){
#Override
public void actionPerformed(ActionEvent event) {
RegComplete regObj = new RegComplete(Frame.this);
}
}
);