在Java中,当actionPerformed线程当前正在运行时,如何从中重新绘制面板?

在Java中,当actionPerformed线程当前正在运行时,如何从中重新绘制面板?,java,swing,concurrency,actionlistener,event-dispatching,Java,Swing,Concurrency,Actionlistener,Event Dispatching,我有一个类(称为class_GUI),它有一个面板,上面有很多按钮。类GUI有一些方法可以更改按钮的文本和颜色 我还有一个带有actionPerformed方法的程序。当调用它时,它会创建一个Class_GUI实例,并反复调用Class_GUI方法、更改按钮等 我遇到的问题是,只有在actionPerformed方法完全完成后,按钮才会正确显示,而我希望在调用每个类的GUI方法后,按钮才会改变 到目前为止,我在每个类的GUI方法中都进行了尝试。我在方法的末尾这样做: SwingUtilities

我有一个类(称为class_GUI),它有一个面板,上面有很多按钮。类GUI有一些方法可以更改按钮的文本和颜色

我还有一个带有actionPerformed方法的程序。当调用它时,它会创建一个Class_GUI实例,并反复调用Class_GUI方法、更改按钮等

我遇到的问题是,只有在actionPerformed方法完全完成后,按钮才会正确显示,而我希望在调用每个类的GUI方法后,按钮才会改变

到目前为止,我在每个类的GUI方法中都进行了尝试。我在方法的末尾这样做:

SwingUtilities.invokeLater(Refresh_GUI);
其中定义了Refresh_GUI:

Runnable Refresh_GUI = new Runnable(){
    public void run(){
        frame.revalidate();
        frame.repaint();
    }
};

首先,确保您仅从事件分派线程访问任何GUI组件(通过invokeLater或作为处理GUI事件的一部分)


其次,如果您更改GUI组件的任何属性,它应该自动发布一个事件以重新绘制自身。如果没有,您可以尝试调用
组件.repaint()
。但对组件属性的更改发生在EDT上是至关重要的。

如果您的actionPerform方法调用代码来更新for循环中的按钮,您还可以在invokeLater中添加更新代码,这样更新和绘制代码都将逐个运行。“以后调用”将仅在当前方法完成其执行后执行,因此确保绘制速度更快的唯一方法是将任务分解为更小的部分。

假设在事件调度线程的上下文中调用了您的
actionPerformed
方法,在
actionPerformed
方法完成之前不会发生UI更新,即使使用
SwingUtilities#invokeLater
也不会改变这一点,因为在
actionPerformed
方法退出之前,EDT将无法继续处理(除其他外)重绘请求

你能做的最好的事情就是启动第二个线程,然后从该线程中更新你的UI组件……但是,你将被迫使用
SwingUtilities\invokeLater
,因为你永远不应该更新EDT之外的任何UI组件

不过,它的优点是线程不需要为了EDT开始处理重绘请求而竞争

用示例更新

public class SwingThreadUpdate {

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

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

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new BlinkPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class BlinkPane extends JPanel {

        private JLabel label;
        private JButton button;

        public BlinkPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridy = 0;

            label = new JLabel("Blinky");
            label.setBackground(Color.RED);
            button = new JButton("Click me");

            add(label, gbc);
            gbc.gridy++;
            add(button, gbc);

            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    button.setEnabled(false);
                    new Thread(new BlinkTask(BlinkPane.this)).start();
                }
            });

        }

        private void setBlink(boolean blink) {
            label.setOpaque(blink);
        }

        private void reset() {
            button.setEnabled(true);
            label.setOpaque(false);
        }
    }

    public class BlinkTask implements Runnable {

        private BlinkPane blinkPane;

        protected BlinkTask(BlinkPane blinkPane) {
            this.blinkPane = blinkPane;
        }

        @Override
        public void run() {
            Blink blinkOn = new Blink(blinkPane, true);
            Blink blinkOff = new Blink(blinkPane, false);

            for (int index = 0; index < 10; index++) {
                if (index % 2 == 0) {
                    SwingUtilities.invokeLater(blinkOn);
                } else {
                    SwingUtilities.invokeLater(blinkOff);
                }
                try {
                    Thread.sleep(125);
                } catch (InterruptedException ex) {
                }
            }

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    blinkPane.reset();
                }
            });

        }
    }

    public class Blink implements Runnable {

        private BlinkPane blinkPane;
        private boolean blink;

        public Blink(BlinkPane blinkPane, boolean blink) {
            this.blinkPane = blinkPane;
            this.blink = blink;
        }

        @Override
        public void run() {
            blinkPane.setBlink(blink);
            blinkPane.repaint();
        }
    }
}
公共类SwingThreadUpdate{
公共静态void main(字符串[]args){
新SwingThreadUpdate();
}
公共SwingThreadUpdate(){
invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException |实例化Exception | IllegalacessException |不支持ookandfeelException ex){
}
JFrame=新JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(新的BorderLayout());
frame.add(新的BlinkPane());
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
});
}
公共类BlinkPane扩展了JPanel{
私人标签;
私人按钮;
公共闪烁窗格(){
setLayout(新的GridBagLayout());
GridBagConstraints gbc=新的GridBagConstraints();
gbc.gridy=0;
标签=新的JLabel(“Blinky”);
标签.立根背景(颜色.红色);
按钮=新建按钮(“单击我”);
添加(标签,gbc);
gbc.gridy++;
添加(按钮,gbc);
addActionListener(新建ActionListener()){
@凌驾
已执行的公共无效操作(操作事件e){
按钮。设置启用(错误);
新线程(新的BlinkTask(BlinkPane.this)).start();
}
});
}
专用链接(布尔闪烁){
标签。设置不透明(闪烁);
}
私有无效重置(){
按钮。setEnabled(真);
label.setOpaque(假);
}
}
公共类任务实现可运行{
私人闪烁窗格闪烁窗格;
受保护的闪烁任务(闪烁窗格闪烁窗格){
this.blinkPane=blinkPane;
}
@凌驾
公开募捐{
闪烁闪烁=新闪烁(闪烁窗格,真);
闪烁闪烁关闭=新闪烁(闪烁窗格,错误);
对于(int-index=0;index<10;index++){
如果(索引%2==0){
SwingUtilities.invokeLater(blinkOn);
}否则{
SwingUtilities.invokeLater(闪烁);
}
试一试{
睡眠(125);
}捕获(中断异常例外){
}
}
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
blinkPane.reset();
}
});
}
}
公共类Blink实现可运行{
私人闪烁窗格闪烁窗格;
私有布尔闪烁;
公共闪烁(闪烁窗格闪烁窗格,布尔闪烁){
this.blinkPane=blinkPane;
this.blink=闪烁;
}
@凌驾
公开募捐{
闪烁窗格。设置链接(闪烁);
blinkPane.repaint();
}
}
}

您可能需要通读了解更多信息。

一个简单的解决方案是执行整个ActionPerformed无事件任务,以清理事件队列末尾的屏幕。 因此,它首先执行cleanScreen()函数,因为事件的其余部分等待所有事件完成

    AnyButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            cleanScreen();        //Modify components before action performer event
            EventQueue.invokeLater( new Runnable() {
                @Override public void run() {
                    anytask();    //Action performer event
                }
            });                     
        }
    });

目前,该类的GUI方法是l