Вопрос

I have been having some problems with using the Timer function of Java swing. I am fairly new to programming with Java, so any help is greatly appreciated. I have looked over many other Timer questions on this site but none of them have answered my question. I have made a GUI that allows you to play rock paper scissors, where you can choose from clicking three buttons. I want my program to sleep for around 1 second after you click the button, and again after it displays a message. After I realized Thread.sleep() wouldn't work for my GUI, I tried to implement a timer.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*; 
import javax.swing.border.Border;
import java.io.*;

public class rps { 
//ROCK PAPER SCISSORS
static JLabel middle = new JLabel();
static JLabel them = new JLabel();
static JLabel yourWins = new JLabel();
static JLabel theirWins = new JLabel();
static JPanel yourPanel = new JPanel();
static JPanel middlePanel = new JPanel();
static JLabel blank1 = new JLabel();
static JLabel blank2 = new JLabel();
static JButton rock = new JButton("Rock");
static JButton paper = new JButton("Paper");
static JButton scissors = new JButton("Scissors");
static int yw = 0;
static int tw = 0;
static ButtonHandler listener = new ButtonHandler();

public static void main(String[] args) { 

    //Create the frame
    JFrame frame = new JFrame("Rock Paper Scissors");
    frame.setSize(500, 500); //Setting the size of the frame

    middle.setFont(new Font("Serif", Font.PLAIN, 30)); 
    middle.setHorizontalAlignment(SwingConstants.CENTER);
    them.setFont(new Font("Serif", Font.PLAIN, 15));
    them.setHorizontalAlignment(SwingConstants.CENTER);
    yourWins.setHorizontalAlignment(SwingConstants.CENTER);
    theirWins.setHorizontalAlignment(SwingConstants.CENTER);

    //Creating panels
    JPanel bigPanel = new JPanel();

    Border border = BorderFactory.createLineBorder(Color.BLACK, 1); 
    Border wlb = BorderFactory.createLineBorder(Color.RED, 1); 
    them.setBorder(border);
    yourPanel.setBorder(border);
    bigPanel.setBorder(border);
    yourWins.setBorder(wlb);
    theirWins.setBorder(wlb);
    middlePanel.setBorder(border);

    //Creating grid layouts 
    GridLayout yourGrid = new GridLayout(1,3,10,10); 
    GridLayout theirGrid = new GridLayout(1,1); //One row, one column
    GridLayout middleGrid = new GridLayout(5,1);
    GridLayout bigGrid = new GridLayout(3,1);//Two rows, one column

    //Setting the layouts of each panel to the grid layouts created above
    yourPanel.setLayout(yourGrid); //Adding layout to buttons panel
    them.setLayout(theirGrid); //Adding layout to label panel
    middlePanel.setLayout(middleGrid); 
    bigPanel.setLayout(bigGrid);

    //Adding r/p/s to your grid.
    yourPanel.add(rock);
    yourPanel.add(paper);
    yourPanel.add(scissors);

    //Adding w/l rations to middlegrid.
    middlePanel.add(theirWins);
    middlePanel.add(blank1);
    middlePanel.add(middle);
    middlePanel.add(blank2);
    middlePanel.add(yourWins);

    //Attaching the listener to all the buttons
    rock.addActionListener(listener);
    paper.addActionListener(listener);
    scissors.addActionListener(listener);

    bigPanel.add(them);
    bigPanel.add(middlePanel);
    bigPanel.add(yourPanel); 

    //Shows the score at 0-0.
    yourWins.setText("Your wins: " + yw);
    theirWins.setText("Their wins: " + tw);

    frame.getContentPane().add(bigPanel); //panel to frame 
    frame.setVisible(true); // Shows frame on screen
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

//Class represents what do when a button is pressed
private static class ButtonHandler implements ActionListener { 
    public void actionPerformed (ActionEvent e) {
        Timer timer = new Timer(1000, this);

        String tc = random();
        them.setText("They chose: " + tc + "!");
        if (e.getSource() == rock) {
            whoWins("rock", tc);
        } else if (e.getSource() == paper) {
            whoWins("paper", tc);
        } else if (e.getSource() == scissors) {
            whoWins("scissors", tc);
        }
        yourWins.setText("Your wins: " + yw);
        theirWins.setText("Their wins: " + tw);

        timer.setRepeats(false);
        timer.start();
    }
} 

public static String random() {
    int random = (int) (Math.random() * 3);
    if (random == 0) {
        return "Rock";
    } else if (random == 1) {
        return "Paper";
    } else if (random == 2) {
        return "Scissors";
    }
    return "";
}

public static void whoWins(String yc, String tc) {
    if (yc.equals("rock")) {
        if (tc.equals("Rock")) {
            middle.setText("It's a tie!");            
        } else if (tc.equals("Paper")) {
            middle.setText("You lose!");
            tw++;
        } else if (tc.equals("Scissors")) {
            middle.setText("You win!");
            yw++;
        }
    } else if (yc.equals("paper")) {
        if (tc.equals("Rock")) {
            middle.setText("You win!");
            yw++;
        } else if (tc.equals("Paper")) {
            middle.setText("It's a tie!");
        } else if (tc.equals("Scissors")) {
            middle.setText("You lose!");
            tw++;
        }
    } else if (yc.equals("scissors")) {
        if (tc.equals("Rock")) {
            middle.setText("You lose!");
            tw++;
        } else if (tc.equals("Paper")) {
            middle.setText("You win!");
            yw++;
        } else if (tc.equals("Scissors")) {
            middle.setText("It's a tie!");
        }
    }
}
}

What is actually happening is there is no delay from when I press the button to a message displaying, because clearly I am not using the timer correctly. I would like the timer to just run once, and after it runs the code will execute. However, when I click a button the timer will run on repeat although setRepeats is false. Therefore, the message I want to display, instead of being delayed, is displayed instantaneously but then goes on a loop and keeps displaying a message (the message is random) until I shut off the program. If I click the button again, it will double the tempo of the timer it seems, and the messages display twice as fast and so on and so forth.

them.setText("They chose: " + tc + "!");

This is the message that is displayed on repeat, with the variable tc changing every time. The timer seems to just be displaying this message every timer interval (1s).

Any help would be greatly appreciated.

EDIT:

So I added this section :

private static class ButtonHandler implements ActionListener { 
    public void actionPerformed (ActionEvent e) {
        // I'd be disabling the buttons here to prevent
        // the user from trying to trigger another 
        // update...

        // This is an instance field which is used by your
        // listener

        Timer timer = new Timer(1000, listenert);
        timer.setRepeats(false);
        timer.start();
    }
}
private static class timer implements ActionListener {
    public void actionPerformed (ActionEvent e) {
        String tc = random(); //A method that chooses a random word.
        them.setText("They chose: " + tc + "!"); 
        if (e.getSource() == rock) {
            whoWins("rock", tc); //whoWins is a method that will display a message.
        } else if (e.getSource() == paper) {
            whoWins("paper", tc);
        } else if (e.getSource() == scissors) {
            whoWins("scissors", tc);
        }
        yourWins.setText("Your wins: " + yw);
        theirWins.setText("Their wins: " + tw);

        // Start another Timer here that waits 1 second
        // and re-enables the other buttons...
    }
}

so what I believe happens now is when I click a button, the buttonhandler listener starts the timer which is attached to the timer listener (named listenert) which will run the code in the actionPerformed of the timer class. however the sleep function still is not working

EDIT 2.5:

