java - Jbutton 在两种背景颜色之间闪烁

标签 java swing animation time intervals

我的问题:程序在我的场景中延迟的有效方法。

我的场景: 我正在为一个简短的项目制作一个问答游戏,长话短说。当用户按下四个有答案的 Jbutton 之一时,问题就会得到回答。然后我的 quizengine 类调用此处显示的 paintbutton 方法。之后它继续调用一些其他方法来负责使下一个问题出现。现在我想要的是使按钮在两种颜色之间随着时间间隔的减少而变化。

到目前为止我尝试了什么: 首先,我在 paintbutton 方法和将界面更改为下一个问题的方法之间放置了一个 JoptionPane,只是为了查看按钮是否会改变颜色。它成功了。当然这不是我的本意,我只是想要一个时间间隔。 然后我尝试使用 Thread.Sleep。虽然程序会在切换到下一个问题之前等待,但颜色变化是不可见的。 最后,我尝试了一个 Timer 东西的实现(可能不正确),虽然它改变了颜色,但程序继续前进并继续下一个问题。

我想成为代码

  /* Paints the button pressed red or green
   *  Green if the anwser is correct red if 
   *  its false
   *
   * @param int bnr the number of the button
   * @param boolean corr true if correct false if false :D
   */
   public static void paintbutton(int bnr,boolean corr) { 
       for (int i=10;i>1;i--){
        b[bnr-1].setBackground(null);     
        //wait for i*100 milliseconds
        b[bnr-1].setBackground(corr?Color.green:Color.red);          
       }
   }

最佳答案

让我们从一些基础知识开始。 Swing 是单线程的,这意味着您绝不能在事件调度线程的上下文中阻塞或执行长时间运行的代码,这会使 UI 卡住并且用户不高兴

Swing 不是线程安全的,这意味着您永远不应在 EDT 上下文之外创建或更新 UI。

这会让您陷入困境。您想在稍作延迟后更新 UI。

幸运的是,至少有两种可能性,Swing TimerSwingWorker

Swing Timer 相对简单,但实际上并没有提供在更新之间生成可变延迟的方法。 SwingWorker 更复杂,但可以让您控制基本上做您想做的事。

这两者都(可以)在 EDT 之外“等待”,但它们都提供了可以安全地将更新推送到 EDT 的方法。

例如……

Blinky

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class BlinkyTheButton {

    public static void main(String[] args) {
        new BlinkyTheButton();
    }

    public BlinkyTheButton() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JButton blinky;

        public TestPane() {
            blinky = new JButton("Blinky");
            blinky.setOpaque(true);
            blinky.addActionListener(new ActionListener() {
                private BlinkWorker worker;
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (worker == null || worker.getState() == SwingWorker.StateValue.DONE) {
                        worker = new BlinkWorker(blinky, Color.RED);
                        worker.addPropertyChangeListener(new PropertyChangeListener() {
                            @Override
                            public void propertyChange(PropertyChangeEvent evt) {
                                SwingWorker worker = (SwingWorker) evt.getSource();
                                if ("state".equals(evt.getPropertyName())) {
                                    if (worker.getState() == SwingWorker.StateValue.DONE) {
                                        // this is where you would then call the method to
                                        // update the state for a new question
                                    }
                                }
                            }
                        });
                        worker.execute();
                    }
                }
            });
            setLayout(new GridBagLayout());
            add(blinky);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        public class BlinkWorker extends SwingWorker<Void, Color> {

            private JButton btn;
            private Color color;
            private Color normal;

            public BlinkWorker(JButton btn, Color color) {
                this.btn = btn;
                normal = btn.getBackground();
                this.color = color;
            }

            @Override
            protected Void doInBackground() throws Exception {
                for (int index = 10; index > 1; index--) {
                    publish(color);
                    Thread.sleep(index * 100);
                    publish(normal);
                    Thread.sleep(index * 100);
                }
                return null;
            }

            @Override
            protected void process(List<Color> chunks) {
                Color color =  chunks.get(chunks.size() - 1);
                btn.setBackground(color);
            }

        }

    }

}

看看Concurrency in Swing , How to use Swing TimersWorker Threads and SwingWorker了解更多详情

关于java - Jbutton 在两种背景颜色之间闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34623827/

相关文章:

java - 为什么不能通过用不同大小的数组替换变量来重新分配数组的大小?

java - 如何获得与网格布局内联的 jpg

python - python 中的极圈动画

java - 覆盖 Jersey 2.5.1 中的 RolesAllowedDynamicFeature

java - java 8 获取和编辑子列表位于主列表中

java - 将多个用户输入存储到整数数组中

java - Java MVC-我在这里缺少什么吗?

java - 简单 JPanel 的问题

jQuery:在调整大小的图像上冒烟

CSS3 Animate 属性在 Chrome 中不起作用,在 Firefox/IE 中起作用