5

JFormattedTextField のマスクに問題があります

無効な文字をスペースまたは setPlaceholderCharacter で定義したものに置き換えることは理解していますが、必要なのは削除またはバックスペースを許可することであり、削除した文字の代わりにスペースを挿入しないことです。文字列はマスクで許可されます。

たとえば、 mask:*#*****の場合、文字列"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);
            }
        });
    }
}

以下の回答を反映するようにコードを更新します。2 番目のフィールドを追加して、修正の有無にかかわらず動作を確認できるようにしました。また、マイナーな修正として、ウィンドウのサイズを変更し、画面の中央に配置して、より使いやすくしました。

public class testFrame extends 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 に答える