 private static class ButtonHandler implements ActionListener { 
    public void actionPerformed (ActionEvent e) {
        final JButton button = (JButton)e.getSource();
        Timer timer = new Timer(1000, new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        String tc = random();
                        them.setText("They chose: " + tc + "!");
                        if (button == rock) {
                            whoWins("rock", tc);
                        } else if (button == paper) {
                            whoWins("paper", tc);
                        } else if (button == scissors) {
                            whoWins("scissors", tc);
                        }
                        yourWins.setText("Your wins: " + yw);
                        theirWins.setText("Their wins: " + tw);
                    }
                });
        timer.setRepeats(false);
        timer.start();     

    }
} 

that is what I have so far, I just need to add antoher sleep after them.setText("They chose: " + tc + "!"); where would I put a timer.restart() if any? the timer.start() is at the end of the method which I don't quite understand.

Это было полезно?

Решение

So, the ActionListener you supply to the Timer is notified when the timer "ticks", so you ButtonHandler actionPerformed should look more like...

public void actionPerformed (ActionEvent e) {
    // I'd be disabling the buttons here to prevent
    // the user from trying to trigger another 
    // update...

    // This is an instance field which is used by your
    // listener
    choice = e.getSource();

    Timer timer = new Timer(1000, listener);
    timer.setRepeats(false);
    timer.start();
}

And your listener should look more like

public void actionPerformed (ActionEvent e) {
    String tc = random(); //A method that chooses a random word.
    them.setText("They chose: " + tc + "!"); 
    if (choice == rock) {
        whoWins("rock", tc); //whoWins is a method that will display a message.
    } else if (choice == paper) {
        whoWins("paper", tc);
    } else if (choice == scissors) {
        whoWins("scissors", tc);
    }
    yourWins.setText("Your wins: " + yw);
    theirWins.setText("Their wins: " + tw);

    // Start another Timer here that waits 1 second
    // and re-enables the other buttons...
}

For example...

You may consider taking a look at How to use Swing Timers for more details

Updated

Start with a simple example... public class TestPane extends JPanel {

    private JLabel label;
    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

    public TestPane() {
        setLayout(new GridBagLayout());
        label = new JLabel();
        add(label);
        tick();

        Timer timer = new Timer(500, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                tick();
            }
        });
        timer.start();
    }

    protected void tick() {

        label.setText(sdf.format(new Date()));

    }
}

This just calls the tick method every half second to update the time on the JLabel...

Другие советы

firstly import the following ;

import java.awt.event.ActionEvent ;

import java.awt.event.ActionListener ;

import javax.swing.Timer ; 

then initialize the timer at the end of the form like this ; public static void main(String args[]) {

 java.awt.EventQueue.invokeLater(new Runnable() {        
            public void run() {       
            new mainprogramme().setVisible(true);    
        }    

});

}    
    private Timer timer ;

then after initializing the timer add a public class like following;

public class progress implements ActionListener { public void actionPerformed(ActionEvent evt){

int n = 0 ;
if (n<100){
    n++ ;
    System.out.println(n) ;
}else{
    timer.stop() ;
}
}
}

after you do this go to the j Frame>right click and select>Events>window>window Opened and type the following ;

private void formWindowOpened(java.awt.event.WindowEvent evt) {                                  
        timer = new Timer(100,new progress()) ;

and after you do all this take a button name it as anything and type the following in its void like following ;

 timer.start();

AND THAT'S IT CODE IT AND THEN REPLY ME...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top