2014-10-18 68 views
1

我正在尝试构建一个西蒙说游戏,它将闪烁按钮按下。我目前正试图弄清楚如何使按钮一个接一个闪烁。遵循文档(尽我所能),我编写了下面的代码,但出于某种原因,只有绿色按钮闪烁。我进一步测试了一下,发现只有btnGo事件中的最后一种方法才能正常工作。我认为这与计时器的运行方式有关,它在计时器结束之前将红色和蓝色按钮变回黑色,但我不确定如何或为什么?摆动定时器仅在最后一个事件上运行

public void flashRed(){ 
    btn1.setBackground(Color.red); 
    btn2.setBackground(Color.black); 
    btn3.setBackground(Color.black); 
    btn4.setBackground(Color.black); 
    repaint(); 
    t.start(); 
} 
public void flashYellow(){ 
    btn1.setBackground(Color.black); 
    btn2.setBackground(Color.yellow); 
    btn3.setBackground(Color.black); 
    btn4.setBackground(Color.black); 
    repaint(); 
    t.start(); 
} 
public void flashGreen(){ 
    btn1.setBackground(Color.black); 
    btn2.setBackground(Color.black); 
    btn3.setBackground(Color.green); 
    btn4.setBackground(Color.black); 
    repaint(); 
    t.start(); 
} 
public void flashBlue(){ 
    btn1.setBackground(Color.black); 
    btn2.setBackground(Color.black); 
    btn3.setBackground(Color.black); 
    btn4.setBackground(Color.blue); 
    repaint(); 
    t.start(); 
} 

@Override 
public void actionPerformed(ActionEvent event) { 
     if(event.getSource() == btnGo) 
     { 
      flashRed(); 
      flashBlue(); 
      flashGreen(); 

     } 
     if(event.getSource() ==t){ 
      btn1.setBackground(Color.black); //resets btn1 to black 
      btn2.setBackground(Color.black); 
      btn3.setBackground(Color.black); 
      btn4.setBackground(Color.black); 

      repaint(); 
      t.stop(); //stops the timer 
     } 
    } 
+0

(event.getSource()== t)是不正确的使用.equals代替 – 2014-10-18 14:07:53

+0

你需要在每次调用之间使用Thread.sleep – subash 2014-10-18 14:32:50

+0

@getlost如果将'ActionListener'附加到'Timer',则源代码将与您连接侦听器的实例完全相同,因此使用'=='是完全有效的代码。不需要使用“equals”。 @subash在他的代码中,我只检测EDT的用法。除非您正在设计无响应的用户界面,否则永远不要在EDT上调用Thread.sleep。 – Robin 2014-10-18 15:18:14

回答

3

有几件事情要记住:

  • Swing是单线程(线程称为E(口)d(ispatch)T(hread))。当你在那个线程上做东西时,你的UI不能重画,反之亦然。
  • repaint()的调用实际上并未执行重绘。它只是在美国东部时间安排重新油漆。如果安排了多个重新打印,他们只是分组,并且只有一个被执行
  • JComponents上的大多数方法不会立即更改组件。他们只是改变组件的状态并安排重新绘制。重绘完成后,您会看到在UI中反映的更改。

    flashRed(); 
    flashBlue(); 
    flashGreen(); 
    

    这会改变很多按钮的背景颜色,但根本就没有时间来进行重绘为:

所以,当你按下JButton和你ActionListener被触发会发生什么你的代码占据了EDT。只有当您的ActionListener完成后,才能执行repaint。此时,除绿色按钮外,所有按钮的背景都会变回黑色。这就是为什么你只看到绿色的按钮闪烁。

你需要做的是解决这个问题,将它们一个接一个地闪光,然后释放两者之间的EDT,给它时间来执行重绘。我会通过使用Timer来解决这个问题。但是,为什么你只用它来将按钮的背景恢复为黑色,我也会用它来闪烁。

在伪代码中,ActionListener会是什么样子:

switch (iteration){ 
    case first: 
    flashRed(); 
    increaseIteration(); 
    break; 
    case second: 
    flashBlue(); 
    increaseIteration(); 
    break; 
    ... 
    case last: 
    restoreAllToBlack(); 
    timer.stop(); 
    break; 
} 
-1

你需要将所有的后台线程在等待完成,然后把以后的颜色变化命令进入EDT与调用。如果你这样做,那么你可以完全不用这个定时器构造,因为你可以睡觉()后台线程。想想这样一来,后台线程是策划的颜色变化,与EDT处理实际屏幕小部件:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 

public class testFrame { 

    static JButton btn1 = new JButton("red"); 
    static JButton btn2 = new JButton("yellow"); 
    static JButton btn3 = new JButton("green"); 
    static JButton btn4 = new JButton("blue"); 

    public static void showFrame() { 
     JFrame frame = new JFrame(); 
     frame.setLocation(500, 500); 
     frame.setSize(100, 100); 
     final JButton button = new JButton("Test"); 
     button.setMaximumSize(new Dimension(80, 30)); 
     button.setSize(80, 20); 
     frame.setLayout(new GridLayout(5, 1)); 
     frame.add(button); 
     frame.add(btn1); 
     frame.add(btn2); 
     frame.add(btn3); 
     frame.add(btn4); 
     button.addMouseListener(new MouseAdapter() { 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { 

        @Override 
        public Void doInBackground() { 
         try { 
          flashRed(); 
          Thread.sleep(500); 
          flashGreen(); 
          Thread.sleep(500); 
          flashBlue(); 
          Thread.sleep(500); 
          flashYellow(); 
         } catch (InterruptedException e) { 
         } 
         return null; 
        } 

        @Override 
        public void done() { 
        } 
       }; 
       worker.execute(); 
      } 
     }); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void flashRed() { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       btn1.setBackground(Color.red); 
       btn2.setBackground(Color.black); 
       btn4.setBackground(Color.black); 
       btn3.setBackground(Color.black); 
      } 
     }); 
    } 

    public static void flashYellow() { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       btn1.setBackground(Color.black); 
       btn2.setBackground(Color.yellow); 
       btn3.setBackground(Color.black); 
       btn4.setBackground(Color.black); 
      } 
     }); 
    } 

    public static void flashGreen() { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       btn1.setBackground(Color.black); 
       btn2.setBackground(Color.black); 
       btn3.setBackground(Color.green); 
       btn4.setBackground(Color.black); 
      } 
     }); 
    } 

    public static void flashBlue() { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       btn1.setBackground(Color.black); 
       btn2.setBackground(Color.black); 
       btn3.setBackground(Color.black); 
       btn4.setBackground(Color.blue); 
      } 
     }); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       showFrame(); 
      } 
     }); 
    } 
} 
+0

'button.addMouseListener'真的吗? “ActionListener”有什么问题。如果你在'done'方法中没有做任何事情,那么使用'SwingWorker'有什么好处呢?如果你打算用invokeLater来混淆你的代码,那么使用'SwingWorker'与Swing'Timer'相比有什么好处呢?你必须在你的代码示例中创建所有按钮静态实例 – Robin 2014-10-20 14:23:48

+0

由于我想创建一个类应用程序,并且main()需要根据定义静态化,所以我将所有内容都设置为静态。这样可以让代码变得简单。 – DaveB 2014-10-20 20:04:14

相关问题