如何根据最小/最大范围外的 jSpinner 中文本字段的无效手动编辑触发事件

我有一个 java swing UI jSpinner 组件,它接受双精度值并设置了最小和最大允许范围。问题是,当用户在组件的 jFormattedTextField 部分中手动输入一个值,该值超出最小/最大范围并且焦点离开文本字段时,该值会立即被拒绝并恢复为上一个有效值,(是组件的预期和正确行为)。


用户已请求更改行为,以便当输入无效值并且焦点离开文本字段而不是仅仅恢复到最后一个有效值时,它应该恢复到最大或最小有效值,具体取决于用户是否输入大于最大允许值或小于允许最小值的无效值。


例如,如果微调器的最小/最大范围设置为 (1,10) 并且用户手动输入值 20,则文本字段应设置为 10,而不是 jSpinner 模型中存在的最后一个有效值。


我已经尝试了很多不同的方法来解决这个问题,包括将 KeyListener 附加到底层的 JFormattedTextField 以及将 PropertyChangeListener 附加到 Jspinner 的数字/默认编辑器,但似乎主要问题是我无法获得无效的值的实际值,以便我可以确定它是否超出范围,高于最大值或低于最小值。


使用 KeyListener(我意识到这不是处理 JFormattedTextField 输入的合适方法)我至少能够捕捉到击键,但是使用以下代码我能做的最多就是捕捉到一个让我知道的异常输入值超出最小/最大范围,仅此而已。


在代码示例中,我收到的值是因为“dirtyValue”始终是最后一个有效值,而不是实际无效的新输入用户输入。

我完全没有想法。任何人都可以帮助提供一些见解吗?


我尝试过使用 KeyListener、propertyChangeListener 和 DocumentListener。


private JFormattedTextField tf = ((JSpinner.NumberEditor)

jSpinnerTiming.getEditor()).getTextField();


((JSpinner.DefaultEditor)jSpinnerTiming.getEditor()).getTextField().

              addKeyListener(new KeyListener(){


              @Override public void keyPressed(KeyEvent e) { 


              }


              @Override public void keyReleased(KeyEvent e) { 


              }


              @Override public void keyTyped(KeyEvent e) { 

    try {        tf.commitEdit(); } catch

              (ParseException e1) { // TODO Auto-generated catch block

              e1.printStackTrace(); } 

    double dirtyValue = (double)tf.getValue(); 

    double max = ALLOWABLE_MAX;

    double min = ALLOWABLE_MIN;

              if (dirtyValue > max) { 

    jSpinnerTiming.setValue(max);

              ; } else if(dirtyValue < min){

              jSpinnerTiming.setValue(min); 

              } }


              });


Helenr
浏览 172回答 3
3回答

慕斯709654

