Swing:单击时禁用按钮
Swing: make button disabled on click
我有一段代码正在处理,我准备了一个简单的例子:
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();
什么也没做。
我的问题是:如何在 swing 工作中做,我需要先禁用按钮,然后做一些耗时的事情(例如睡眠)并在工作完成后启用按钮?
那是因为您不能 Thread.sleep()
在创建 UI 的同一线程上,否则它会冻结 UI 直到 sleep完成。
您想要做的可能是使用 Swing Timer or Swing Worker。
其他几点:
- 不要不必要地扩展
JFrame
class
- 不要使用 null/
AbsoluteLayout
而是使用适当的 LayoutManager
- 不要在组件上调用
setBounds()
或 setSize()
,如果您使用正确的布局管理器,系统会为您处理此问题
- 在将框架设置为可见之前调用
JFrame#pack()
- 应通过
SwingUtilities.invokeLater
在 EDT 上调用所有 Swing 组件
- 我也从来不喜欢在 class 的基础上实现
ActionListener
,尤其是当你有超过 1 个组件注册 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);
}
}
@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();
}
}
我有一段代码正在处理,我准备了一个简单的例子:
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();
什么也没做。
我的问题是:如何在 swing 工作中做,我需要先禁用按钮,然后做一些耗时的事情(例如睡眠)并在工作完成后启用按钮?
那是因为您不能 Thread.sleep()
在创建 UI 的同一线程上,否则它会冻结 UI 直到 sleep完成。
您想要做的可能是使用 Swing Timer or Swing Worker。
其他几点:
- 不要不必要地扩展
JFrame
class - 不要使用 null/
AbsoluteLayout
而是使用适当的 LayoutManager - 不要在组件上调用
setBounds()
或setSize()
,如果您使用正确的布局管理器,系统会为您处理此问题 - 在将框架设置为可见之前调用
JFrame#pack()
- 应通过
SwingUtilities.invokeLater
在 EDT 上调用所有 Swing 组件
- 我也从来不喜欢在 class 的基础上实现
ActionListener
,尤其是当你有超过 1 个组件注册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);
}
}
@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();
}
}