java - Swing - 使用 TextComponents 的 GUI 中的关键问题(箭头键、Tab 等)

标签 java swing keyevent

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

我猜想会发生以下问题:当我更改列表选择时,文本区域获得焦点(这属于我想要实现的逻辑)。当 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);
}

}

在此示例中,Alt-ArrowDown 命令有效,而普通的 ArrowUp 命令无效。如果我更改 requestFocus() 行,以便标签请求焦点,ArrowUp 也可以工作(因为现在是标签而不是文本区域获得焦点)。

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

最佳答案

文本组件的键绑定(bind)在获得焦点时优先。因此,您需要使用如下代码从文本组件中删除绑定(bind):

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

请参阅 Swing 教程中 How to Make/Remove Bindings 的部分了解更多信息。

关于java - Swing - 使用 TextComponents 的 GUI 中的关键问题(箭头键、Tab 等),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33884770/

相关文章:

java - 在二叉树中找到一个值避免计算器异常

Java:使用类作为 hashmap 中的值

java - @GenerateValue(策略= GenerationType.AUTO): MySQL and generated IDs shared between tables?

Java Swing 按钮文本显示不同

java - JCheckBoxTree初始状态问题

java - 使用 EventKey 在 EditText 上设置文本

c# - 如何在 C# 应用程序中捕获 Control-V?

java - 如何公开本地部署的Web服务

Java 调整我的分割框大小

python - 更改事件键上的光标形状