【问题标题】:Swing: make button disabled on clickSwing:使按钮在单击时禁用
【发布时间】:2020-12-09 10:17:53
【问题描述】:

我正在处理一段代码,我准备了一个简单的例子:

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Example extends JFrame implements ActionListener {
    public static void main(String[] args) {
        Example e = new Example();
        e.setVisible(true);
    }

    private JButton button;

    public Example() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(600, 400);
        this.setLayout(null);

        button = new JButton("button");
        button.setBounds(200, 150, 200, 50);
        button.addActionListener(this);
        this.add(button);
    }
    @Override
    public void actionPerformed(ActionEvent actionEvent) {
        button.setEnabled(false);
        
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

重点是,我们有actionPerformed 函数,它有两个动作:禁用按钮并运行sleep 来模仿我所做的一些工作。

我的问题是按钮在actionPerformed 结束后被禁用,换句话说,在这 5 秒的睡眠之后,我不能更早地禁用它。我试图用它做点什么,但到目前为止将button.setEnabled(false); 更改为button.setEnabled(false); this.repaint(); this.validate(); 什么也没做。

我的问题是:如何在工作中完成工作,我需要先禁用按钮,然后做一些耗时的事情(例如睡觉)并在工作完成后启用按钮?

【问题讨论】:

  • 我很好奇。您在发布问题之前尝试过searching 吗?从 Swing 代码调用Thread.sleep() 已经被询问(并回答)了好几次了。 This question 看起来和你的很相似。你同意吗?

标签: java multithreading swing jbutton actionlistener


【解决方案1】:

这是因为您不能在创建 UI 的同一线程上Thread.sleep(),否则它将冻结 UI,直到 sleep 完成。

您想要做的可能是改用Swing TimerSwing Worker

其他几点:

  1. 不要不必要地扩展 JFrame
  2. 不要使用空值/AbsoluteLayout,而是使用适当的LayoutManager
  3. 不要在组件上调用 setBounds()setSize(),如果您使用正确的布局管理器,我们会为您处理此问题
  4. 在将框架设置为可见之前调用JFrame#pack()
  5. 应通过SwingUtilities.invokeLaterEDT 上调用所有Swing 组件
  6. 我也从来不喜欢在类的基础上实现ActionListener,特别是如果您有多个组件注册ActionListener

以下是使用Timer 所做更改的示例:

import java.awt.BorderLayout;
import javax.swing.*;
import java.awt.event.ActionEvent;
import javax.swing.border.EmptyBorder;

public class Example {

    private JButton button;
    private Timer timer;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(Example::new);
    }

    public Example() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.setBorder(new EmptyBorder(20, 20, 20, 20));

        button = new JButton("button");

        button.addActionListener((ActionEvent e) -> {
            if (timer != null && timer.isRunning()) {
                return;
            }
            
            button.setEnabled(false);

            timer = new Timer(5000, (ActionEvent e1) -> {
                // TODO do something after sleeping for 5 seconds
                button.setEnabled(true);
                timer.stop();
            });
            timer.start();
        });

        panel.add(button, BorderLayout.CENTER);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }
}

【讨论】:

    【解决方案2】:

    @David Kroukamp 非常感谢,这正是我想要的。如果这里需要的人很简单(但不完美,请参阅 toDavid 的回答)示例,Worker

    import javax.swing.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    public class Example extends JFrame implements ActionListener {
        public static void main(String[] args) {
            Example e = new Example();
            e.setVisible(true);
        }
    
        private JButton button;
    
        public Example() {
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            this.setSize(600, 400);
            this.setLayout(null);
    
            button = new JButton("button");
            button.setBounds(200, 150, 200, 50);
            button.addActionListener(this);
            this.add(button);
        }
        @Override
        public void actionPerformed(ActionEvent actionEvent) {
            button.setEnabled(false);
            startThread();
        }
    
        private void startThread() {
    
            SwingWorker sw1 = new SwingWorker() {
                @Override
                protected Object doInBackground() {
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return null;
                }
    
                @Override
                protected void done() {
                    button.setEnabled(true);
                }
            };
            
            sw1.execute();
        }
    }
    
    

    【讨论】:

      猜你喜欢
      • 2012-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多