【问题标题】:Java Swing JButton Time Delays (Flicker)Java Swing JButton 时间延迟(闪烁)
【发布时间】:2014-07-12 07:08:17
【问题描述】:

我正在尝试让我正在创建的这个游戏的 JButton 闪烁红色。该网站上的所有解决方案都建议使用线程并将其置于睡眠状态或使用计时器,但是,暂停缓解似乎是在颜色更改之后发生的

这是我的代码:

Color cb = board[Y1][X1].getBackground();
board[Y1][X1].setBackground(Color.RED);
//Pause
board[Y1][X1].setBackground(cb);

如果我在第 3 行放置一个线程并将其置于睡眠状态并注释掉第 4 行,则暂停将在 JButton 变为红色之前出现。 (记事板只是 JButton 的二维数组)

【问题讨论】:

  • 欢迎来到 Stack Overflow!实际的runnable example that demonstrates your problem 将涉及更少的猜测工作和更好的响应
  • 我想以前一定有人遇到过类似的问题,实际代码没用,这更像是一个java问题。 JButton -> 红色暂停 JButton -> 黑色

标签: java swing colors jbutton thread-sleep


【解决方案1】:

发生这种情况的原因有很多,同样,解决方法也有很多。

根据您的描述,听起来您正在尝试从事件调度线程之外更新 UI。

Swing 是单线程环境,它也不是线程安全的。基本上,这意味着,对 UI 的所有交互/更改都期望在 EDT 的上下文中进行。不遵守这条规则可能会导致各种奇怪而奇妙的行为。

最简单的解决方案是使用javax.swing.Timer,例如,它允许您安排保证在 EDT 内执行的定期定时事件

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
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 FlashyButton {

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

    public FlashyButton() {
        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.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JButton button;
        private Color[] colors = new Color[]{Color.RED, Color.YELLOW};

        public TestPane() {
            button = new JButton("Flash Gorden");
            button.setContentAreaFilled(false);
            button.setBorderPainted(false);
            button.setFocusPainted(false);
            button.setOpaque(true);
            button.setBackground(Color.YELLOW);
            setLayout(new GridBagLayout());
            add(button);

            Timer timer = new Timer(500, new ActionListener() {
                private int counter = 0;
                @Override
                public void actionPerformed(ActionEvent e) {
                    counter++;
                    if (counter % 2 == 0) {
                        button.setBackground(colors[0]);
                    } else {
                        button.setBackground(colors[1]);
                    }
                }
            });
            timer.start();
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.dispose();
        }
    }

}

查看Concurrency in SwingHow to Use Swing Timers 了解更多详情。

更复杂的解决方案将允许您使用 Thread,但需要使用 SwingUtilities.invokeLater 更新 UI,这将在 EDT 上放置一个执行 Runnable 接口的事件,您将用于更新 UI。这可能存在同步问题,因为您调用的 Thread 将在实际事件触发之前继续进行,并且可能导致一些脏更新,除非您仔细控制更新过程...

【讨论】:

  • 此解决方案不适用于我的特定问题,我需要它闪烁一次而不是连续闪烁。因此,我尝试将计数器更改为布尔值并使用 if/else 但是因为我在板上使用它,所以事情很快就会下降
  • 所以?在所需的闪烁次数后停止Timer。您还可以使用单个 TimerListQueue 需要刷新的项目
猜你喜欢
  • 1970-01-01
  • 2015-05-16
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
  • 1970-01-01
相关资源
最近更新 更多