我有一个系统,我需要能够问一个简单的"继续?"风格问题。有一个文本字段和一个按钮。要么单独修改文本字段,要么单独按下按钮,我需要能够要求用户确认。因此,这为我提供了文本字段的焦点监听器和按钮上的动作监听器。
但是,如果我编辑该字段,并立即单击该按钮,将弹出两个确认对话框 - 一个来自焦点监听器,另一个来自动作监听器后面的一个。现在,我显然只需要确认一次,所以我尝试同步抛出JOptionPane的函数,因此它不会输入两次,但这似乎没有效果。
一些代码证明了这一点:
public class Main extends JFrame {
static public void main(String [] args) {
SwingUtilities.invokeLater(() -> {
Main m = new Main();
m.setVisible(true);
});
}
private JTextField field;
private JButton button;
private boolean isValid;
public Main() {
isValid = false;
setLayout(new BorderLayout());
field = new JTextField(15);
field.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent arg0) {}
@Override
public void focusLost(FocusEvent e) {
doValidate();
}
});
add(field, BorderLayout.CENTER);
button = new JButton("Push Me");
button.addActionListener((ActionEvent e) -> {
doValidate();
doAction();
});
add(button, BorderLayout.SOUTH);
pack();
}
private synchronized void doValidate() {
System.out.println("Validating");
if(!isValid) {
int answer = JOptionPane.showConfirmDialog(this, "Really do it?");
if(answer == JOptionPane.YES_OPTION)
isValid = true;
}
}
private void doAction() {
System.out.println("Action done!");
}
}
首先,这有点令人惊讶。如果有人对Swing / JOptionPane如何绕过synchronized关键字进行解释,我会很高兴。
至于如何处理,我的想法是我需要实现一个等待确认对话框答案的线程。然后,我需要检查线程是否处于活动状态(如果对话框已经启动,那么),如果它已启动,我需要在给出答案时添加一个监听器。我已经完成了这项任务,但感觉就像过度设计问题的解决方案一样,特别是因为我对这为什么会发生这种情况的理解有限。此外,我已经可以想象至少有几种不同的情况,我最终会遇到麻烦,使其更容易出错。
=== EDIT ===
要清楚,这些消息框会同时弹出,而不是按顺序弹出。例如:
答案 0 :(得分:1)
同步意味着2个线程不能同时进入块,而不是永远。他们只是等待其他线程释放对该方法的锁定然后调用它。因此你的2个对话框。
这可能无论如何都不相关,因为我认为UI渲染是相同的线程,所以你只是从两个独立的UI事件中调用两次相同的方法(我可能错了)。
至于让它工作,不要担心线程,而是查看DocumentListener
。
答案 1 :(得分:0)
我建议添加以下内容,以便单击红色x将退出程序。
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //new
请注意,只需删除按钮监听器即可获得所需的行为。
以下是我认为可以为您提供所需行为的代码:
package swingdemo1;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SwingDemo1 extends JFrame {
static public void main(String [] args) {
SwingUtilities.invokeLater(() -> {
SwingDemo1 m = new SwingDemo1();
m.setVisible(true);
});
}
private JTextField field;
private JButton button;
private boolean isValid;
private boolean validationDone;
String state;
public SwingDemo1() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //new
isValid = false;
setLayout(new BorderLayout());
field = new JTextField(15);
field.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent arg0) {
}
@Override
public void focusLost(FocusEvent e) {
doValidate();
doAction();
}
});
add(field, BorderLayout.CENTER);
button = new JButton("Push Me");
/* //new
button.addActionListener((ActionEvent e) -> {
System.out.println("ActionEvent: " + e.getActionCommand());
doValidate();
doAction();
});
*/ //new
add(button, BorderLayout.SOUTH);
pack();
}
private synchronized void doValidate() {
System.out.println("Validating");
if(!isValid) {
int answer = JOptionPane.showConfirmDialog(this, "Really do it?");
if(answer == JOptionPane.YES_OPTION)
isValid = true;
}
}
private void doAction() {
System.out.println("Action done!");
}
}