【问题标题】:Why is the focus never lost from my component when I press the JFrame?为什么当我按下 JFrame 时我的组件始终没有失去焦点?
【发布时间】:2013-06-01 08:53:08
【问题描述】:

CustomTextField 类实现的焦点侦听器有问题。只有当另一个 Swing 组件获得焦点时才会调用焦点侦听器。但是如果我通过用鼠标拖动来移动 JFrame istelf,则永远不会调用 focusLost() 方法(换句话说,焦点似乎没有从 CustomTextField 转移到 JFrame)。

编辑:我的问题的解决方案如下:

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

public class ScrollFocus extends JFrame {

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            new ScrollFocus();
        }
    });
}

public ScrollFocus() {
    this.setLayout(new BorderLayout());
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Vector<String> values = new Vector<>();
    values.add("a");
    values.add("b");
    values.add("c");
    values.add("d");
    values.add("e");
    JComboBox<String> comboBox = new JComboBox<>(values);
    JScrollPane scrollPane = new JScrollPane(comboBox);
    this.add(scrollPane, BorderLayout.NORTH);

    CustomTextField customTextField = new CustomTextField();
    this.add(customTextField, BorderLayout.CENTER);

    JButton button = new JButton("press");
    final JPopupMenu menu = new JPopupMenu("Menu");
    menu.add(new JMenuItem("Test"));
    button.setComponentPopupMenu(menu);
    this.add(button, BorderLayout.SOUTH);

    pack();
    setVisible(true);
}

class CustomTextField extends JTextField implements FocusListener {

    private CustomPopup customPopup = new CustomPopup();

    public CustomTextField() {
        this.addFocusListener(this);


        this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "VK_UP");
        this.getActionMap().put("VK_UP", new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                setPopupSize();
                customPopup.show(CustomTextField.this, CustomTextField.this.getX(), CustomTextField.this.getY() + CustomTextField.this.getHeight());    
                customPopup.setSelectedIndex(0);
            }
        });
        this.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "VK_DOWN");
        this.getActionMap().put("VK_DOWN", new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                setPopupSize();
                customPopup.show(CustomTextField.this, CustomTextField.this.getX(), CustomTextField.this.getY() + CustomTextField.this.getHeight());
                customPopup.setSelectedIndex(0);
            }
        });
    }

    public void setPopupSize() {
        customPopup.setPopupSize(new Dimension(this.getWidth(), 110));
    }

    @Override
    public void focusGained(FocusEvent e) {
    }

    @Override
    public void focusLost(FocusEvent e) {
    }

    class CustomPopup extends JPopupMenu {
        String[] values = new String[]{"Value1", "Value2", "Value3", "Value4", "Value5", "Value6", "Value7",
                "Value8","Value9", "Value10", "Value11", "Value12", "Value13", "Value14", "Value15", "Value16",};
        JList<String> list = new JList<>(values);
        JScrollPane scrollPane = new JScrollPane(list);
        public int index = 0;

        public CustomPopup() {
            this.setLayout(new GridLayout(0,1));
            this.add(scrollPane);
            this.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    if(e.getKeyCode() == KeyEvent.VK_UP){
                        if(customPopup.index > 0)
                            customPopup.setSelectedIndex(--customPopup.index);
                    }
                    else if(e.getKeyCode() == KeyEvent.VK_DOWN){
                        if(customPopup.index < customPopup.getListSize()-1)
                            customPopup.setSelectedIndex(++customPopup.index);
                    }
                }
            });
            this.addFocusListener(new FocusAdapter() {
                @Override
                public void focusLost(FocusEvent e) {
                    index=0;
                }
            });
            pack();

        }

        public void setSelectedIndex(int index) {
            list.setSelectedIndex(index);
            list.ensureIndexIsVisible(index);
            requestFocus();
        }

        public int getListSize() {
            return values.length;
        }
    }
}
}

【问题讨论】:

    标签: java swing focus jframe focuslistener


    【解决方案1】:
    //customPopup.setVisible(true);
    customPopup.show((JComponent)e.getSource(), 0, 20);
    

    您应该使用show(...) 方法来显示弹出窗口。这必须在弹出窗口中添加一些侦听器,这样您就不再需要文本字段上的 FocusListener。

    但是,现在这是一个不同的问题。文本字段失去焦点,因此 Action 永远不会被调用。没关系,但是 JList 永远不会获得焦点,因此除非您先单击列表框,否则它不会响应向上/向下键。我不确定这里有什么问题。

    也许您可以尝试使弹出窗口、滚动窗格和列表都不可聚焦,以便焦点保持在文本字段上?

    【讨论】:

    • @camickr:谢谢camickr! customPopup.show() 成功了,而不是 customPopup.setVisible()。 show() 的工作方式似乎与 setVisible() 完全不同,因为调用 show() 方法的组件获得了焦点,但 setVisible() 使焦点留在了 JTextField 上。 show() 将焦点从 JTextField 中移除,这正是我想要的!
    【解决方案2】:

    'Focus',诚然是一个有点含糊的术语,通常适用于一个组件,而不是整个窗口。我们想到的是“有焦点的窗口”,但我认为我们真正的意思是“当前窗口,包含焦点的窗口”。如果我移动窗口(又名 JFrame)本身,我不会期望 focus_lost 被调用。

    另一种思考方式;如果我有一个文本字段,单击它并输入一两个字母,我会在该文本字段中看到这些字母。如果我然后稍微移动窗口并键入另一个或两个字母,我仍然希望这些字母出现在该字段中。它仍然有焦点,从未失去它。

    【讨论】:

    • JComboBox 的下拉菜单在组件外按下时会自动消失,例如在 JFrame 上。那是什么活动?当按下 JFrame 时,我的弹出菜单/下拉菜单不会消失,而是在另一个组件上(与 JComboBox 一样)。
    • 这是一个不同的问题吗?您的原文说“如果我通过用鼠标拖动来移动 JFrame istelf [原文如此],则永远不会调用 focusLost() 方法”-我不确定您在此响应中的意思是“在 JFrame 上按 ... "。
    • @rox 从技术上讲,当窗口失去焦点时,具有键盘焦点的字段实际上可能不会失去焦点,因为从技术上讲,它仍然在窗口内具有焦点。组合框使用一个特殊的弹出窗口(通常不是)另一个窗口。它有能力检测窗口焦点的变化(哪个窗口有焦点)并在失去焦点时自行关闭......
    • 按下或拖动...这对我的问题无关紧要,我希望在与 JFrame 交互时失去焦点。我还提到了 JComboBox。如果按下 JComboBox 使其下拉菜单出现,然后按下 JFrame,JComboBox 的下拉菜单就会消失。我想这是 JComboBox 正在发生的一些事件,当它被触发时,下拉菜单被隐藏了。当我的CustomTextField 类中的下拉/弹出菜单出现时,它只会在我按下 JFrame 上的另一个组件时消失,但如果我按下 JFrame 本身则不会消失。
    • @MadProgrammer:我在 BasicComboPopup 类中搜索了 Window 对象,但它不包含任何对象。它正在扩展 JPopupMenu,它似乎使用了 Frame(正在扩展 Window),所以看起来 JPopupMenu 完全在使用 Windows 对象。但是我看不到 Frame 是如何使用的...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多