【问题标题】:Change JButton Color in a Thread更改线程中的 JButton 颜色
【发布时间】:2013-08-07 01:15:25
【问题描述】:

我正在尝试制作一个类似 simon 的游戏:http://www.freegames.ws/games/kidsgames/simon/simon.htm#

我正在制作一个只有 2 个按钮的较小比例尺。我希望颜色在 2 个按钮、按钮 1 和按钮 2 之间切换。这是在一个线程中,因为我需要在发生这种情况时单击按钮。当我打开程序时,按钮颜色保持原样。

提前感谢您的帮助!

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;

import javax.swing.*;

public class TestFrame extends JFrame{

    public JButton button1; 
    public JButton button2;

    boolean isTrue = true;
    boolean switchColor = true;

    TestFrame(){
        super("Simon");
        initialize();

        this.setSize(200, 400);
        this.setVisible(true);
    }

    private void initialize() {
         this.setLayout(new BorderLayout()); 

        button1 = new JButton();
        button1.setBackground(Color.green);
        button1.setSize(200,200);

        button2 = new JButton();
        button2.setSize(200, 200);
        button2.setBackground(Color.blue);

        this.add(button1, BorderLayout.NORTH);
        this.add(button2, BorderLayout.SOUTH);
        Thread t = new Thread(r1);
        t.start();

    }
    Runnable r1 = new Runnable() {
        public void run() {
            while(isTrue){
            if(switchColor = true){
                button1.setBackground(Color.blue);
                button2.setBackground(Color.green);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                refresh();
                switchColor = false;
            } else {
                button1.setBackground(Color.green);
                button2.setBackground(Color.blue);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                refresh();

                switchColor = true;
                }
            }

        }
    };

    public void refresh(){
        this.invalidate();
        this.validate();
        this.repaint();
    }

}

【问题讨论】:

    标签: java multithreading swing


    【解决方案1】:

    有很多问题很突出(shazin 已经解决了一个),另一个让我害怕的是你违反了 Swing 的单线程要求。对 UI 的所有更改都必须在事件调度线程的上下文中进行。

    您应该使用javax.swing.Timer,而不是使用Thread。这将使您无需将更新重新同步回 EDT。

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class FlashyButtons {
    
        public static void main(String[] args) {
            new FlashyButtons();
        }
    
        public FlashyButtons() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private JButton btn1;
            private JButton btn2;
            private int count = 0;
    
            public TestPane() {
                setLayout(new GridBagLayout());
                btn1 = new FlashButton();
                btn2 = new FlashButton();
                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridwidth = GridBagConstraints.REMAINDER;
                add(btn1, gbc);
                add(btn2, gbc);
    
                btn1.setBackground(Color.GREEN);
                btn2.setBackground(Color.BLUE);
    
                Timer timer = new Timer(500, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        count++;
                        if (count % 2 == 0) {
                            btn1.setBackground(Color.BLUE);
                            btn2.setBackground(Color.GREEN);
                        } else {
                            btn1.setBackground(Color.GREEN);
                            btn2.setBackground(Color.BLUE);
                        }
                    }
                });
                timer.start();
            }
    
        }
    
        public class FlashButton extends JButton {
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
        }
    
    }
    

    查看Concurrency in Swing了解更多详情

    【讨论】:

      【解决方案2】:
      if(switchColor = true){
          button1.setBackground(Color.blue);
          button2.setBackground(Color.green);
          try {
              Thread.sleep(500);
          } catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
          refresh();
          switchColor = false;
      } else {
          button1.setBackground(Color.green);
          button2.setBackground(Color.blue);
          try {
              Thread.sleep(500);
          } catch (InterruptedException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
          refresh();
      
          switchColor = true;
          }
      }
      

      在上面的代码中将以下内容更改为

      if(switchColor = true){
      

      if(switchColor == true){ 
      

      或者只是

      if(switchColor){
      

      最好把你的 Runnable 匿名类放在里面

      SwingUtilities.invokeLater(new Runnable() {
          public void run() {
      
          }
      });
      

      而不是使用新的 Thread 对象来创建和启动线程,因为它将更改 Swing UI 属性。

      【讨论】:

      • 您是否还想讨论一下 OP 违反了 Swing 的单线程要求这一事实
      猜你喜欢
      • 2014-05-11
      • 2015-12-12
      • 2011-01-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 2019-02-14
      相关资源
      最近更新 更多