Вопрос по jbutton, thread-sleep, colors, swing, java – Java Swing JButton Временные задержки (мерцание)

0

Я пытаюсь заставить свой JButton мигать красным для этой игры, которую я создаю. Все решения на этом веб-сайте предлагают использовать поток и перевести его в спящий режим или использовать таймер, однако после смены цвета появляются задержки паузы.

Вот мой код:

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

Если я поместил поток и перевел его в строку 3 и закомментировал строку 4, пауза наступит до того, как JButton станет красным. (Доска объявлений - это просто двумерный массив кнопок J)

Добро пожаловать в переполнение стека! Фактическийработающий пример, который демонстрирует вашу проблему будет включать меньше работы по угадыванию и лучшие ответы MadProgrammer
Вы были бы удивлены MadProgrammer
Я полагал, что кто-то, должно быть, сталкивался с подобной проблемой прежде, фактический код бесполезен, это больше проблема Java. JButton -> красная пауза JButton -> черный user3667398

Ваш Ответ

1   ответ
4

Существует множество причин, по которым это может происходить, и, в равной степени, любое количество способов его устранения.

Судя по вашему описанию, похоже, что вы пытаетесь обновить пользовательский интерфейс за пределами потока диспетчеризации событий.

Swing - это однопоточное окружение, оно также небезопасно. По сути, это означает, что все взаимодействия / изменения пользовательского интерфейса выполняются в контексте 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();
        }
    }

}

Взгляни наПараллелизм в Swing а такжеКак использовать Swing Timers Больше подробностей.

Более сложное решение позволит вам использоватьThread, но потребуется обновить интерфейс пользователя с помощьюSwingUtilities.invokeLater, который поместит событие в EDT, которое будет выполнятьRunnable интерфейс, который вы будете использовать для обновления пользовательского интерфейса. Это может иметь проблемы с синхронизацией, так какThread ваш звонок перешел до того, как фактическое событие сработало, и может вызвать некоторые грязные обновления, если вы тщательно не контролируете процесс обновления ...

Так? ОстановитьTimer после необходимого количества вспышек. Вы также можете использовать одинTimer иList или жеQueue предметов, которые нужно прошить MadProgrammer
Это решение не работает для моей конкретной проблемы, мне нужно, чтобы оно мигало один раз, а не мигало непрерывно. Поэтому я попытался изменить счетчик на логическое значение и использовать if / else, однако, поскольку я использую это на доске, все очень быстро снижается. user3667398
Видите, наглядный пример действительно помогает ... MadProgrammer

Похожие вопросы