关闭 JPopupMenu 时,通过按键操作。

huangapple go评论72阅读模式
英文:

Close JPopupMenu on Keystroke

问题

我正在创建一个工具,用于自动完成Processing IDE的文本,它是Java的定制版本。以下是弹出的弹出菜单类,用于呈现不同的填充选项:

class Entry extends JPopupMenu implements KeyListener{

    private JEditTextArea parent;

    public Entry(String word, JEditTextArea _parent) {
        super();
        parent = _parent;
        parent.add(this);

        parent.addKeyListener(this);

        add(word);
    }

    public void show(int x, int y) {
        super.show(parent, x, y);
    }

    public void keyPressed(KeyEvent key) {
        setVisible(false);
        setEnabled(false);
    }

    public void keyReleased(KeyEvent key) {}

    public void keyTyped(KeyEvent key) {}
}

父类是一个JEditTextArea,据我所知,它与swing包中的JTextArea大部分功能相同。word参数只是开始输入的单词,作为稍后在代码中查找匹配完成的模式。

问题是,一旦弹出菜单打开,它会阻止进一步输入新字符,你必须通过按ESC键手动关闭它。我尝试将其设置为KeyListener,并在按键时关闭它,但迄今为止没有成功。我还尝试让它在任何按键时打印出简单的消息,但无论我尝试什么,都无法让它对任何形式的键盘输入作出反应。有没有办法让它在接收到按键时关闭?

~Okaghana

英文:

I'm creating a tool to autocomplete Text for the Processing IDE, a customized version of Java. The following class Is the popup-menu that pops up to present the different fill-in possibilities:

class Entry extends JPopupMenu implements KeyListener{

    private JEditTextArea parent;
    
    public Entry(String word, JEditTextArea _parent) {
        super();
        parent = _parent;
        parent.add(this);
        
        parent.addKeyListener(this);
        
        add(word);
    }
    
    public void show(int x, int y) {
        super.show(parent, x, y);
    }
    
    public void keyPressed(KeyEvent key) {
        setVisible(false);
        setEnabled(false);
    }
    
    public void keyReleased(KeyEvent key) {}

    public void keyTyped(KeyEvent key) {}
}

The parent is a JEditTextArea, that afaik shares most of its functionality with the JTextArea from the swing package. The word parameter is just the word that was started being typed, as a pattern to find a fitting completion later in the code.

The problem is, that as soon as the popup opens it blocks the further input of new characters and you have to manually close it by pressing ESC. I tried to make it a KeyListener and make it close on a keystroke, but had no success so far. I also tries to let it print a simple message on any keystroke, but whatever I try, I can't convince it to react to any form of a key input. Is there a way I can make it close on an incoming keystroke?

~Okaghana

答案1

得分: 1

以下是您提供的代码的翻译部分:

import javax.swing.*;
import java.awt.event.*;

public class Main {
    public static void main(String[] args) {
        // 创建元素
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        JButton button = new JButton("点击我!");
        JPopupMenu menu = new JPopupMenu("菜单");
        menu.add("A");
        menu.add("B");
        menu.add("C");

        // 在按钮点击时打开菜单
        button.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                menu.show(button, button.getWidth() / 2, button.getHeight() / 2);
            }
        });

        // 在按下CTRL+X时关闭菜单
        frame.addKeyListener(new KeyListener() {
            @Override
            public void keyPressed(KeyEvent e) {
                // 参见 https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#setVisible-boolean-
                // 参见 https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#isVisible--
                if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_X && menu.isVisible()) {
                    menu.setVisible(false);
                }
            }

            @Override
            public void keyTyped(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
            }
        });

        // 将所有内容放在一起
        panel.add(button);
        frame.add(panel);
        frame.setSize(300, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

这段代码出现问题的原因是键盘监听器被添加到了 JFrame 上。当按钮被按下并且菜单打开时,菜单获得了焦点,因此键盘监听器不起作用。

可以通过添加以下代码来解决这个问题:

// 这是解决的关键
button.setFocusable(false);
menu.setFocusable(false);

如果您不想这样做,而是只想将 KeyListener 添加到 JPopupMenu 上,可以使用以下方法:

// 在按钮点击时打开菜单
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        menu.show(button, button.getWidth() / 2, button.getHeight() / 2);
        menu.requestFocus();
    }
});

// 在按下CTRL+X时关闭菜单
menu.addKeyListener(new KeyListener() {
    @Override
    public void keyPressed(KeyEvent e) {
        // 参见 https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#setVisible-boolean-
        // 参见 https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#isVisible--
        if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_X && menu.isVisible()) {
            menu.setVisible(false);
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
});

关键在于在菜单打开时为其设置焦点(在按钮的 actionlistener 中):

menu.requestFocus();
英文:

I couldn't really work with the class you provided, because there are some classes missing. So I just created this minimal working example, I hope it illustrates your problem:

import javax.swing.*;
import java.awt.event.*;

public class Main {
	public static void main(String[] args) {
		//Creating elements
		JFrame frame = new JFrame();
		JPanel panel = new JPanel();
		JButton button = new JButton("click me!");
		JPopupMenu menu = new JPopupMenu("Menu");
		menu.add("A");
	    menu.add("B");
	    menu.add("C");	

		//Open menu on button-click
	    button.addActionListener( new ActionListener() {
	        public void actionPerformed(ActionEvent e) {
	            menu.show(button, button.getWidth()/2, button.getHeight()/2);
	        }
	    });

	    //Close menu on CTRL+X
	    frame.addKeyListener(new KeyListener(){
         	@Override
            public void keyPressed(KeyEvent e) {
            	//See https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#setVisible-boolean-
            	//See https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#isVisible--
                if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_X && menu.isVisible()) {
                	menu.setVisible(false);
                }
            }

            @Override
            public void keyTyped(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
            }
        });

        //Putting everything together
	    panel.add(button);
	    frame.add(panel);
	    frame.setSize(300,300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	    
		frame.setVisible(true);
	}
}

This isn't working because the keylistener is added to the JFrame. When the button is pressed and the menu opens, the menu gains focus and therefore the keylistener doesn't work.

This problem can be solved by adding the following lines to the code:

//this is doing the trick
button.setFocusable(false);
menu.setFocusable(false);

If you don't want to do this and want to add the KeyListener only to the JPopupMenu, then you can do this:

//Open menu on button-click
button.addActionListener( new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        menu.show(button, button.getWidth()/2, button.getHeight()/2);
        menu.requestFocus();
    }
});

//Close menu on CTRL+X
menu.addKeyListener(new KeyListener(){
 	@Override
    public void keyPressed(KeyEvent e) {
    	//See https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#setVisible-boolean-
    	//See https://docs.oracle.com/javase/8/docs/api/javax/swing/JPopupMenu.html#isVisible--
        if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_X && menu.isVisible()) {
        	menu.setVisible(false);
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
});

The trick here is to set the focus on the menu once it is open (in the actionlistener for the button):

menu.requestFocus();

huangapple
  • 本文由 发表于 2020年9月20日 21:47:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/63979634.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定