如何使用 DefaultEditor 方法检查对 JSpinner 字段的手动编辑 [英] How to check manual edits on a JSpinner field using DefaultEditor approach
问题描述
我正在修改这里的代码:
I am adapting code from here:
编辑 2
当我按下向上微调箭头时,下面的代码给了我一个无限循环的对话框:
The following code gives me an infinite loop of dialogs when I press the up spinner arrow:
字符串:字符串:10值:10细绳:字符串:10值:10细绳:字符串:10值:10.....
STRING: STRING: 10 VALS: 10 STRING: STRING: 10 VALS: 10 STRING: STRING: 10 VALS: 10 .....
警告你需要使用任务管理器来杀死它.
Warning you will need to use taskmanager to kill it.
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame F = new JFrame();
F.setVisible(true);
JPanel p = new JPanel();
final JSpinner spin2 = new JSpinner();
spin2.setModel(new SpinnerNumberModel(10, 10, 100, 1));
JComponent comp = spin2.getEditor();
JFormattedTextField field = (JFormattedTextField) comp.getComponent(0);
DefaultFormatter formatter = (DefaultFormatter) field.getFormatter();
formatter.setCommitsOnValidEdit(true);
((JSpinner.DefaultEditor)spin2.getEditor()).getTextField().getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
warn();
}
public void removeUpdate(DocumentEvent e) {
warn();
}
public void insertUpdate(DocumentEvent e) {
warn();
}
public void warn() {
String text = ((JSpinner.DefaultEditor)spin2.getEditor()).getTextField().getText();
JOptionPane.showMessageDialog(null, "STRING: "+text, "Error Massage", JOptionPane.ERROR_MESSAGE);
if (text != null && !text.trim().isEmpty()) {
int stringValue = Integer.parseInt(((JSpinner.DefaultEditor)spin2.getEditor()).getTextField().getText());
JOptionPane.showMessageDialog(null,
"VALS: "+spin2.getValue(), "Error Massage",
JOptionPane.ERROR_MESSAGE);
if (stringValue<10 || stringValue >100){
JOptionPane.showMessageDialog(null,
"Error: Number outside bounds", "Error Massage",
JOptionPane.ERROR_MESSAGE);
}
}
}
});
p.add(spin2);
F.add(p);
F.pack();
F.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
编辑 3
当无效时,这会将背景更改为红色,但当字段失去焦点时,BUT 值将恢复为以前的(如果无效).我希望能够在那时放置一个 JOptionPane 说值仍然无效,而不是恢复到以前的:
This changes background to red when invalid, BUT values reverts to previous (if invalid) when field looses focus. I want to be able to put up a JOptionPane at that point saying value is STILL invalid, instead of reverting to previous:
((JSpinner.DefaultEditor)Position.getEditor()).getTextField().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
//LOG.info("" + evt);
if ("editValid".equals(evt.getPropertyName())) {
if (Boolean.FALSE.equals(evt.getNewValue())) {
SpinnerNumberModel model = (SpinnerNumberModel) Position.getModel();
((JSpinner.DefaultEditor)Position.getEditor()).getTextField().setBackground(Color.RED);
((JSpinner.DefaultEditor)Position.getEditor()).getTextField().setToolTipText("Amount must be in range [ " + model.getMinimum() + " ... " + model.getMaximum() + " ] for this symbol");
}
else{
((JSpinner.DefaultEditor)Position.getEditor()).getTextField().setBackground(Color.WHITE);
}
}
}
});
///////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////
原始问题
但是如果我使用微调器输入低于下限的值.我在文本字段中收到一个 "(" 和这个错误:
But if I use spinner to put in value lower than lower bound. I get a "(" in the text field and this error:
线程AWT-EventQueue-0"中的异常java.lang.NumberFormatException:对于输入字符串:"在 java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)在 java.lang.Integer.parseInt(Integer.java:504)在 java.lang.Integer.parseInt(Integer.java:527)在 com.NResearch.ValueAtRisk.Sigma$7.warn(Sigma.java:626)在 com.NResearch.ValueAtRisk.Sigma$7.removeUpdate(Sigma.java:619)在 javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:260)在 javax.swing.text.AbstractDocument.handleRemove(AbstractDocument.java:623)在 javax.swing.text.AbstractDocument.remove(AbstractDocument.java:591)在 javax.swing.text.AbstractDocument.replace(AbstractDocument.java:667)在 javax.swing.text.JTextComponent.setText(JTextComponent.java:1718)在 javax.swing.JFormattedTextField$AbstractFormatter.install(JFormattedTextField.java:949)在 javax.swing.text.DefaultFormatter.install(DefaultFormatter.java:124)在 javax.swing.text.InternationalFormatter.install(InternationalFormatter.java:285)在 javax.swing.JFormattedTextField.setFormatter(JFormattedTextField.java:465)在 javax.swing.JFormattedTextField.setValue(JFormattedTextField.java:789)在 javax.swing.JFormattedTextField.processFocusEvent(JFormattedTextField.java:636)在 java.awt.Component.processEvent(Component.java:6261)在 java.awt.Container.processEvent(Container.java:2229)在 java.awt.Component.dispatchEventImpl(Component.java:4861)在 java.awt.Container.dispatchEventImpl(Container.java:2287)在 java.awt.Component.dispatchEvent(Component.java:4687)在 java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1895)在 java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:938)在 java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:570)在 java.awt.Component.dispatchEventImpl(Component.java:4731)在 java.awt.Container.dispatchEventImpl(Container.java:2287)在 java.awt.Component.dispatchEvent(Component.java:4687)在 java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735)在 java.awt.EventQueue.access$200(EventQueue.java:103)在 java.awt.EventQueue$3.run(EventQueue.java:694)在 java.awt.EventQueue$3.run(EventQueue.java:692)在 java.security.AccessController.doPrivileged(Native Method)在 java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)在 java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)在 java.awt.EventQueue$4.run(EventQueue.java:708)在 java.awt.EventQueue$4.run(EventQueue.java:706)在 java.security.AccessController.doPrivileged(Native Method)在 java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)在 java.awt.EventQueue.dispatchEvent(EventQueue.java:705)在 java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)在 java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)在 java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)在 java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Integer.parseInt(Integer.java:504) at java.lang.Integer.parseInt(Integer.java:527) at com.NResearch.ValueAtRisk.Sigma$7.warn(Sigma.java:626) at com.NResearch.ValueAtRisk.Sigma$7.removeUpdate(Sigma.java:619) at javax.swing.text.AbstractDocument.fireRemoveUpdate(AbstractDocument.java:260) at javax.swing.text.AbstractDocument.handleRemove(AbstractDocument.java:623) at javax.swing.text.AbstractDocument.remove(AbstractDocument.java:591) at javax.swing.text.AbstractDocument.replace(AbstractDocument.java:667) at javax.swing.text.JTextComponent.setText(JTextComponent.java:1718) at javax.swing.JFormattedTextField$AbstractFormatter.install(JFormattedTextField.java:949) at javax.swing.text.DefaultFormatter.install(DefaultFormatter.java:124) at javax.swing.text.InternationalFormatter.install(InternationalFormatter.java:285) at javax.swing.JFormattedTextField.setFormatter(JFormattedTextField.java:465) at javax.swing.JFormattedTextField.setValue(JFormattedTextField.java:789) at javax.swing.JFormattedTextField.processFocusEvent(JFormattedTextField.java:636) at java.awt.Component.processEvent(Component.java:6261) at java.awt.Container.processEvent(Container.java:2229) at java.awt.Component.dispatchEventImpl(Component.java:4861) at java.awt.Container.dispatchEventImpl(Container.java:2287) at java.awt.Component.dispatchEvent(Component.java:4687) at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1895) at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:938) at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:570) at java.awt.Component.dispatchEventImpl(Component.java:4731) at java.awt.Container.dispatchEventImpl(Container.java:2287) at java.awt.Component.dispatchEvent(Component.java:4687) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735) at java.awt.EventQueue.access$200(EventQueue.java:103) at java.awt.EventQueue$3.run(EventQueue.java:694) at java.awt.EventQueue$3.run(EventQueue.java:692) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87) at java.awt.EventQueue$4.run(EventQueue.java:708) at java.awt.EventQueue$4.run(EventQueue.java:706) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.awt.EventQueue.dispatchEvent(EventQueue.java:705) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
final JSpinner spin2 = new JSpinner();
spin2.setModel(new SpinnerNumberModel(10, 10, 100, 1));
JComponent comp = spin2.getEditor();
JFormattedTextField field = (JFormattedTextField) comp.getComponent(0);
DefaultFormatter formatter = (DefaultFormatter) field.getFormatter();
formatter.setCommitsOnValidEdit(true);
((JSpinner.DefaultEditor)spin2.getEditor()).getTextField().getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
warn();
}
public void removeUpdate(DocumentEvent e) {
warn();
}
public void insertUpdate(DocumentEvent e) {
warn();
}
public void warn() {
int stringValue = Integer.parseInt(((JSpinner.DefaultEditor)spin2.getEditor()).getTextField().getText());
JOptionPane.showMessageDialog(null,
"VALS: "+spin2.getValue(), "Error Massage",
JOptionPane.ERROR_MESSAGE);
if (stringValue<10 || stringValue >100){
JOptionPane.showMessageDialog(null,
"Error: Please enter number bigger than 0", "Error Massage",
JOptionPane.ERROR_MESSAGE);
}
}
});
推荐答案
自定义 DocumentListeners 和 formattedTextField 不能很好地相互配合,最好不要混用.相反,在文本字段上使用 PropertyChangeListener 来侦听其 editValid 属性的更改:每当更改为 false 时,您可以通知用户
Custom DocumentListeners and formattedTextField don't play nicely with each other, better don't mix. Instead, use a PropertyChangeListener on the text field that listens for changes of its editValid property: whenever that changes to false, you could notify the users
field.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
LOG.info("" + evt);
if ("editValid".equals(evt.getPropertyName())
&& Boolean.FALSE.equals(evt.getNewValue())) {
SpinnerNumberModel model = (SpinnerNumberModel) spin2.getModel();
JOptionPane.showMessageDialog(null,
"Error: Number must be in range [" + model.getMinimum() + " ..." + model.getMaximum() + "]",
"Error Massage",
JOptionPane.ERROR_MESSAGE);
}
}
});
顺便说一句,就我个人而言,我同意 Mad - 这种侵入性的通知往往会惹恼我,也许你的用户也会..
BTW, personally, I agree with Mad - such an intrusive notification tends to annoy me and maybe your users as well ..
这篇关于如何使用 DefaultEditor 方法检查对 JSpinner 字段的手动编辑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!