Java使用KeyListener检查是否按下了括号

时间:2015-07-27 19:44:09

标签: java swing keylistener parentheses

我在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但似乎没有任何效果。当按下&#39;(&#39;或&#39; 9&#39;)时,它就好像只按了&#39; 9&#39;按下了。不确定这里发生了什么。我和#39;还尝试搜索谷歌的例子,但无法找到任何内容。有人知道问题是什么,或者我可以去哪里找到工作代码的解释或示例?

2 个答案:

答案 0 :(得分:2)

根据你想要达到的目标,这既简单又复杂,但首先是一些“不要”:

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

好的,那你应该怎么用?一个DocumentFilter,它允许您修改已传递到文本组件的基础Document的文本。有关详细信息,请参阅Implementing a Document Filter

下一个问题是,一般来说作为用户,如果你没有修改我的光标位置(除非我想要你),我更喜欢。)。现在,在这种情况下,插入一个}并让光标移动到它的右侧是相当粗鲁的,因为现在我必须将光标向后移动,这只会打破工作流程。 / p>

这是一个难题,因为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();
        }
    }

}

现在,有几种方法我可以想到控制光标位置,您可以简单地在更改之前获取当前位置并在更改后重置它,这将起作用,但您可能会发现它会生成一个小的当光标绕着这个地方晃动时渲染一下。另一种方法是简单地在发生更新时停止光标移动,例如......

Helloworld

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);

答案 1 :(得分:0)

不完全确定您使用ArrayList密码的原因。在初始化方法中的ArrayList时,它只会包含一个值(e.getKeyCode()的值)。如果您尝试使用密钥组合,理论上可以使用KeyListeners,但使用KeyBindings要好得多。

至于标题问题:

将实际ASCII值与KeyListeners.

一起使用

对于左括号,keyCode为40(您可以在互联网上找到许多ASCII表,包括this一个)。

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