如何从 PropertyChangeListener 更改 JOptionPane 的值而不触发侦听器?
我正在尝试制作一个程序来管理一群体育运动员。每个玩家都有一个枚举 Sport,并且 SportManager 有方便的工厂方法。我想做的是打开一个对话框,其中有一个用于名称的 JTextField 和一个用于选择运动的组合框。但是,我想阻止用户在文本字段为空时关闭对话框,因此我编写了一个 PropertyChangeListener,以便当文本字段为空时,它会发出蜂鸣声让用户知道。但是,如果用户在发出蜂鸣声后在文本中输入某些内容,则不会触发侦听器,并且在不按取消键的情况下无法关闭对话框,因为该值已经是 JOptionPane.OK_OPTION,而取消是唯一的方法更改 JOptionPane.VALUE_PROPERTY。 添加
message.setValue(JOptionPane.UNITIALIZED_VALUE);
所以我尝试在监听器中 。然而,这只是立即关闭窗口,而没有让用户有机会填写文本字段,大概是因为它触发了我刚刚注册的侦听器。我该如何使其能够多次发出蜂鸣声并让用户有机会填写该字段?
仅供参考 newPlayer 是我将操作注册到的组件。
代码:
newPlayer.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
Object[] msg = new Object [4];
msg[0] = new JLabel("Name:");
final JTextField nameField = new JTextField();
msg[1]=nameField;
msg[2] = new JLabel("Sport: ");
JComboBox<Sport> major = new JComboBox<Sport>(SportManager.getAllSports());
msg[3]=major;
final JOptionPane message = new JOptionPane();
message.setMessage(msg);
message.setMessageType(JOptionPane.PLAIN_MESSAGE);
message.setOptionType(JOptionPane.OK_CANCEL_OPTION);
final JDialog query = new JDialog(gui,"Create a new player",true);
query.setContentPane(message);
query.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
message.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (query.isVisible()&& (e.getSource() == message)&& (prop.equals(JOptionPane.VALUE_PROPERTY))) {
if(nameField.getText().equals("")&&message.getValue().equals(JOptionPane.OK_OPTION)){
Toolkit.getDefaultToolkit().beep();
message.setValue(JOptionPane.UNINITIALIZED_VALUE);
return;
}
query.dispose();
}
}
});
query.pack();
query.setVisible(true);
if(Integer.parseInt(message.getValue().toString())==JOptionPane.OK_OPTION){
players.add(new Player(nameField.getText(),(Sport)major.getSelectedItem()));
edited=true;
}
gui.show(players);
}
});
I am trying to make a program to manage a group of sports players. Each player has an enum Sport, and SportManager has convenient factory methods. What I am trying to do is open a dialog that has a JTextField for a name and a combo box to choose a sport. However, I want to stop the user from closing the dialog while the text field is blank, so I wrote a PropertyChangeListener so that when the text field is blank, it would beep to let the user know. However, if the user puts in something in the text after setting off the beep, it doesn't trigger the listener and you can't close the dialog without pressing cancel because the value is already JOptionPane.OK_OPTION, and cancel is the only way to change JOptionPane.VALUE_PROPERTY. So I tried to add
message.setValue(JOptionPane.UNITIALIZED_VALUE);
within the listener. However this just closes the window right away without giving the user a chance to fill in the text field, presumably because it triggers the listener I just registered. How do I make it so that it will beep more than once and give the user a chance to fill in the field?
FYI newPlayer is the component I'm registering the action to.
Code:
newPlayer.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
Object[] msg = new Object [4];
msg[0] = new JLabel("Name:");
final JTextField nameField = new JTextField();
msg[1]=nameField;
msg[2] = new JLabel("Sport: ");
JComboBox<Sport> major = new JComboBox<Sport>(SportManager.getAllSports());
msg[3]=major;
final JOptionPane message = new JOptionPane();
message.setMessage(msg);
message.setMessageType(JOptionPane.PLAIN_MESSAGE);
message.setOptionType(JOptionPane.OK_CANCEL_OPTION);
final JDialog query = new JDialog(gui,"Create a new player",true);
query.setContentPane(message);
query.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
message.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (query.isVisible()&& (e.getSource() == message)&& (prop.equals(JOptionPane.VALUE_PROPERTY))) {
if(nameField.getText().equals("")&&message.getValue().equals(JOptionPane.OK_OPTION)){
Toolkit.getDefaultToolkit().beep();
message.setValue(JOptionPane.UNINITIALIZED_VALUE);
return;
}
query.dispose();
}
}
});
query.pack();
query.setVisible(true);
if(Integer.parseInt(message.getValue().toString())==JOptionPane.OK_OPTION){
players.add(new Player(nameField.getText(),(Sport)major.getSelectedItem()));
edited=true;
}
gui.show(players);
}
});
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我认为您不能使用 JOptionPane 来做到这一点,但您可以使用 TaskDialog框架和其他一些。
您还可以自己创建一个对话框,将更改侦听器附加到您的字段,并根据字段的内容启用/禁用“确定”按钮。这个过程通常称为“表单验证”
I don't think you can do it with JOptionPane but you can using using TaskDialog framework and few others.
You can also create a dialog yourself, attach change listeners to your fields and enable/disable OK button based on content of your fields. This process is usually called "form validation"
我知道你要去哪里,但 Java Swing 对此不太擅长。您无法阻止侦听器被调用。一种解决方案是忽略该调用,但这实现起来很复杂。
我解决这个问题的方法是让弹出窗口消失,检查返回的值,如果它为空/空,则发出蜂鸣声并重新打开它,直到用户填写一些内容。
I get where you are going, but Java Swing is not very good at this. There is no way you can prevent the listener from being called. A solution would be to ignore the call, but this is complicated to implement.
The way I solved this issue is to let the pop-up disappear, check the returned value and if it is null/empty, beep and re-open it until user fills something.
JOptionPane 内部不支持输入验证(Bug 参考)。您最好的选择是创建自己的自定义 JDialog,它支持在输入数据无效时禁用“确定”按钮。
我建议阅读错误报告,因为其他人谈论它并给出解决方法。
JOptionPane does not internally support validation of inputs (Bug Reference). Your best bet is to create your own custom JDialog which supports disabling the OK button when the input data is invalid.
I'd recommend reading the bug report since other people talk about it and give workarounds.
停止自动对话框关闭 有一个执行此操作的工作示例。
快速查看您的代码和工作示例后,我认为您的代码应该类似于:
否则,我会让您将您的代码与工作代码进行比较,看看有什么区别。
The
CustomDialog
example from the section in the Swing tutorial on Stopping Automatic Dialog Closing has a working example that does this.After taking a quick look at your code and the working example I think your code should be something like:
Otherwise, I'll let you compare your code with the working code to see what the difference is.
解决此问题的一种方法是在对话框中添加
Cancel
和Ok
按钮。然后,禁止通过角落中的X
关闭弹出窗口,强制用户单击Cancel
或Ok
完成/关闭对话框。现在,只需向文本字段添加一个侦听器,如果文本字段为空,该侦听器将禁用Ok
按钮。从您的代码来看,我假设您可以弄清楚如何实现这些步骤,但如果您遇到问题,请告诉我们!祝你好运!
One way to solve this problem is to add a
Cancel
andOk
button to your dialog. Then, disable closing the popup via theX
in the corner, forcing the user to click eitherCancel
orOk
to finish/close the dialog. Now, simply add a listener to the text field that will disable theOk
button if the text field is blank.Judging from your code I assume you can figure out how to implement these steps, but if you have trouble let us know! Good luck!