Java JSpinner with SpinnerNumberModel:是否对输入的数字进行验证?

Java JSpinner with SpinnerNumberModel:是否对输入的数字进行验证?,java,swing,jspinner,Java,Swing,Jspinner,我们的目标是拥有这样一个JSpinner: SpinnerNumberModel(1650, 1650, 2100, 10); setEditable(true); setFocusable(true); 它还应该只接受数值​​在1650-2100范围内。如果该值不在此范围内,请设置默认值(1650)。目前,我的代码只允许我输入4位数字,但它们超出了范围。我读过很多类似的问题,但在Jspinner中没有找到一个限制输入数字的主题 public class MySpinner extends J

我们的目标是拥有这样一个JSpinner:

SpinnerNumberModel(1650, 1650, 2100, 10);
setEditable(true);
setFocusable(true);
它还应该只接受数值​​在1650-2100范围内。如果该值不在此范围内,请设置默认值(1650)。目前,我的代码只允许我输入4位数字,但它们超出了范围。我读过很多类似的问题,但在Jspinner中没有找到一个限制输入数字的主题

public class MySpinner extends JSpinner {
    int defValue;
    int minimum;
    int maximum;
    int stepSize;

    public MySpinner(int defValue, int minimum, int maximum, int stepSize) {
        this.defValue = defValue; //1650
        this.minimum = minimum;   //1650
        this.maximum = maximum;   //2100
        this.stepSize = stepSize; //10
        SpinnerNumberModel spinnerNumberModel = new SpinnerNumberModel(defValue, minimum, maximum, stepSize);
        setModel(spinnerNumberModel);
        setBorder(new EmptyBorder(0, 0, 0, 0));

        JSpinner.NumberEditor numberEditor = ((JSpinner.NumberEditor) this.getEditor());
        numberEditor.getTextField().setEnabled(true);
        numberEditor.getTextField().setEditable(true);
        numberEditor.getFormat().setMaximumFractionDigits(4);

        JFormattedTextField textField = numberEditor.getTextField();
        ((NumberFormatter) textField.getFormatter()).setAllowsInvalid(false);
        NumberFormatter formatter = (NumberFormatter) textField.getFormatter();
        DecimalFormat decimalFormat = new DecimalFormat("0");
        formatter.setFormat(decimalFormat);

        final Document jsDoc = numberEditor.getTextField().getDocument();
        if (jsDoc instanceof PlainDocument) {
            AbstractDocument doc = new PlainDocument() {
                private static final long serialVersionUID = 1L;

                @Override
                public void setDocumentFilter(DocumentFilter filter) {
                    if (filter instanceof MyDocumentFilter) {
                        super.setDocumentFilter(filter);
                    }
                }
            };
            doc.setDocumentFilter(new MyDocumentFilter());
            numberEditor.getTextField().setDocument(doc);
        }
    }

    public static class MyDocumentFilter extends DocumentFilter {

        @Override
        public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
            if (stringContainsOnlyDigits(string)) {
                super.insertString(fb, offset, string, attr);
            }
        }

        @Override
        public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
            super.remove(fb, offset, length);
        }

        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
            int currentLength = fb.getDocument().getLength();
            int overLimit = (currentLength + text.length()) - 4 - length;
            if (overLimit > 0) {
                text = text.substring(0, text.length() - overLimit);
            }
            if (stringContainsOnlyDigits(text)) {
                super.replace(fb, offset, length, text, attrs);
            }
        }

        private boolean stringContainsOnlyDigits(String text) {

            for (int i = 0; i < text.length(); i++) {
                if (!Character.isDigit(text.charAt(i))) {
                    return false;
                }
            }
            return true;
        }
    }
}
公共类MySpinner扩展了JSpinner{
int-def值;
最小整数;
int最大值;
整数步长;
公共MySpinner(int defValue、int minimum、int maximum、int stepSize){
this.defValue=defValue;//1650
this.minimum=minimum;//1650
this.max=max;//2100
this.stepSize=stepSize;//10
喷丝头NumberModel喷丝头NumberModel=新喷丝头NumberModel(定义值、最小值、最大值、步长);
setModel(喷丝头编号模型);
setboorder(新的EmptyBorder(0,0,0,0));
JSpinner.numberditor numberditor=((JSpinner.numberditor)this.getEditor());
numberditor.getTextField().setEnabled(true);
numberditor.getTextField().setEditable(true);
numberditor.getFormat().setMaximumFractionDigits(4);
JFormattedTextField textField=numberditor.getTextField();
((NumberFormatter)textField.getFormatter()).setAllowsInvalid(false);
NumberFormatter formatter=(NumberFormatter)textField.getFormatter();
DecimalFormat DecimalFormat=新的DecimalFormat(“0”);
setFormat(十进制格式);
最终文档jsDoc=numberditor.getTextField().getDocument();
if(普通文档的jsDoc实例){
AbstractDocument文档=新的PlainDocument(){
私有静态最终长serialVersionUID=1L;
@凌驾
公共void setDocumentFilter(DocumentFilter筛选器){
if(MyDocumentFilter的筛选器实例){
super.setDocumentFilter(过滤器);
}
}
};
doc.setDocumentFilter(新的MyDocumentFilter());
numberditor.getTextField().setDocument(doc);
}
}
公共静态类MyDocumentFilter扩展了DocumentFilter{
@凌驾
public void insertString(FilterBypass fb,int offset,String String,AttributeSet attr)引发BadLocationException{
if(stringContainsOnlyDigits(字符串)){
super.insertString(fb,offset,string,attr);
}
}
@凌驾
公共void remove(FilterBypass fb,int offset,int length)引发BadLocationException{
超级。删除(fb、偏移、长度);
}
@凌驾
public void replace(FilterBypass fb、int offset、int length、字符串文本、AttributeSet attrs)引发BadLocationException{
int currentLength=fb.getDocument().getLength();
int overLimit=(currentLength+text.length())-4-长度;
如果(超限>0){
text=text.substring(0,text.length()-overLimit);
}
if(stringContainsOnlyDigits(text)){
super.replace(fb、偏移量、长度、文本、属性);
}
}
私有布尔字符串containsOnlyDigits(字符串文本){
对于(int i=0;i

也许我的代码中有很多不必要的东西。我很乐意接受任何建议。提前谢谢。

您可以键入任何号码。一旦焦点丢失,将编辑该值。如果输入的值无效,它将被重置为最后一个有效值。“也许我的代码中有很多不必要的东西。”询问
JSpinner
的行为如何?肯定但也有一些“缺失的部分”允许我们运行和实验代码:主方法、导入等。为了更快地获得更好的帮助,可以添加一个或。在
JOptionPane
@camickr中显示微调器需要大约20-30行代码,您是对的。这种行为很好。我在代码中发现了一个新问题。当我运行应用程序时,JSpinner总是在一开始就集中精力。JFrame还有很多其他组件(按钮、组合框、复选框),它们都设置为setFocusable(false)和setOrderPaint(false);因为我不需要他们被突出显示,如果他们做了一些行动。但spinner的这种行为很奇怪,我只想在应用程序开始运行时spinner不在焦点上。@camickr我试过做这个把戏,并将焦点设置为随机按钮,但现在spinner不在焦点上,但是微调器JFormattedTextField中的值消失了,当我单击微调器文本字段时,该值会一直显示到应用程序运行结束。我做错了什么?如果其他组件处于焦点位置,是否有任何技巧可以使微调器文本可见?我在使用微调器时从来没有遇到过问题。如果没有正确的答案,我看不到描述的行为,也猜不出问题出在哪里。