Java Swing JButton 时间延迟(闪烁) [英] Java Swing JButton Time Delays (Flicker)

查看:67
本文介绍了Java Swing JButton 时间延迟(闪烁)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to make my JButton flicker red for this game I am creating. All the solutions on this website suggest using a thread and putting it to sleep or using a timer, however, the pause allays seems to come after the color change

这是我的代码:

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

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

If I put a thread and put it to sleep on line 3 and comment out line 4 the pause will come before the JButton is turned red. (Note board is just a 2D array of JButtons)

推荐答案

出现这种情况的原因有很多,同样,也有很多解决方案.

There are any number reasons why this might be occurring and equally, any number of ways it might be fixed.

根据您的描述,您似乎正在尝试从事件调度线程之外更新 UI.

Based on your description, it sounds like you're trying to update the UI from outside of the Event Dispatching Thread.

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

Swing is a single thread environment, it's also not thread safe. Basically what this means is, there is an expectation that all interactions/changes to the UI are carried out within the context of the EDT. Failing to following this rule can lead to all sorts of weird and wonderful behaviour.

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

The simplest solution is to use a javax.swing.Timer, which allows you to schedule regular timed events which are guaranteed to be executed within the EDT, for example

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();
        }
    }

}

看看 Swing 中的并发如何使用 Swing 计时器 了解更多详情.

Take a look at Concurrency in Swing and How to Use Swing Timers for more details.

更复杂的解决方案将允许您使用 Thread,但需要使用 SwingUtilities.invokeLater 更新 UI,这会将事件放置到 EDT这将执行一个 Runnable 接口,您将使用它来更新 UI.这可能会出现同步问题,因为您正在调用的 Thread 将在实际事件被触发之前移动,并可能导致一些脏更新,除非您仔细控制更新过程......

A more complex solution would allow you to use a Thread, but would require to update the UI by using SwingUtilities.invokeLater, which would place an event onto the EDT that would execute a Runnable interface, which you would use to update the UI. This could have synchronisation issues as the Thread you're calling from will have moved on before the actual event is triggered and could cause some dirty updates, unless you control the update process carefully...

这篇关于Java Swing JButton 时间延迟(闪烁)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