我想实现自动完成功能 . 目前我有一个包含JTextField的JPanel,当用户开始输入时,会出现一个包含多个选项的自动完成(JPopupMenu) .
问题是它从文本字段获取焦点,用户不再可以键入 . 当我将焦点返回到文本字段时,用户不再在选项之间导航(使用向上和向下按钮) . 同时关注菜单不允许我拦截其KeyListener(不知道为什么),当我尝试在文本字段侧处理输入时,我在尝试选择菜单项时遇到问题 .
所以我想拥有:
-
一个弹出菜单,其中包含当用户更改文本字段中的文本时仍会激活菜单的动态更改的选项
-
用户可以使用向上和向下箭头键在选项之间导航,也可以使用Enter和Escape键分别使用选项或关闭弹出窗口 .
是否可以在菜单上处理键盘事件并将键入事件转发回文本字段?
接近我的问题的正确方法是什么?
这是下面的代码 . 提前致谢!
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
class TagVisual extends JPanel {
private JTextField editField;
public TagVisual() {
FlowLayout layout = new FlowLayout();
layout.setHgap(0);
layout.setVgap(0);
setLayout(layout);
editField = new JTextField();
editField.setBackground(Color.RED);
editField.setPreferredSize(new Dimension(200, 20));
editField.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
JPopupMenu menu = new JPopupMenu();
menu.add("Item 1");
menu.add("Item 2");
menu.add("Item 3");
menu.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
JOptionPane.showMessageDialog(TagVisual.this, "keyTyped");
}
@Override
public void keyPressed(KeyEvent e) {
JOptionPane.showMessageDialog(TagVisual.this, "keyPressed");
}
@Override
public void keyReleased(KeyEvent e) {
JOptionPane.showMessageDialog(TagVisual.this, "keyReleased");
}
});
menu.show(editField, 0, getHeight());
}
@Override
public void keyPressed(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
});
add(editField, FlowLayout.LEFT);
}
public void place(JPanel panel) {
panel.add(this);
editField.grabFocus();
}
}
public class MainWindow {
private JPanel mainPanel;
private JFrame frame;
public MainWindow(JFrame frame) {
mainPanel = new JPanel(new FlowLayout());
TagVisual v = new TagVisual();
v.place(mainPanel);
this.frame = frame;
}
public static void main(String[] args) {
JFrame frame = new JFrame("TextFieldPopupIssue");
frame.setContentPane(new MainWindow(frame).mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
2 回答
我个人建议使用弹出窗口或自定义
JWindow
而不是JPopupMenu
,因为后者最初仅用于显示菜单项 . 它通常用于其他事情,但不是以不同方式使用它的最佳实践 .例如,您的示例中有一些菜单项作为自动完成选项 - 如果只有一些结果,则可以正常工作 . 但是,如果有10个呢?怎么样50?还是500?您将不得不以某种方式为这些情况创建其他变通方法 - 将项目放入滚动窗格(哦,上帝,这看起来很难看)或将结果剪切到最佳状态(这也不是最好的选项) .
所以我用
JWindow
做了一个小例子作为AutocompleteField
的弹出窗口 . 这很简单,但是你可以从中得到一些基本的东西以及你提到的东西:所以在这个例子中,弹出窗口
JWindow
本身不是活动的(没有聚焦),并且由于其强制配置而无法获得焦点 . 这使我们能够将注意力集中在JTextField
并继续打字 .在此示例中,我们还捕获字段中的向上/向下箭头等关键事件,以浏览自动完成结果 . 并且ENTER和ESCAPE用于接受/取消结果选择 .
此代码也可以稍微重写以使用Swing
PopupFactory
作为自动完成弹出窗口的源,但它在essense中仍然是相同的,因为PopupFactory
使用的HeavyWeightWindow
只是扩展JWindow
并添加了一些设置 .最简单的解决方案是使菜单不可聚焦:
并在编辑器中处理键