如何以编程方式调用作为独立任务运行的按钮?

发布于 2024-11-28 13:19:19 字数 679 浏览 1 评论 0原文

我已经在Java swing中实现了康威的生命游戏问题。一切正常。正如您在下面的屏幕截图中看到的那样,每当单击“勾选”按钮时,游戏就会进入下一个生命形式。现在,我计划在“勾选”按钮旁边添加一个“自动播放”按钮。自动播放的目的很简单。当我点击它时,自动操作应该继续进行,就像我以 1 秒的间隔按下勾选按钮一样。

在此处输入图像描述

我尝试过这个。但这似乎阻止了所有其他操作。如何在单独的线程中执行此操作?一个小代码片段就能让我继续下去。

class AutoPlayListener implements ActionListener{
  public void actionPerformed(ActionEvent e) {
    if(e.getSource() == btnAutoPlay){
      while(true){
        Thread.sleep(1000); //InterruptedException try catch hidden
        btnTick.doClick();
      }
    }
  }
}

I have implemented Conway's Game of Life problem in Java swing. Everything is working fine. As you can see in the screenshot below, whenever the "Tick" button is clicked, the game progresses to the next life form. Now, I am planning to include an "Autoplay" button alongside "Tick" button. The purpose of this autoplay is simple. When I hit it, an automated operation should carry on as if I am pressing tick button at an interval of 1 second.

enter image description here

I tried this. But this seems to block all the other operations. How to do this action in a separate thread? A small code snippet would get me going.

class AutoPlayListener implements ActionListener{
  public void actionPerformed(ActionEvent e) {
    if(e.getSource() == btnAutoPlay){
      while(true){
        Thread.sleep(1000); //InterruptedException try catch hidden
        btnTick.doClick();
      }
    }
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

盛夏尉蓝 2024-12-05 13:19:19

使用javax.swing.Timer。如果删除了 while(true) 和 Thread.sleep() 调用,它将能够与现有的 ActionListener 一起使用。

Use a javax.swing.Timer. It will be able to work with the existing ActionListener if the while(true) and Thread.sleep() calls are removed.

静赏你的温柔 2024-12-05 13:19:19

正如 @Ranman 所说,你正在阻塞主 UI 线程。我相信 SwingUtilities .invokeLater 通常用于此类事情。

As @Ranman said you're blocking main UI thread. I believe SwingUtilities.invokeLater is usually used for things like this.

有两个选项:

  1. 启动新线程。该线程将包含 while 循环,并执行处理数组的方法。在每次迭代中,在窗口上调用 repaint()invalidate() 来告诉它需要重绘。
  2. 使用计时器。 GUI 线程将定期调用您的例程。

线程:

actionPerformed 方法中,创建一个新线程。并调用它的start方法。
线程的 Runnable 应该运行一个 while 循环(正如您已经完成的那样),然后简单地退出。

Timer:

在 Timer 类型的类中创建一个对象。如果您使用 swing,请使用 java.swing.Timer 中的一个(还有一个不适合 GUI 操作的 java.util.Timer)。计时器应该有一个 ActionListener 来调用您的方法一次,但计时器的重复率为 1000 毫秒。

提示

  1. 要调用该操作,您应该将其放在单独的方法中,而不是直接在按钮处理程序下。这样,您就不会从 GUI 线程外部调用 GUI 内容。

例如

tickButton.addActionListener(new ActionListener(){
  public void actionPerformed(ActionEvent e){
    doTick();
  }
});
  1. 停止线程的机制同样重要!一般来说,不要在线程中使用 while(true) 因为它会丢失;发明一个信号量来终止它。

  2. 使用JToggleButton而不是Button

  3. 同步:
    如果您使用线程,您将需要这样的东西,以防止每次按下按钮时创建新线程:

代码

Thread autoplayThread = null;
Object lock;
boolean autoplaying = false;
public void actionPerformed(ActionEvent e){
  synchronized(lock){ // prevent any race condition here
    if(!autoplaying && autoplayThread==null ){
      autoplaying = true; 
      autoplayThread = new Thread(new Runnable(){
        public void run(){
          try{ 
            while(autoplaying){  ....  }
          }finally{
            synchronized(lock) {
              autoplaying=false;
              autoplayThread=null;
            }
          }
        }
      });
      autoplayThread.start();
    }else{ // stop the thread!
      autoplaying=false;
    }
  }
}

There are two options:

  1. Start a new thread. The thread will contain the while loop, and execute a method that processes the array. In each iteration, call repaint() or invalidate() on your window to tell it that it needs redrawing.
  2. Use a Timer. The GUI thread will call your routine at regular intervals.

Threads:

In actionPerformed method, create a new Thread. and call its start method.
The Runnable of the thread should run a while loop (as you have already done), and then simply exit.

Timer:

Create an object in your class of type Timer. Use the one in java.swing.Timer if you are using swing (there is also java.util.Timer which isn't good for GUI ops). The timer should have an ActionListener that calls your method once, but the Timer has a repeat rate of 1000ms.

Tips

  1. to invoke the action, you should put it in a separate method, rather than directly under the button handler. That way, you aren't calling GUI stuff from outside the GUI thread.

e.g.

tickButton.addActionListener(new ActionListener(){
  public void actionPerformed(ActionEvent e){
    doTick();
  }
});
  1. The mechanism to stop the thread is equally important! In general, don't use a while(true) in a thread as it will get lost; invent a semaphore to terminate it.

  2. use a JToggleButton rather than Button?

  3. Synchronization:
    If you use threads, you will need something like this, to prevent new threads being created each time the button is pressed:

Code

Thread autoplayThread = null;
Object lock;
boolean autoplaying = false;
public void actionPerformed(ActionEvent e){
  synchronized(lock){ // prevent any race condition here
    if(!autoplaying && autoplayThread==null ){
      autoplaying = true; 
      autoplayThread = new Thread(new Runnable(){
        public void run(){
          try{ 
            while(autoplaying){  ....  }
          }finally{
            synchronized(lock) {
              autoplaying=false;
              autoplayThread=null;
            }
          }
        }
      });
      autoplayThread.start();
    }else{ // stop the thread!
      autoplaying=false;
    }
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文