【问题标题】:How to remove content of JTextField while DocumentListener is running?DocumentListener 运行时如何删除 JTextField 的内容?
【发布时间】:2020-06-03 15:30:58
【问题描述】:

对于以下代码,我收到 IllegalStateException(尝试在通知中变异):

private class DocumentHandler implements DocumentListener {
    public void changedUpdate(DocumentEvent ev) {
        // unused
    }
    public void insertUpdate(DocumentEvent ev) {    
        if(textInput.getText().equals("...")) {
        JOptionPane.showMessageDialog(null, "...");
        textInput.setText("");
    }
}

为什么我不能在 DocumentListener 处于活动状态时更改 TextField?

我试图在 TextField 设置为“”时删除 DocumentListener,但这根本没有帮助。 我知道以前有人问过一个非常相似的问题,但我没有得到那个答案......

谢谢

【问题讨论】:

    标签: java swing jtextfield illegalstateexception documentlistener


    【解决方案1】:

    一般来说,您不会在使用 DocumentListener 的同时收听 Document 的状态。我知道的两种可能的解决方案:

    • 从您的侦听器中,将进行您希望进行的更改的代码放入 Runnable 中,并通过调用 SwingUtilities.invokeLater(yourRunnable) 将 Runnable 排队到 Swing 事件线程中。这是一个无耻的混蛋
    • 更好:不要使用 DocumentListener 而是使用 DocumentFilter,因为这种类型的侦听器适用于在文本在组件中可视化之前对 Document 进行更改。

    不相关的附带问题:您的代码显示出令人担忧的耦合程度,因为您尝试从侦听器中更改特定文本组件中的文本。 DocumentListeners 应该完全不知道他们收听的文档的文本组件,实际上可以添加到多个文档中。


    一个 DocumentFilter 有 3 个方法需要被覆盖并做你期望它们做的事情:你期望它们做的事情:

    • insertString:在文档中插入一个字符串
    • remove:从文档中删除文本
    • replace:替换文档中的文字

    更重要的是,这些方法文本组件呈现文档更改之前执行它们的操作。

    所以在我的方法覆盖中,我提取了当前文档的文本,并使用参数来创建新文本的外观,例如我所做的替换方法:

    @Override
    public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
            throws BadLocationException {
        String currentText = fb.getDocument().getText(0, fb.getDocument().getLength());
        StringBuilder sb = new StringBuilder(currentText);
    
        String newText = sb.replace(offset, offset + length, text).toString();
    

    然后我对 newText 做一个布尔测试,看它是否“好”,如果是,则调用 super 的方法,这里是 replace(...),传入所有参数。如果没有,如果 newText 没有通过测试,那么我会从文档中删除所有文本并显示一个 JOptionPane。

    所以在这个例子中,我用这个作为我的测试方法:

    private boolean isTextOk(String text) {
        return !BAD_TEXTS.contains(text);
    }
    

    它测试文本是否是任何不允许的字符串,这里是"...", " ", "oops", "OOPS",但它可以是您想要的任何字符串。同样,如果文本通过文本,则调用 super 的方法,否则删除文本:

    if (isTextOk(newText)) {
        super.replace(fb, offset, length, text, attrs);
    } else {
        badText(fb);
    }
    

    badText(fb) 在哪里:

    private void badText(FilterBypass fb) throws BadLocationException {
        remove(fb, 0, fb.getDocument().getLength());
        JOptionPane.showMessageDialog(null, "Don't do this!", "Bad Text Entered",
                JOptionPane.WARNING_MESSAGE);
    }
    

    整个例子是:

    import java.util.Arrays;
    import java.util.List;
    import javax.swing.*;
    import javax.swing.text.AttributeSet;
    import javax.swing.text.BadLocationException;
    import javax.swing.text.DocumentFilter;
    import javax.swing.text.PlainDocument;
    
    @SuppressWarnings("serial")
    public class ClearThreeDots extends JPanel {
        private JTextField textField = new JTextField(40);
    
        public ClearThreeDots() {
            ((PlainDocument) textField.getDocument()).setDocumentFilter(new MyDocFilter());
            add(textField);
        }
    
        private static void createAndShowGui() {
            ClearThreeDots mainPanel = new ClearThreeDots();
    
            JFrame frame = new JFrame("Clear Three Dots");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    
    class MyDocFilter extends DocumentFilter {
        private static final List<String> BAD_TEXTS = Arrays.asList("...", "   ", "oops", "OOPS");
    
        @Override
        public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
                throws BadLocationException {
            String currentText = fb.getDocument().getText(0, fb.getDocument().getLength());
            StringBuilder sb = new StringBuilder(currentText);
    
            String newText = sb.insert(offset, string).toString();
    
            if (isTextOk(newText)) {
                super.insertString(fb, offset, string, attr);
            } else {
                badText(fb);
            }
        }
    
        @Override
        public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
            String currentText = fb.getDocument().getText(0, fb.getDocument().getLength());
            StringBuilder sb = new StringBuilder(currentText);
    
            String newText = sb.replace(offset, offset + length, "").toString();
    
            if (isTextOk(newText)) {
                super.remove(fb, offset, length);
            } else {
                badText(fb);
            }
    
        }
    
        @Override
        public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
                throws BadLocationException {
            String currentText = fb.getDocument().getText(0, fb.getDocument().getLength());
            StringBuilder sb = new StringBuilder(currentText);
    
            String newText = sb.replace(offset, offset + length, text).toString();
    
            if (isTextOk(newText)) {
                super.replace(fb, offset, length, text, attrs);
            } else {
                badText(fb);
            }
    
        }
    
        private boolean isTextOk(String text) {
            return !BAD_TEXTS.contains(text);
        }
    
        private void badText(FilterBypass fb) throws BadLocationException {
            remove(fb, 0, fb.getDocument().getLength());
            JOptionPane.showMessageDialog(null, "Don't do this!", "Bad Text Entered",
                    JOptionPane.WARNING_MESSAGE);
        }
    
    }
    

    【讨论】:

    猜你喜欢
    • 2011-01-18
    • 2013-10-11
    • 2013-05-23
    • 2013-02-16
    • 2013-03-10
    • 2016-10-13
    • 2016-04-25
    • 2012-10-25
    • 2017-07-16
    相关资源
    最近更新 更多