java - 在后台作业时禁用 JButton,以避免多次点击

标签 java swing thread-safety jbutton

我需要阻止用户在 JButton 上进行多次点击,而第一次点击仍在执行。

我能够为这个问题提供解决方案,但我不完全理解它为什么有效。

下面我发布了有效的代码和无效的代码(修剪到最低限度)。

在第一个示例(好)中,如果您运行它并多次单击按钮,则只有一个操作被视为第二个示例(坏),如果您多次单击鼠标,您至少会执行两次操作。

第二个(错误的)示例根本没有使用 invokeLater() 方法。

行为差异从何而来?

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

public class TestButtonTask {

    public static void main(String[] args) {

        final JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        final JButton task = new JButton("Test");

        task.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                long t = System.currentTimeMillis();
                System.out.println("Action received");

                task.setText("Working...");
                task.setEnabled(false);

                SwingUtilities.invokeLater(new Thread() {

                    @Override
                    public void run() {
                        try {
                            sleep(2 * 1000);
                        } catch (InterruptedException ex) {
                            Logger.getLogger(TestButtonTask.class.getName()).log(Level.SEVERE, null, ex);
                        }

                        SwingUtilities.invokeLater(new Runnable() {

                            public void run() {
                                task.setEnabled(true);
                                task.setText("Test");
                            }
                        });

                    }
                });
            }
        });

        frame.add(task);
        frame.pack();
        frame.setVisible(true);
    } //end main
} //end class

现在是“错误的”代码

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

public class TestButtonTask {

    public static void main(String[] args) {

        final JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        final JButton task = new JButton("Test");

        task.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                long t = System.currentTimeMillis();
                System.out.println("Action received");

                task.setText("Working...");
                task.setEnabled(false);

                SwingUtilities.invokeLater(new Thread() {

                    @Override
                    public void run() {
                        try {
                            sleep(2 * 1000);
                        } catch (InterruptedException ex) {
                            Logger.getLogger(TestButtonTask.class.getName()).log(Level.SEVERE, null, ex);
                        }

                        //SwingUtilities.invokeLater(new Runnable() {

                            //public void run() {
                                task.setEnabled(true);
                                task.setText("Test");
                            //}
                        //});

                    }
                });
            }
        });

        frame.add(task);
        frame.pack();
        frame.setVisible(true);
    } //end main
} //end class

根据@kleopatra 和@Boris Pavlović 提供的信息,这里是我创建的代码,看起来工作得相当不错。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

public class TestButtonTask {

    public static void main(String[] args) {

        final JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        final JButton task = new JButton("Test");

        task.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                task.setText("Working...");
                task.setEnabled(false);

                SwingWorker worker = new SwingWorker<Void, Void>() {

                    @Override
                    protected Void doInBackground() throws Exception {
                        try {
                            Thread.sleep(3 * 1000);
                        } catch (InterruptedException ex) {
                            Logger.getLogger(TestButtonTask.class.getName()).log(Level.SEVERE, null, ex);
                        }

                        return null;
                    }                    
                };

                worker.addPropertyChangeListener(new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        System.out.println("Event " + evt + " name" + evt.getPropertyName() + " value " + evt.getNewValue());
                        if ("DONE".equals(evt.getNewValue().toString())) {
                            task.setEnabled(true);
                            task.setText("Test");
                        }
                    }
                });

                worker.execute();
            }
        });

        frame.add(task);
        frame.pack();
        frame.setVisible(true);
    } //end main
} //end class

最佳答案

你有两个选择

1) JButton#setMultiClickThreshhold

2) 你必须将这个想法拆分为 actionListener 或 Action 中的两个单独的 Action

  • 第一。步骤,JButton#setEnabeld(false);
  • 第二。步骤,然后调用包装到 javax.swing.Action 的其余代码(来自 javax.swing.Timer 并由其处理),SwingWorker可运行#Thread

关于java - 在后台作业时禁用 JButton,以避免多次点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8428841/

相关文章:

java - hadoop DistributedFileSystem 线程安全吗?

java - 无法从其他 EJB2 查找 EJB2,但可以从 servlet 查找

java - 为什么 Collection 的 .addAll 比手动添加慢?

java - 改变JTree第一个节点的图标

当在新框架上显示时,Java var 变回 0

java - 检测显示器是否旋转

ios - CoreData 和线程安全

C++ 线程安全 vector .erase

输入字符串 "1"的 java.lang.NumberFormatException

java - 无法在java中的selenium webdriver中选择下拉列表