java – 停止JPopupMenu窃取焦点

前端之家收集整理的这篇文章主要介绍了java – 停止JPopupMenu窃取焦点前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个JTextField,我希望建议结果匹配用户的输入.我在JPopupMenu中包含的JList中显示这些建议.

但是,当通过show(Component invoker,int x,int y)以编程方式打开弹出菜单时,焦点将从JTextField中获取.

奇怪的是,如果我调用setVisible(true)代替,焦点不会被盗;但是然后JPopupMenu不附加到任何面板,并且当框打开时最小化应用程序时,它将保持画在窗口上.

我也尝试使用requestFocus()将焦点重置到JTextField,但是我必须使用SwingUtilities.invokeLater()还原插入符号位置,并且调用后面的东西给用户一个微小的余地与现有内容/覆盖/或做其他不可预测的事情.

我的代码是有效的:

JTextField field = new JTextField();
JPopupMenu menu = new JPopupMenu();

field.addKeyListener(new KeyAdapter() {
    public void keyTyped(KeyEvent e) {
        JList list = getAListOfResults();

        menu.add(list);
        menu.show(field,field.getHeight());
    }
});

任何人都可以建议最好的途径,以编程方式显示JPopupMenu,同时保留对JTextField的关注?

解决方法

技术答案是将弹出的对焦属性设置为false:
popup.setFocusable(false);

这意味着textField必须接管通常由列表本身处理的所有键盘和鼠标触发的操作,sosmething类似于:

final JList list = new JList(Locale.getAvailableLocales());
final JPopupMenu popup = new JPopupMenu();
popup.add(new JScrollPane(list));
popup.setFocusable(false);
final JTextField field = new JTextField(20);
Action down = new AbstractAction("nextElement") {

    @Override
    public void actionPerformed(ActionEvent e) {
       int next = Math.min(list.getSelectedIndex() + 1,list.getModel().getSize() - 1);
       list.setSelectedIndex(next);
       list.ensureIndexIsVisible(next);
    }
};
field.getActionMap().put("nextElement",down);
field.getInputMap().put(
        KeyStroke.getKeyStroke("DOWN"),"nextElement");

由于您的上下文与JComboBox非常相似,您可以考虑查看BasicComboBoxUI和BasicComboPopup的来源.

编辑

只是为了好玩,以下没有回答焦点问题:-)而是演示如何使用可排序/可过滤的JXList来显示下拉列表中对应于打字文本的选项(这里以启动规则)

// instantiate a sortable JXList
final JXList list = new JXList(Locale.getAvailableLocales(),true);
list.setSortOrder(SortOrder.ASCENDING);

final JPopupMenu popup = new JPopupMenu();
popup.add(new JScrollPane(list));
popup.setFocusable(false);
final JTextField field = new JTextField(20);

// instantiate a PatternModel to map text --> pattern 
final PatternModel model = new PatternModel();
model.setMatchRule(PatternModel.MATCH_RULE_STARTSWITH);
// listener which to update the list's RowFilter on changes to the model's pattern property  
PropertyChangeListener modelListener = new PropertyChangeListener() {

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if ("pattern".equals(evt.getPropertyName())) {
            updateFilter((Pattern) evt.getNewValue());
        }
    }

    private void updateFilter(Pattern newValue) {
        RowFilter<Object,Integer> filter = null;
        if (newValue != null) {
            filter = RowFilters.regexFilter(newValue);
        }
        list.setRowFilter(filter);
    }
};
model.addPropertyChangeListener(modelListener);

// DocumentListener to update the model's rawtext property on changes to the field
DocumentListener documentListener = new DocumentListener() {

    @Override
    public void removeUpdate(DocumentEvent e) {
        updateAfterDocumentChange();
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        updateAfterDocumentChange();
    }

    private void updateAfterDocumentChange() {
        if (!popup.isVisible()) {
            popup.show(field,field.getHeight());
        } 
        model.setRawText(field.getText());
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
    }
};
field.getDocument().addDocumentListener(documentListener);

猜你在找的Java相关文章