【问题标题】:Java Swing Timer Not ClearJava Swing 计时器不清晰
【发布时间】:2014-05-29 03:50:53
【问题描述】:

我在使用 Java swing 的 Timer 功能时遇到了一些问题。我对使用 Java 编程相当陌生,因此非常感谢任何帮助。我查看了该站点上的许多其他 Timer 问题,但没有一个回答我的问题。我制作了一个 GUI,允许您玩石头剪刀布,您可以在其中单击三个按钮进行选择。我希望我的程序在您单击按钮后休眠大约 1 秒钟,然后在它显示一条消息后再次休眠。在我意识到 Thread.sleep() 不适用于我的 GUI 之后,我尝试实现一个计时器。

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!");
        }
    }
}
}

实际发生的情况是从我按下按钮到显示消息没有延迟,因为显然我没有正确使用计时器。我希望计时器只运行一次,运行后代码将执行。但是,当我单击一个按钮时,尽管 setRepeats 为 false,但计时器将重复运行。因此,我想显示的消息不会被延迟,而是会立即显示,但随后会循环显示一条消息(消息是随机的),直到我关闭程序。如果我再次单击该按钮,它将使计时器的速度增加一倍,并且消息显示的速度增加一倍,依此类推。

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

这是重复显示的消息,变量 tc 每次都在变化。计时器似乎只是在每个计时器间隔 (1s) 显示此消息。

任何帮助将不胜感激。

编辑:

所以我添加了这个部分:

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...
    }
}

所以我相信现在发生的事情是,当我单击一个按钮时,按钮处理程序侦听器会启动附加到计时器侦听器(名为 listenert)的计时器,该计时器将运行计时器类的 actionPerformed 中的代码。但是睡眠功能仍然不起作用

编辑 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();     

    }
} 

这就是我目前所拥有的,我只需要在之后添加antoher sleep them.setText("他们选择了:" + tc + "!"); 如果有的话,我会把 timer.restart() 放在哪里? timer.start() 在我不太明白的方法的末尾。

【问题讨论】:

  • 您可以在 MadProgrammer 的 TestPane 示例中看到他如何创建一个匿名类 ActionListener 作为参数传递给 Timer。考虑那个,因为您的计时器侦听器不应与ButtonListener(用于按钮)相同。将这个想法与他的其他答案结合起来,并尝试解决它。重点不是给你完整的答案,而是让你了解计时器应该如何工作:-)
  • 你不需要额外的监听器。只需执行new Timer(1000, new ActionListener() { ... });。尝试并工作。如果您遇到困难,请发布您的尝试的另一个编辑:-)
  • 我应该在这些括号内插入按下按钮时会发生什么或进行某种计时器操作吗?
  • 不完全确定您期望的结果,但是是的,但您还需要actionPerformed。传递给 Timer 的 ActionListener 的目的是在延迟后执行您想要执行的操作。所以你想在延迟之后执行什么,这就是计时器监听器应该做的事情
  • 好的,我已经进行了编辑,感谢你们两个,我想我已经取得了进展。它现在可以正确执行延迟,然后显示消息,但这次不会在延迟和 FIRST 消息之后设置中间文本。

标签: java swing timer sleep


【解决方案1】:

因此,当计时器“滴答”时,您提供给TimerActionListener 会收到通知,因此您的ButtonHandler actionPerformed 应该看起来更像...

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();
}

你的listener 应该看起来更像

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...
}

例如...

您可以考虑查看How to use Swing Timers了解更多详情

更新

从一个简单的例子开始... 公共类 TestPane 扩展 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()));

    }
}

这只是每半秒调用一次tick方法来更新JLabel上的时间...

【讨论】:

  • 我有点困惑,我应该创建两个名为 actionPerformed 的方法吗?您能否通过禁用按钮以防止用户进行另一次更新来详细说明您的意思?当计时器滴答作响时,听众究竟会发生什么,我不太清楚。使用的侦听器与我的 GUI 上的按钮连接的侦听器相同,有问题吗?
  • 我已经多次查看该网页,但似乎无法从中提取任何有用的信息。它没有告诉我将计时器代码放在哪里,以便在显示消息之前只运行一次。
  • 基本上,当Timer "ticks" 时,它会调用提供的ActionListeneractionPerformed 方法,这就是你如何知道计时器已关闭
  • 那么这里的问题是我在它调用的方法中调用计时器吗?我不清楚听众的事情。如果您查看我的完整代码,您能否详细说明一下?我将不胜感激。
  • Listener 是一个 ButtonHandler,都在上面的代码中。我真的迷路了,我尝试运行您刚刚发布的最后一个程序,但不知道导入所有内容后如何,所以我无法理解您的示例。
【解决方案2】:

首先导入以下内容;

import java.awt.event.ActionEvent ;

import java.awt.event.ActionListener ;

import javax.swing.Timer ; 

然后像这样在表格末尾初始化计时器; 公共静态 void main(String args[]) {

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

});

}    
    private Timer timer ;

然后在初始化计时器后添加一个公共类,如下所示;

公共类进度实现 ActionListener { public void actionPerformed(ActionEvent evt){

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

完成此操作后转到 j 框架>右键单击并选择>事件>窗口>打开的窗口并键入以下内容;

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

在你完成所有这些之后,将一个按钮命名为任何东西,然后在其空白处键入以下内容,如下所示;

 timer.start();

这就是它的代码,然后回复我......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    • 1970-01-01
    • 2020-11-23
    • 2012-08-22
    • 1970-01-01
    • 1970-01-01
    • 2017-05-18
    相关资源
    最近更新 更多