为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Helenr 2023-03-23 14:15:47
我有一个 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);               } }              });
查看完整描述

3 回答

?
慕斯709654

TA贡献1840条经验 获得超5个赞

这是我能够使用 FocusListener 开始工作的解决方案,尽管我不确定它的正确性。


private JFormattedTextField tf = ((JSpinner.DefaultEditor) jSpinnerTiming.getEditor()).getTextField();

((JSpinner.DefaultEditor)jSpinnerTiming.getEditor()).getTextField().addFocusListener(new  FocusListener() {


            @Override

            public void focusLost(FocusEvent e) {

                // The unchecked user input value 

                double dirtyValue = Double.parseDouble(tf.getText());


                // Get Minimum and Maximum values from jSpinner's Model 

                double max = (Double) ((SpinnerNumberModel) jSpinnerTiming.getModel()).getMaximum();//MAX_ALLOWED_RATE

                double min = (Double) ((SpinnerNumberModel) jSpinnerTiming.getModel()).getMinimum();//LOWEST_ALLOWABLE_RATE;


                if (dirtyValue > max) { 

                    jSpinnerTiming.setValue(max);

                } else if(dirtyValue < min){

                    jSpinnerTiming.setValue(min);

                } 

            }

            @Override

            public void focusGained(FocusEvent e) {

                // TODO Auto-generated method stub

            }

        });


查看完整回答
反对 回复 2023-03-23
?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

问题是 JSpinner 将所有内容都保留在内部。编辑器安装了一个AbstractFormatter,它永远不允许低于最小值或高于最大值,因此您永远没有机会对这些条件做出反应。


由于拦截现有 AbstractFormatter 的行为几乎是不可能的,因此我只创建没有最小值或最大值的 JSpinner,并在 ChangeListener 中手动强制执行这些边界:


private static JSpinner createSpinner() {


    double initialValue = 20;


    SpinnerModel model =

        new SpinnerNumberModel(initialValue, null, null, 1d);


    model.addChangeListener(e -> {

        double value = ((Number) model.getValue()).doubleValue();

        if (value < ALLOWABLE_MIN) {

            EventQueue.invokeLater(() -> model.setValue(ALLOWABLE_MIN));

        } else if (value > ALLOWABLE_MAX) {

            EventQueue.invokeLater(() -> model.setValue(ALLOWABLE_MAX));

        }

    });


    return new JSpinner(model);

}


查看完整回答
反对 回复 2023-03-23
?
慕虎7371278

TA贡献1802条经验 获得超4个赞

您还可以更改的(AbstractFormatter通过自定义),如以下代码:JFormattedTextFieldDefaultEditorJSpinnerAbstractFormatterFactory


import 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 {


    public static class IntegerFormatter extends AbstractFormatter {

        private final int min, max;


        public IntegerFormatter(final int min, final int max) {

            this.min = min;

            this.max = max;

        }


        @Override

        public Object stringToValue(final String text) throws ParseException {

            try {

                //This is where we compare for out of bounds values:

                final int val = Integer.parseInt(text);

                if (val < min)

                    return min;

                if (val > max)

                    return max;

                return val;

            }

            catch (final NumberFormatException nfx) {

                //Find where in the string is the parsing error (so as to return ParseException accordingly).

                int i = 0;

                for (final int cp: text.codePoints().toArray()) {

                    if (!Character.isDigit(cp))

                        throw new ParseException("Not a digit.", i);

                    ++i;

                }

                //Should not happen:

                throw new ParseException("Failed to parse input \"" + text + "\".", 0);

            }

        }


        @Override

        public String valueToString(final Object value) throws ParseException {

            return Objects.toString(value);

        }

    }


    public static class IntegerFormatterFactory extends AbstractFormatterFactory {

        private final int min, max;


        public IntegerFormatterFactory(final int min, final int max) {

            this.min = min;

            this.max = max;

        }


        @Override

        public AbstractFormatter getFormatter(final JFormattedTextField tf) {

            if (!(tf.getFormatter() instanceof IntegerFormatter))

                return new IntegerFormatter(min, max);

            return tf.getFormatter();

        }

    }


    public static void main(final String[] args) {

        final SpinnerNumberModel model = new SpinnerNumberModel(0, -10, 10, 1);

        final JSpinner spin = new JSpinner(model);

        spin.setPreferredSize(new Dimension(100, 25));


        ((DefaultEditor) spin.getEditor()).getTextField().setFormatterFactory(

                new IntegerFormatterFactory((Integer) model.getMinimum(), (Integer) model.getMaximum())

        );


        final JPanel contents = new JPanel(); //FlowLayout.

        contents.add(spin);

        contents.add(new JButton("Click me to change focus!"));


        final JFrame frame = new JFrame("Spinner out of bounds");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane().add(contents);

        frame.pack();

        frame.setLocationRelativeTo(null);

        frame.setVisible(true);

    }

}



查看完整回答
反对 回复 2023-03-23
  • 3 回答
  • 0 关注
  • 160 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信