【问题标题】:Java using KeyListener to check if parenthesis is pressedJava使用KeyListener检查是否按下了括号
【发布时间】:2015-10-18 03:46:21
【问题描述】:

我正在用 java 创建一个记事本程序,我想实现自动关闭大括号,包括 ()、[] 和 {}。现在我无法检测何时使用按键监听器按下左括号。

// called in the GUI create method
// passes in a JTextPane in the parameter
autoCloseBraces(txt);

private static void AutoCloseBraces(JTextPane txt) {

        txt.addKeyListener(new KeyListener() {

            @Override
            public void keyPressed(KeyEvent e) {

                ArrayList<Integer> keyCode = new ArrayList<Integer>();
                keyCode.add(e.getKeyCode());
                if (keyCode.contains(KeyEvent.VK_SHIFT) && keyCode.contains(KeyEvent.VK_9)) {

                    System.out.println("OK");

                }

            }

            @Override
            public void keyReleased(KeyEvent e) {

                if (e.getKeyCode() == KeyEvent.VK_9) {

                    System.out.println("OKKKKKK");

                }

            }

            @Override
            public void keyTyped(KeyEvent e) {

                if (e.getKeyCode() == KeyEvent.VK_9) {

                    System.out.println("OKK");

                }

            }

        });

    }

我也尝试过使用 KeyEvent.VK_LEFT_PARENTHESIS 代替 KeyEvent.VK_9,但似乎没有任何效果。当按下'('或'9'时,它就像只按下'9'。不知道这里发生了什么。我也尝试在谷歌搜索它的例子,但找不到任何东西。任何人都知道什么问题是或者我可以去哪里找到工作代码的解释或示例?

【问题讨论】:

标签: java swing keylistener parentheses


【解决方案1】:

根据您想要实现的目标,这既简单又复杂,但是首先,有一些“不要”:

  • 如果您打算修改字段的文本,请不要使用 KeyListener 或与文本组件的键绑定,当用户粘贴测试时,这些都不会通知
  • 不要使用DocumentListener,因为这会产生无限循环并导致Document 中的突变异常

好的,那么您应该使用什么?一个DocumentFilter,它允许您修改已传递到文本组件底层Document 中的文本。详情请见Implementing a Document Filter

下一个问题是,一般而言,作为用户,我希望您不修改光标的位置(除非我希望您这样做;))。现在,在这种情况下,插入 } 并将光标移到它的右侧是相当粗鲁的,因为现在我必须将光标移回,这只会破坏工作流程。

这是一个难题,因为DocumentFilter 不知道文本组件(也不应该),所以我们需要某种方式让过滤器告诉我们它即将应用更改并已应用更改.

为此,我们可以创建一个自定义的DocumentFilter,它具有一个监听器回调功能,它可以通知我们它即将应用“自动完成”更改并且已经完成了“自动完成”更改。这给了我们两个时间点,改变之前和之后,所以我们可以抓取我们需要的信息来控制光标...

public interface AutoCompleteListener {

    public void willAutoComplete(SyntaxFilter filter);

    public void didAutoComplete(SyntaxFilter filter);

}

public class SyntaxFilter extends DocumentFilter {

    private List<AutoCompleteListener> listeners;

    public SyntaxFilter() {
        listeners = new ArrayList<>(25);
    }

    public void addAutoCompleteListener(AutoCompleteListener listener) {
        listeners.add(listener);
    }

    public void removeAutoCompleteListener(AutoCompleteListener listener) {
        listeners.add(listener);
    }

    protected void fireWillAutoComplete() {
        for (AutoCompleteListener listener : listeners) {
            listener.willAutoComplete(this);
        }
    }

    protected void fireDidAutoComplete() {
        for (AutoCompleteListener listener : listeners) {
            listener.didAutoComplete(this);
        }
    }

    @Override
    public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
        super.replace(fb, offset, length, text, attrs); //To change body of generated methods, choose Tools | Templates.
        if (text.endsWith("{")) {
            fireWillAutoComplete();
            fb.insertString(fb.getDocument().getLength(), "}", attrs);
            fireDidAutoComplete();
        }
    }

}

现在,我可以想到几种控制光标位置的方法,您可以简单地在更改前获取当前位置并在更改后重置它,这会起作用,但您可能会发现它会产生一个小当光标在该位置移动时呈现轻弹。另一种方法是在发生更新时阻止光标移动,例如...

JTextArea editor = new JTextArea(10, 20);
SyntaxFilter filter = new SyntaxFilter();
filter.addAutoCompleteListener(new AutoCompleteListener() {
    private int updatePolicy = DefaultCaret.UPDATE_WHEN_ON_EDT;

    @Override
    public void willAutoComplete(SyntaxFilter filter) {
        updatePolicy = ((DefaultCaret) editor.getCaret()).getUpdatePolicy();
        ((DefaultCaret) editor.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
    }

    @Override
    public void didAutoComplete(SyntaxFilter filter) {
        ((DefaultCaret) editor.getCaret()).setUpdatePolicy(updatePolicy);
    }
});
((AbstractDocument) editor.getDocument()).setDocumentFilter(filter);

【讨论】:

    【解决方案2】:

    不完全确定您为什么使用ArrayList 的 keyCodes。当您在方法中初始化ArrayList 时,无论如何它只会包含一个值(e.getKeyCode() 的值)。如果您尝试使用组合键,理论上可以使用KeyListeners,但使用KeyBindings 会更好。

    关于标题问题:

    使用KeyListeners.的实际ASCII值

    对于左括号,keyCode 是 40(你可以在网上找到很多 ASCII 表,包括this 一个)。

    if(e.getKeyCode() == 40){
        //do something
    }
    

    【讨论】:

    • 当想要实时修改文本组件时,KeyListener 或键绑定或 DocumentListener 都不合适。如果用户将 txt 粘贴到字段中,并且 DocumentListener 不用于在执行期间修改字段的状态,则不会通知键输入 API 更改字段,而是适合使用 DocumentFilter
    • @MadProgrammer 这是正确的。抱歉,我没有意识到正在创建的程序涉及可编辑的文本字段。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多