Java 使用TextComponents的GUI中的Swing键问题(箭头键、选项卡等)

Java 使用TextComponents的GUI中的Swing键问题(箭头键、选项卡等),java,swing,keyevent,Java,Swing,Keyevent,我想将箭头键绑定到整个窗口的某些特定操作(无论哪个组件被聚焦)。我特别想用箭头键移动JList中的选择栏。我的窗口包含一个JTextArea和不同的JScrollPanes 我猜会出现以下问题:当我更改列表选择时,textarea会获得焦点(这取决于我想要实现的逻辑)。当JTextArea或JScrollPane具有焦点时,所有向上箭头等关键事件“丢失”(或者更确切地说,只影响TextComponent/Pane) 下面是一个小示例,它演示了问题: import java.awt.BorderL

我想将箭头键绑定到整个窗口的某些特定操作(无论哪个组件被聚焦)。我特别想用箭头键移动JList中的选择栏。我的窗口包含一个JTextArea和不同的JScrollPanes

我猜会出现以下问题:当我更改列表选择时,textarea会获得焦点(这取决于我想要实现的逻辑)。当JTextArea或JScrollPane具有焦点时,所有向上箭头等关键事件“丢失”(或者更确切地说,只影响TextComponent/Pane)

下面是一个小示例,它演示了问题:

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class KeyProblemExample extends JFrame implements ListSelectionListener {

private JList<Integer> list;
private JTextArea textArea;
private JLabel label;

public KeyProblemExample() 
{
    Font font = new Font("Dialog", Font.PLAIN, 20);
    Integer[] listValues = {1, 2, 3};
    list = new JList<>(listValues);
    list.setFixedCellWidth(50);
    list.setFont(font);
    textArea = new JTextArea();
    textArea.setEditable(false);
    textArea.setLineWrap(true);
    String text = Stream.generate(()-> "xyz").limit(300).collect(Collectors.joining());
    textArea.setText(text);
    textArea.setFont(font);
    label = new JLabel("bla bla bla");
    label.setFont(font);
}


private void buildLogic() 
{
    //list selection listener
    list.addListSelectionListener(this);
    //up and down keys
    AbstractAction down = new AbstractAction() {    
        @Override
        public void actionPerformed(ActionEvent e) {
            if (list.getSelectedIndex() >= 0 && list.getSelectedIndex() < list.getModel().getSize() - 1)
                list.setSelectedIndex(list.getSelectedIndex() + 1);
        }
    };
    AbstractAction up = new AbstractAction() {  
        @Override
        public void actionPerformed(ActionEvent e) {
            if (list.getSelectedIndex() >= 1 && list.getSelectedIndex() < list.getModel().getSize())
                list.setSelectedIndex(list.getSelectedIndex() - 1);
        }
    };
    KeyStroke keyDown = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.ALT_MASK);
    label.getActionMap().put("indexDown", down);
    label.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyDown, "indexDown"); 
    KeyStroke keyUp = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
    label.getActionMap().put("indexUp", up);
    label.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyUp, "indexUp");
}


private void displayGUI() 
{
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);       
    JPanel panel = new JPanel(new BorderLayout());
    JScrollPane sp1 = new JScrollPane();
    sp1.setViewportView(textArea);
    sp1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
    sp1.setWheelScrollingEnabled(true);
    JScrollPane sp2 = new JScrollPane();
    sp2.setViewportView(list);
    sp2.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
    sp2.setWheelScrollingEnabled(true);
    panel.add(sp1, BorderLayout.CENTER);
    panel.add(sp2, BorderLayout.EAST);
    panel.add(label, BorderLayout.SOUTH);
    this.getContentPane().add(panel);      
    this.pack();
    this.setSize(400,400);
    this.setLocationByPlatform(true);
    this.setVisible(true);
}


@Override
public void valueChanged(ListSelectionEvent e) {
    textArea.requestFocus();
//  label.requestFocus();
}


