代码之家  ›  专栏  ›  技术社区  ›  Victor

回转部件和AWT事件的问题

  •  2
  • Victor  · 技术社区  · 15 年前

    我的Java GUI代码似乎有问题,我不知道为什么它不工作。

    当鼠标点击 面板 或框架- 现在我们只说panel;因为这只是一个测试,最终这个代码将为另一个GUI组件实现,但我想先让它工作。 - 弹出式菜单 需要变得可见,焦点需要设置在 文本字段 .然后,当用户按Enter键或文本字段上的焦点丢失时,弹出菜单需要隐藏,文本重置为空白或我需要的任何内容。

    这就是我写的:

    public class Test {
        private final JFrame frame = new JFrame();
        private final JPanel panel = new JPanel();
        private final JPopupMenu menu = new JPopupMenu();
        private final JTextField field = new JTextField();
        private final Obj obj;
    
        //... constructor goes here
    
        public void test(){
            frame.setSize(new Dimension(200,200));
            field.setColumns(10);
            field.addActionListener(new ActionListener(){
                public void actionPerformed(ActionEvent arg0) {
                    obj.method(field.getText());
                    menu.setVisible(false);
                    field.setText("");
                }
            });
            field.addFocusListener(new FocusListener() {
                 public void focusLost(FocusEvent e) {
                     menu.setVisible(false);
                     field.setText("");
                 }
    
                 //... focus gained event goes here
            });
            panel.addMouseListener(new MouseListener() {
                public void mouseClicked(MouseEvent e) {
                    menu.setLocation(e.getX(), e.getY());
                    menu.setVisible(true);
                    field.requestFocusInWindow();
                }
    
                //... other mouse events go here
            });
    
            menu.add(field);
            frame.getContentPane().add(panel);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    }
    

    当代码写在这里时,菜单会在我单击后自动隐藏。它只是在屏幕上短暂地闪烁,然后不做任何其他事情就隐藏了起来。

    如果我更改代码以排除 menu.setVisible(false) 然后文本字段将永远无法获得焦点。

    这是因为jpopupmenu的误用吗?我哪里出错了?

    还要注意,我省略了main或obj。它们在另一个文件中,很可能对这个问题无关紧要。obj.method()什么也不做,main只调用测试的构造函数和test()方法。

    4 回复  |  直到 15 年前
        1
  •  2
  •   Peter    15 年前

    这段代码应该按照您希望的方式工作(希望您遵循匿名类的用法:

    public class Test {
    
    public static void main(String[] args) {
        Test test = new Test();
        test.test();
    }
    
    private JFrame frame;
    private JPanel panel;
    private JPopupMenu menu;
    private JTextField field;
    
    public Test() {
        frame = new JFrame();
        frame.setSize(new Dimension(200, 200));
        frame.getContentPane().add(getPanel());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    
    private JPanel getPanel() {
        if (panel == null) {
            panel = new JPanel();
            panel.setComponentPopupMenu(getMenu());
            panel.addMouseListener(new MouseAdapter() {
    
                @Override
                public void mouseClicked(MouseEvent e) {
                    menu.show(panel, e.getX(), e.getY());
                }
            });
        }
        return panel;
    }
    
    private JPopupMenu getMenu() {
        if (menu == null) {
            menu = new JPopupMenu() {
    
                @Override
                public void setVisible(boolean visible) {
                    super.setVisible(visible);
                    if (visible) {
                        getField().requestFocus();
                    }
                }
            };
            menu.add(getField());
        }
        return menu;
    }
    
    private JTextField getField() {
        if (field == null) {
            field = new JTextField();
            field.setColumns(10);
            field.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    getMenu().setVisible(false);
                }
            });
        }
        return field;
    }
    
    public void test() {
        frame.setVisible(true);
    }
    }
    

    要注意的关键是当我们设置弹出菜单时:

    panel.setComponentPopupMenu(getMenu());
    panel.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent event) {
            getMenu().show(getPanel(), event.getX(), event.getY());
        }
    });
    

    以及当弹出菜单可见时,如何请求文本字段的焦点,这是通过请求焦点的文本字段完成的,但不是在窗口中的焦点,因为它不存在于窗口中,只存在于菜单中:

    menu = new JPopupMenu() {
        @Override
        public void setVisible(boolean visible) {
            super.setVisible(visible);
            if (visible) {
                getField().requestFocus();
            }
        }
    };
    

    最后,文本字段如何取消弹出菜单:

    field.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            getMenu().setVisible(false);
        }
    });
    
        2
  •  1
  •   aperkins    15 年前

    您应该能够通过重写getcomponentpopupmenu来返回jpopupmenu来完成此操作。这应该和你想要的完全一样。它将允许焦点等。

    编辑:这不是严格必要的,尽管它允许更好的继承。

    Public JPopupMenu getComponentPopupMenu() {
        return getMenu();
    }
    

    哦,如果您希望它在任何鼠标单击时显示,请添加一个鼠标侦听器,然后调用弹出菜单上的显示:

    public void processMouseEvent(MouseEvent e) {
        popup.show(this, e.getX(), e.getY());
    }
    

    这将在任何鼠标单击时显示。

    或者,另一个选项是,如果您有鼠标监听器(调用processMouseEvent),并且只想在右键单击时调用:

    public void processMouseEvent(MouseEvent e) {
        if (e.isPopupTrigger()) {
            popup.show(this, e.getX(), e.getY());
        }
    }
    

    鼠标侦听器如下所示:

    panel.addMouseListener(new MouseAdapter() {
        mouseClicked(MouseEvent e) {
            processMouseEvent(e);
        }
    }
    
        3
  •  1
  •   Victor    15 年前

    我想指出的是,通过使用建议的方法,我发现 setComponentPopupMenu() 自动添加mouseListener以显示给定的弹出菜单,然后使用右键单击事件。
    所以里面有什么 if(e.isPopupTrigger()) 结构从不在右键单击时运行,因为该事件已被消耗。

    所以本质上,我只需要加上 panel.setComponentPopupMenu(getMenu()) 但事实上,它消耗了我所有的右键点击事件,而不仅仅是鼠标点击,这是非常有限的。

        4
  •  0
  •   Jens Schauder    15 年前

    当你显示一个弹出窗口时,它应该有焦点(它可能会抓住它),任何其他东西都没有什么意义。

    所以可能发生的是: 菜单显示并获取焦点。

    使用下一个命令,您将焦点遍历到文本字段。因为弹出窗口没有焦点,没有焦点的弹出窗口是无用的,所以它再次隐藏。