这是我能够使用 FocusListener 开始工作的解决方案,尽管我不确定它的正确性。private JFormattedTextField tf = ((JSpinner.DefaultEditor) jSpinnerTiming.getEditor()).getTextField();((JSpinner.DefaultEditor)jSpinnerTiming.getEditor()).getTextField().addFocusListener(new&nbsp; FocusListener() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public void focusLost(FocusEvent e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // The unchecked user input value&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double dirtyValue = Double.parseDouble(tf.getText());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Get Minimum and Maximum values from jSpinner's Model&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double max = (Double) ((SpinnerNumberModel) jSpinnerTiming.getModel()).getMaximum();//MAX_ALLOWED_RATE&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; double min = (Double) ((SpinnerNumberModel) jSpinnerTiming.getModel()).getMinimum();//LOWEST_ALLOWABLE_RATE;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (dirtyValue > max) {&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jSpinnerTiming.setValue(max);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if(dirtyValue < min){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jSpinnerTiming.setValue(min);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public void focusGained(FocusEvent e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // TODO Auto-generated method stub&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });

慕无忌1623718

问题是 JSpinner 将所有内容都保留在内部。编辑器安装了一个AbstractFormatter,它永远不允许低于最小值或高于最大值,因此您永远没有机会对这些条件做出反应。由于拦截现有 AbstractFormatter 的行为几乎是不可能的,因此我只创建没有最小值或最大值的 JSpinner,并在 ChangeListener 中手动强制执行这些边界:private static JSpinner createSpinner() {&nbsp; &nbsp; double initialValue = 20;&nbsp; &nbsp; SpinnerModel model =&nbsp; &nbsp; &nbsp; &nbsp; new SpinnerNumberModel(initialValue, null, null, 1d);&nbsp; &nbsp; model.addChangeListener(e -> {&nbsp; &nbsp; &nbsp; &nbsp; double value = ((Number) model.getValue()).doubleValue();&nbsp; &nbsp; &nbsp; &nbsp; if (value < ALLOWABLE_MIN) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EventQueue.invokeLater(() -> model.setValue(ALLOWABLE_MIN));&nbsp; &nbsp; &nbsp; &nbsp; } else if (value > ALLOWABLE_MAX) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EventQueue.invokeLater(() -> model.setValue(ALLOWABLE_MAX));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; });&nbsp; &nbsp; return new JSpinner(model);}

慕虎7371278

您还可以更改的(AbstractFormatter通过自定义),如以下代码:JFormattedTextFieldDefaultEditorJSpinnerAbstractFormatterFactoryimport java.awt.Dimension;import java.text.ParseException;import java.util.Objects;import javax.swing.JButton;import javax.swing.JFormattedTextField;import javax.swing.JFormattedTextField.AbstractFormatter;import javax.swing.JFormattedTextField.AbstractFormatterFactory;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.JSpinner;import javax.swing.JSpinner.DefaultEditor;import javax.swing.SpinnerNumberModel;public class Main {&nbsp; &nbsp; public static class IntegerFormatter extends AbstractFormatter {&nbsp; &nbsp; &nbsp; &nbsp; private final int min, max;&nbsp; &nbsp; &nbsp; &nbsp; public IntegerFormatter(final int min, final int max) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.min = min;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.max = max;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public Object stringToValue(final String text) throws ParseException {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //This is where we compare for out of bounds values:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; final int val = Integer.parseInt(text);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (val < min)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return min;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (val > max)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return max;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return val;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; catch (final NumberFormatException nfx) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Find where in the string is the parsing error (so as to return ParseException accordingly).&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int i = 0;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (final int cp: text.codePoints().toArray()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!Character.isDigit(cp))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ParseException("Not a digit.", i);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ++i;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Should not happen:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new ParseException("Failed to parse input \"" + text + "\".", 0);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public String valueToString(final Object value) throws ParseException {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Objects.toString(value);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; public static class IntegerFormatterFactory extends AbstractFormatterFactory {&nbsp; &nbsp; &nbsp; &nbsp; private final int min, max;&nbsp; &nbsp; &nbsp; &nbsp; public IntegerFormatterFactory(final int min, final int max) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.min = min;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.max = max;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public AbstractFormatter getFormatter(final JFormattedTextField tf) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!(tf.getFormatter() instanceof IntegerFormatter))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return new IntegerFormatter(min, max);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return tf.getFormatter();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; public static void main(final String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; final SpinnerNumberModel model = new SpinnerNumberModel(0, -10, 10, 1);&nbsp; &nbsp; &nbsp; &nbsp; final JSpinner spin = new JSpinner(model);&nbsp; &nbsp; &nbsp; &nbsp; spin.setPreferredSize(new Dimension(100, 25));&nbsp; &nbsp; &nbsp; &nbsp; ((DefaultEditor) spin.getEditor()).getTextField().setFormatterFactory(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new IntegerFormatterFactory((Integer) model.getMinimum(), (Integer) model.getMaximum())&nbsp; &nbsp; &nbsp; &nbsp; );&nbsp; &nbsp; &nbsp; &nbsp; final JPanel contents = new JPanel(); //FlowLayout.&nbsp; &nbsp; &nbsp; &nbsp; contents.add(spin);&nbsp; &nbsp; &nbsp; &nbsp; contents.add(new JButton("Click me to change focus!"));&nbsp; &nbsp; &nbsp; &nbsp; final JFrame frame = new JFrame("Spinner out of bounds");&nbsp; &nbsp; &nbsp; &nbsp; frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);&nbsp; &nbsp; &nbsp; &nbsp; frame.getContentPane().add(contents);&nbsp; &nbsp; &nbsp; &nbsp; frame.pack();&nbsp; &nbsp; &nbsp; &nbsp; frame.setLocationRelativeTo(null);&nbsp; &nbsp; &nbsp; &nbsp; frame.setVisible(true);&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java