public static void main(String[] args) {
    Runnable r = new Runnable() {
        @Override
        public void run() {
            KeyProblemExample x = new KeyProblemExample();
            x.buildLogic();
            x.displayGUI();
        }
    };
    SwingUtilities.invokeLater(r);
}

}
导入java.awt.BorderLayout;
导入java.awt.Font;
导入java.awt.event.ActionEvent;
导入java.awt.event.KeyEvent;
导入java.util.stream.collector;
导入java.util.stream.stream;
导入javax.swing.AbstractAction;
导入javax.swing.JComponent;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JList;
导入javax.swing.JPanel;
导入javax.swing.JScrollPane;
导入javax.swing.JTextArea;
导入javax.swing.KeyStroke;
导入javax.swing.ScrollPaneConstants;
导入javax.swing.SwingUtilities;
导入javax.swing.event.ListSelectionEvent;
导入javax.swing.event.ListSelectionListener;
公共类KeyProblemExample扩展JFrame实现ListSelectionListener{
私人名单;
私人JTEXTEXTAREA textArea;
私人标签;
公钥问题示例()
{
Font Font=新字体(“对话框”,Font.PLAIN,20);
整数[]listValues={1,2,3};
列表=新的JList(列表值);
列表。设置固定单元格宽度(50);
list.setFont(字体);
textArea=新的JTextArea();
textArea.setEditable(false);
textArea.setLineWrap(true);
String text=Stream.generate(()->“xyz”).limit(300.collect(Collectors.joining());
textArea.setText(text);
textArea.setFont(字体);
标签=新的JLabel(“bla bla bla”);
label.setFont(字体);
}
私有void buildLogic()
{
//列表选择侦听器
list.addListSelectionListener(此);
//上下键
AbstractAction down=新建AbstractAction(){
@凌驾
已执行的公共无效操作(操作事件e){
如果(list.getSelectedIndex()>=0&&list.getSelectedIndex()=1&&list.getSelectedIndex()
在本例中,Alt ArrowDown命令起作用,而普通ArrowUp命令不起作用。如果我更改
requestFocus()
行,以便标签请求焦点,则ArrowUp也可以工作(因为现在标签而不是文本区域获得焦点)


我的问题:如何将箭头键等“窗口范围”键绑定到特定操作(特别是如果我的窗口中有文本组件)。

文本组件的键绑定在有焦点时优先。因此,您需要使用以下代码从文本组件中删除绑定:

textComponent.getInputMap().put(KeyStroke.getKeyStroke("UP"), "none");

有关更多信息,请参阅Swing教程中的部分。

文本组件的键绑定在具有焦点时优先。因此,您需要使用以下代码从文本组件中删除绑定:

textComponent.getInputMap().put(KeyStroke.getKeyStroke("UP"), "none");

有关更多信息,请参阅Swing教程中的部分。

谢谢@camickr,问题可以通过您的提示解决

。。。以下是一些进一步的信息/解决方案:

  • 禁用整个组件类型的关键操作(如camickr中所述):

    这将禁用所有
    TextArea
    ScrollPane
    组件的向上和向下箭头键输入(在调用此命令之前,必须实例化每种类型的一个对象)

  • 通过
    KeyEventDispatcher
    禁用整个窗口的按键:

    KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
    manager.addKeyEventDispatcher(new KeyEventDispatcher() {
        @Override
        public boolean dispatchKeyEvent(KeyEvent e) {
            if (e.getID() == KeyEvent.KEY_PRESSED) {
                int keyCode = e.getKeyCode();
                if (keyCode == KeyEvent.VK_DOWN) {
                    //doAction
                    return true;
                }
                else if (keyCode == KeyEvent.VK_UP) {
                    //doAction
                    return true;
                }   
            }
            return false;
        }
    });
    
    这将分别对按下“窗口宽度”的上箭头和下箭头键执行“doAction”命令。由于该方法在这两种情况下都返回true,因此键事件将不会被分派到其他组件,因此该键将得到d