5

我在使用 JFormattedTextField 中的掩码时遇到问题

我知道它用空格或您通过 setPlaceholderCharacter 定义的任何字符替换无效字符,但我需要它做的是允许删除或退格,而不是插入空格代替我删除的字符,只要其余的掩码中允许使用字符串。

例如,使用掩码: *#*****,字符串"12 abc"是有效的。
如果将光标放在 b 和 c 字符之间,然后按退格键,我需要它来删除 b,结果是"12 ac". 相反,它会删除它,并添加一个空格,变成:"12 a c"

下面是一个简单的代码示例来演示。

我将不胜感激任何解决此问题的想法或示例。


public class testFrame extends javax.swing.JFrame {

    public testFrame() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(new java.awt.FlowLayout());

        setMinimumSize(new Dimension(300,150));

        java.awt.Button closeButton = new java.awt.Button();
        JFormattedTextField maskTextField = new JFormattedTextField();
        maskTextField.setMinimumSize(new Dimension(100,30));

        getContentPane().add(maskTextField);

        closeButton.setLabel("close");
        closeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                System.exit(0);
            }
        });

        getContentPane().add(closeButton);

        try {
            MaskFormatter someMask = new MaskFormatter("*#****");
            DefaultFormatterFactory formatterFactory 
                = new DefaultFormatterFactory(someMask);
            maskTextField.setFormatterFactory(formatterFactory);
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        maskTextField.setText("12 abc");

        pack();

    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {
                new testFrame().setVisible(true);
            }
        });
    }
}

更新代码以反映下面的答案。我添加了第二个字段,以便您可以查看有无修复的行为。也是一个小修复,我调整了窗口的大小并将其在屏幕中居中以使其更友好。

公共类 testFrame 扩展 javax.swing.JFrame {

public testFrame() {
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setMinimumSize(new java.awt.Dimension(300, 200));
    getContentPane().setLayout(new java.awt.FlowLayout());


    JFormattedTextField maskTextField = new JFormattedTextField();
    maskTextField.setMinimumSize(new Dimension(100,30));
    getContentPane().add(maskTextField);


    JFormattedTextField maskTextField2 = new JFormattedTextField();
    maskTextField2.setMinimumSize(new Dimension(100,30));
    getContentPane().add(maskTextField2);

    java.awt.Button closeButton = new java.awt.Button();
    closeButton.setLabel("close");
    closeButton.addActionListener(new java.awt.event.ActionListener() {

        public void actionPerformed(java.awt.event.ActionEvent evt) {
            System.exit(0);
        }
    });

    getContentPane().add(closeButton);

    try {

        MaskFormatter someMask = new MaskFormatter("*#****");
        DefaultFormatterFactory formatterFactory = 
            new DefaultFormatterFactory(someMask);
        maskTextField.setFormatterFactory(formatterFactory);

        MaskFormatter someMask2 = new MaskFormatter("*#****");
        DefaultFormatterFactory formatterFactory2 = 
            new DefaultFormatterFactory(someMask2);
        maskTextField2.setFormatterFactory(formatterFactory2);

    } catch (ParseException ex) {
        ex.printStackTrace();
    }

    maskTextField.setText("12 abc");
    maskTextField2.setText("12 abc");

    // added per suggestion below
    if (maskTextField.getFormatter() instanceof DefaultFormatter) {
         DefaultFormatter f = (DefaultFormatter) maskTextField.getFormatter();
         f.setAllowsInvalid(true);

         // options are: 
         // JFormattedTextField.COMMIT
         // JFormattedTextField.COMMIT_OR_REVERT  --> default
         // JFormattedTextField.REVERT
         // JFormattedTextField.PERSIST
         maskTextField.setFocusLostBehavior(JFormattedTextField.PERSIST);
    } 
    pack();
    this.setLocationRelativeTo(null);

}

public static void main(String args[]) {
    java.awt.EventQueue.invokeLater(new Runnable() {

        public void run() {
            new testFrame().setVisible(true);
        }
    });
}

}

4

2 回答 2

5

首先,感谢您发布一个体面的工作示例。

似乎DefaultFormatter是您的蒙面文本字段使用的格式化程序。我发现我可以通过以下方式允许临时无效编辑:

if (maskTextField.getFormatter() instanceof DefaultFormatter) {
  DefaultFormatter f = (DefaultFormatter) maskTextField.getFormatter();
  f.setAllowsInvalid(true);          
}

希望这足以让您入门。尽管请注意,如果您在字段中存在无效值时更改焦点,则此快速修复具有完全擦除文本字段内容的有趣行为。这似乎与JFormattedTextField暗示默认行为是COMMIT_OR_REVERT.

于 2012-08-01T07:14:23.913 回答
1

只是一个想法 - 绝对不适合生产,并且在一般情况下很可能不可能:您可以尝试包装默认 documentFilter 并在调用委托之前/之后调用自定义检查/操作。

这是一个似乎适用于您问题中的特定示例的片段:

public static class MyMaskFormatter extends MaskFormatter {

    DocumentFilter filter;

    /**
     * @param string
     * @throws ParseException
     */
    public MyMaskFormatter(String string) throws ParseException {
        super(string);
    }

    @Override
    protected DocumentFilter getDocumentFilter() {
        if (filter == null) {
            filter = new MyDocumentFilter(super.getDocumentFilter());
        }
        return filter;
    }

    public class MyDocumentFilter extends DocumentFilter {

        DocumentFilter delegate;

        MyDocumentFilter(DocumentFilter delegate) {
            this.delegate = delegate;
        }

        @Override
        public void remove(FilterBypass fb, int offset, int length)
                throws BadLocationException {
            String toRemove = fb.getDocument().getText(offset, length);
            delegate.remove(fb, offset, length);
            String replaced = fb.getDocument().getText(offset, length);
            if (replaced.charAt(0) == getPlaceholderCharacter() && 
                toRemove.charAt(0) != getPlaceholderCharacter()    ) {
                int sublength = fb.getDocument().getLength() - offset;
                String text = fb.getDocument().getText(offset, sublength);
                text = text.substring(1) + text.charAt(0);
                replace(fb, offset, sublength, text, null);
                getFormattedTextField().setCaretPosition(offset);
                //getNavigationFilter().setDot(fb, offset, null);
            }
        }

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

        @Override
        public void replace(FilterBypass fb, int offset, int length,
                String text, AttributeSet attrs)
                throws BadLocationException {
            delegate.replace(fb, offset, length, text, attrs);
        }

    }

}
于 2012-08-06T08:14:22.687 回答