below in the sample code which i wrote where the user gets an interface with 2 buttons. when the user click on start button the timer starts and when the end button is clicked the timer stops and the difference in time is displayed.
But the difference in time is not being output:(
can someone help mi.
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
public class Timer2 extends JFrame {
private JButton start;
private JButton end;
public Timer2() {
super("Test Timer");
setLayout(new FlowLayout());
start = new JButton("START");
add(start);
end = new JButton("END");
add(end);
ButtonHandler handler = new ButtonHandler();
start.addActionListener(handler);
end.addActionListener(handler);
}
private class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
long s_time = 0;
long e_time = 0;
long diff = 0;
String name = ((JButton) event.getSource()).getText();
if (name.equals("start")) {
s_time = System.currentTimeMillis();
} else {
e_time = System.currentTimeMillis();
}
diff = (e_time - s_time) / 1000;
JOptionPane.showMessageDialog(null, diff);
}
}
public static void main(String[] args) {
Timer2 timer2 = new Timer2();
timer2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
timer2.setSize(200, 200);
timer2.setVisible(true);
}
}
You've given your buttons text in UPPER CASE but then are looking for lower case in your event handler.
You also are setting both s_time and e_time to 0 inside the actionPerformed() method which means they are set to 0 every time you click. These both need to be fields in the ButtonHandler class.
In addition, the way you have it written, the JOptionPane.showMessageDialog() will be fired when you click either button.
Edit: To solve the last problem, move your diff calculation and JOptionPane.showMessageDialog() call to inside the else block it follows; you only want it when the "end" button is pressed.
I'm assuming you want to display the result only when the user clicks "End". The way you've written it, the dialog will be displayed either way. To resolve this, move the JOptionPane.showMessageDialog(null, diff) inside the else block.
Another thing, as #Brian Roach so helpfully explains, computers are very case sensitive (e.g. "THUS" does not equal "thus"). So, make sure you're referring to the correct item.
Related
I am working on creating a small program to recreate a game. So far I have created a small GUI. My question is when I created an action listener to update the variable counterNum which then updates cookieCountLabel the screen does not update it only says one. I thought that if the button is clicked counterNum should equal counterNum + 1. And then it should have updated cookieCountLabel, but this didn't seem to work.
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JComponent;
import java.awt.Graphics;
import java.awt.Canvas;
import java.awt.FlowLayout;
import javax.swing.SwingUtilities;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
*Author:Graham
*Lang:Java
*Program: Cookie Clicker
*Date Created: 6/22/2019
*CITATION:
*Some GUI concepts from(the pdf you provided):https://lms.dist113.org/attachment/907907595/docviewer
*Some GUI concepts from https://www.guru99.com/java-swing-gui.html
*/
public class Clicker extends JComponent
{
public static void main(String[] args){
//variables
//frame
JFrame frame = new JFrame("Cookie Clicker");
frame.setLocationRelativeTo(null);
frame.setSize(300,300);
frame.setResizable(true);
frame.setLayout(null);
//close on click x
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//buttons
JButton cookie = new JButton("Cookie");
cookie.setBounds(80,0, 140, 20);
//to set visible
frame.setVisible(true);
frame.add(cookie);
//listen for click
cookie.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
Integer counterNum = 0;
counterNum += 1;
String convert = counterNum.toString();
JLabel cookieCountLabel = new JLabel();
cookieCountLabel.setBounds(140,120,50,20);
cookieCountLabel.setText(convert);
frame.add(cookieCountLabel);
}
});
}
}
First of all, you are setting your counterNum to 0 every time you click the button. Therefore, your counterNum value will always show as 1:
cookie.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
Integer counterNum = 0; !!! -> error here
counterNum += 1;
To fix this, take out your counterNum variable out of the main method and make it a field.
public class Clicker extends JComponent
{
private static int counterNum; !!!
public static void main(String[] args){
...
Next, every time you press the button, you create a new Label which holds the value of the counterNum. As suggested in the comments, you probably don't want to create a new Label object every time you press the button, but rather you want to change the value that is written on the Label. Therefore, take out your Label creation code from the ActionListener and put it in your main method. Now you will only have 1 Label that holds the value of counterNum.
public static void main(String[] args){
JLabel cookieCountLabel = new JLabel(); !!!
cookieCountLabel.setBounds(140,120,50,20); !!!
//frame
JFrame frame = new JFrame("Cookie Clicker");
frame.setLocationRelativeTo(null);
Now, whenever you press the button, no new Label is created, but the value of counterNum is changed and incremented by 1. This is how your ActionListener should look like now:
cookie.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
counterNum += 1; //increment counterNum by 1
String convert = counterNum + ""; //convert to String
cookieCountLabel.setText(convert);
frame.add(cookieCountLabel);
}
I've recently made a small puzzle game that deals with clicking certain areas. I also made a solver which activates the necessary areas to win. The problem that I am facing is that I would like to pause each time it activates an area to create a sort of "solving animation". My problem is represented here
package experiment;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ExperimentHere extends JFrame implements ActionListener
{
private static final long serialVersionUID = 1L;
private JButton changeLabelButton;
private JPanel mainPanel;
private JLabel labelToChange;
public ExperimentHere() {
changeLabelButton = new JButton("Set the label");
changeLabelButton.addActionListener(this);
mainPanel = new JPanel();
labelToChange = new JLabel();
labelToChange.setText("This needs to be changed");
mainPanel.add(labelToChange);
mainPanel.add(changeLabelButton);
this.add(mainPanel);
setTitle("Timer Program");
setContentPane(mainPanel);
setPreferredSize(new Dimension(1000, 1000));
pack();
}
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(changeLabelButton)){
changeLabel();
}
}
public void changeLabel(){
for (int i = 0; i<5; i++){
labelToChange.setText(""+i);
// Pause for 200ms here
}
}
public static void main(String[] args){
ExperimentHere test = new ExperimentHere();
test.setVisible(true);
}
}
I have tried using Timers, but I'm not sure how to format it properly so that it only pauses each time the loop inside of changeLabel() is incremented, because the second paramter in Timer() asks for an ActionListener.
I've also tried using Thread.sleep() but it just freezes my program and then instantly solves it.
Ideally the changeLabel method would increment by 1, set the label to the new String, wait for 200ms, and then increment again.
I have tried using Timers, but I'm not sure how to format it properly so that it only pauses each time the loop inside of changeLabel() is incremented
When you use a Timer you don't use a loop. The point of a Timer is that you start the Timer and it keeps executing until you stop the Timer.
You also don't make methods, you make an Action to invoke whenever the Timer fires.
So you need an instance variable in your class that keeps track of the number of times the Timer has fired (lets call it "timerCounter"). Then you need to create an Action to invoke every time the Timer is fired.
So you create a couple of instance variables:
int timerCounter = 0;
Action action;
Then in the constructor of your class you create an Action something like:
action = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
labelToChange.setText("" + timerCounter);
timerCounter++;
if (timerCounter > 5)
{
Timer timer = (Timer)e.getSource();
timer.stop();
}
}
}
So now in the ActionListenerof your button you can do something like:
timerCounter = 0;
Timer timer = new Timer(200, action);
timer.start();
This question already has answers here:
How could I add a simple delay in a Java Swing application?
(3 answers)
Closed 6 years ago.
i'm making a poker game for a uni assignment and i was wondering if there is any way to have a method that does as follows ( Note: very roughly written up code )
JTextArea textArea = new JTextArea();
public void printer(String s){
//I want to delay here, for 2 seconds each time i print to the jtextarea
textArea.append(s);
}
public void runGame(){
printer("Dealing cards...");
//I want to delay to add to an effect of the time it takes to actually deal the cards
pokerHand.setVisibility(true);
printer("What you like to do?");
//
//Code here containing running the game
//
printer("Daniel Negreanu folds");
//I want to have a delay here for the time it takes to make a decision.
printer("Phil Hellmuth folds");
Theres many many more instances i want to use this throughout my program, and just wondered if there is any way to do this.
Thanks in advance
EDIT: Not looking to use Thread.sleep() as it doesn't work well with gui.
EDIT2: I want the pokerHand.setVisibility(true), and other methods in my code to execute AFTER the delay, ( using a timer doesn't do this ).
Not looking to use Thread.sleep() as it doesn't work well with gui.
Good, use a Swing Timer instead
I want the pokerHand.setVisibility(true), and other methods in my code to execute AFTER the delay, ( using a timer doesn't do this ).
Yes it does, you're just not using it properly, but since you've not provided any actual code, I can't say "how" you're not using it properly, only from the sounds of it, you are.
Start by taking a look at How to use Swing Timers for more details
The following is very simple example, it uses a Timer to calculate and print the amount of time between the time you clicked the button.
The example updates the UI AFTER the Timer is started, but until the Timer completes, the calculation and result are not generated
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalTime;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
private JButton btn;
private Timer timer;
private LocalTime startTime, endTime;
public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(10, 20);
add(new JScrollPane(ta));
btn = new JButton("Click");
add(btn, BorderLayout.SOUTH);
timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
endTime = LocalTime.now();
Duration duration = Duration.between(startTime, endTime);
ta.append("Ended # " + endTime + "\n");
ta.append("Took " + (duration.toMillis() / 1000) + " seconds\n");
}
});
timer.setRepeats(false);
ta.setEditable(false);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
timer.start();
startTime = LocalTime.now();
btn.setEnabled(false);
ta.append("Start # " + startTime + "\n");
}
});
}
}
}
First, your code seems to be imperative ("ask user what to do", "game loop goes here") instead of event-driven ("when this happens, do that"). Read up on event-driven programming, which is used on all GUIs, sooner rather than later.
In event-driven code, there is no big difference between "user clicks a button" and "timeout expires" - both will cause events that your code can react to. So start by rewriting your code so that, once you press a button, the "next thing" happens. Then change it again so that once a timer expires, the same "next thing" happens.
Assuming that you have the following code:
// an ActionListener for both clicks and timer-expired events
private nextThingListener = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
doNextThing();
}
};
// method that does the next thing
public void doNextThing() {
// change the UI in some way
// if using timers, may also start the next timer
}
You can now associate it to a button using:
// create a button and have it do the "next thing" when clicked
JButton jb = new JButton("do next thing");
jb.addActionListener(nextThingListener);
myInterface.add(jb); // <-- display it in the interface somehow
And you can associate it to a timer as:
// launch a timer that will ring the nextThingListener every 2 seconds
new Timer(2000, nextThingListener).start();
If you want to have the timer ring only once, you can use
// launch a timer that will ring the nextThingListener after 2 seconds
Timer t = new Timer(2000, nextThingListener);
t.setRepeats(false);
t.start();
While trying to compile a 'Guess the Number' program in Netbeans the programme seems to keep on running but the programme is not executing. When the user clicks the 'Play' JButton the playGame method should run but nothing seems too happen and no exception is thrown.
Code is below.
Thanks
Ciaran
/*
* chpter 11 GUI programmong questions
* 11.15
*/
package Chapter11GUI;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.ActiveEvent;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.Icon;
import javax.swing.SwingConstants;
import java.util.Random;
public class GuessGame extends JFrame {
//instance varibles/files
private JLabel intro;
private JLabel highorlow;
private JButton play;
private JTextField enterAnswer;
private int answer1;
private int answer2;
private ImageIcon icon1;
private ImageIcon icon2;
private JPanel panel;
private Random numberGenerator;
private int correctAnswer;
//constructor willll create GUI o a JFrame and register event handlers
public GuessGame() {
super("GuessGAme");
setLayout(new BorderLayout());
Icon icon1 = new ImageIcon(getClass().getResource("bug1.gif"));
Icon icon2 = new ImageIcon(getClass().getResource("travelbug.gif"));
//JtextField to get user input
enterAnswer = new JTextField(5);
//enterAnswer.addActionListener(handler);
enterAnswer.setText("Guess");
enterAnswer.setEditable(false);
//JLabel to display heading
intro = new JLabel("Press Play to begin....", icon1, SwingConstants.CENTER);
highorlow = new JLabel();
//place componments on a panel useing flowlayout manager to hold text aea only
panel = new JPanel();
panel.add(enterAnswer);
panel.add(highorlow);
//JButton to play again and use anoumonus class to call gameMethod
play = new JButton("Play");
add(panel, BorderLayout.CENTER);
add(intro, BorderLayout.NORTH);
add(play, BorderLayout.SOUTH);
play.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//if button clicked then setart game
play.setText("Enjoy");
playGame();
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}//end actionPerfomred
});//end annmous class ActionListener call from addAcionlistener method
}//end construtor
//a method to play the game
public void playGame() {
//generate randown number bewteen 1 and 100
numberGenerator = new Random();
correctAnswer = numberGenerator.nextInt(100);
panel.setBackground(Color.magenta);
answer1 = 0;
answer2 = 0;
enterAnswer.setEditable(true);
enterAnswer.setText("");
while ((answer1 != correctAnswer) && (answer2 != correctAnswer)) {
intro.setText("I have a number bewteen 1 and a 100."
+ "Can you guess my number?");
enterAnswer.setEditable(true);
enterAnswer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == enterAnswer) {
answer1 = Integer.parseInt(enterAnswer.getText());
}
//set background as red as it is first guess
panel.setBackground(Color.red);
//noe set wether too high or two low
if (answer1 > correctAnswer) {
highorlow.setText("Guess Too High");
highorlow.setIcon(icon2);
} else if (answer1 < correctAnswer) {
highorlow.setText("You are gussing too low");
highorlow.setIcon(icon2);
}//end esle if statement
}//end actionPerfomred
});//end ActionListener
//get answer number 2
intro.setText("Try Again...");
enterAnswer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == enterAnswer) {
answer2 = Integer.parseInt(enterAnswer.getText());
}
//check if gettingb hot or cold
//2nd answer is closer than first so turn red
if ((Math.abs(answer2 - correctAnswer)) > (Math.abs(answer2 - correctAnswer))) {
panel.setBackground(Color.red);
} else {
panel.setBackground(Color.BLUE);
}
//now add too hihg ot tewo low
//noe set wether too high or two low
if (answer2 > correctAnswer) {
highorlow.setText("Guess Too High");
highorlow.setIcon(icon2);
} else if (answer2 < correctAnswer) {
highorlow.setText("You are gussing too low");
highorlow.setIcon(icon2);
}//end esle if statement
}//end actionPerformed
});//end ActionLIstener
}//end while loop when answer is correct
//what to do if answer is correct
panel.setBackground(Color.orange);
enterAnswer.setText("Correct!!");
enterAnswer.setEditable(false);
play.setText("PLay Again?");
}//end method playGame
}//end class
/*
*chapter 11
* porgramming question 11.14
*/
package Chapter11GUI;
import javax.swing.JFrame;
public class GuessGameTest {
public static void main(String[] args) {
// instanistae frame form GuessGAme
GuessGame frame = new GuessGame();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(350, 350);
}//end main
}//end clas test
Thanks. Have removed the while loop and programme is now running, but not as I intended. To troubleshoot I am using the netbeans debugger, the problem I have is I cannot seem to step into the playGame() method to see exactly what is going wrong. Have tried using step in (F7) at the anonymous ActionListener innerclass assoc with JButton to access playGame(), and also I have pointed the cursor at beginning of playGame and then Run To Cursor command. In both instances the debugger returns to the test application main class. Hope that made sense...
Have tried inserting a breakpoint at the playGame() but could not access. Could this be something to do with the playGame() method not been part of a java main class?? I can only seem to access the constructor of a class from a main class when the class in question is instaniated.....
Your program is in fact compiling and in fact appears to be running as well, but it looks like you're tying up the Swing event thread with a while (true) loop.
public void playGame() {
//generate randown number bewteen 1 and 100
numberGenerator = new Random();
// .... etc...
// ***** this will lock your GUI!! *******
while ((answer1 != correctAnswer) && (answer2 != correctAnswer)) {
intro.setText("I have a number bewteen 1 and a 100."
+ "Can you guess my number?");
// ....
}
}//end method playGame
When you do this, the while loop will continue running on the Swing event thread (or event dispatch thread or edt), preventing the edt from interacting with the user. This will cause the program to be completely non-responsive.
The solution, don't do this. Use event-driven programming code not linear console program code for your project. Have your program change it's behaviors based on the state of the answer1 and answer2 fields, but don't do this in a while loop. In other words, have the ActionListener's actionPerformed method behave differently depending on the state of these and other class fields. The Swing event loop will be all the game loop that you'll need.
Ok got it, accessed the method thru the JButton actionListener anonymous class by using a GUI snapshot in the debugger.
Thanks again for the help.
C
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.