2

我的 java gui 代码似乎有问题,我不知道为什么它不起作用。

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

所以这就是我写的:

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 的构造函数和 test() 方法。

4

4 回答 4

2

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

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);
    }
});
于 2009-07-24T19:47:12.507 回答
1

您应该能够通过覆盖 getComponentPopupMenu 来返回一个 JPopupMenu 来做到这一点。这应该完全按照您的意愿处理。它将允许焦点等。

编辑:这不是绝对必要的,尽管它确实允许更好的继承。

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

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

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);
    }
}
于 2009-07-24T19:19:53.840 回答
1

我想指出,我通过使用setComponentPopupMenu()自动添加 MouseListener 来显示给定的 PopupMenu 的建议方法发现,然后使用右键单击事件。
因此,if(e.isPopupTrigger())结构内部的任何内容都不会在右键单击时运行,因为事件已被消耗。

所以基本上我只是通过添加来获得我的问题中指定的panel.setComponentPopupMenu(getMenu())行为,但事实上它消耗了我所有的右键单击事件,而不仅仅是 mouseClicked,这是非常有限的。

于 2009-07-27T18:36:44.413 回答
0

当您显示一个弹出窗口时,它应该具有焦点(并且可能会抓住它)其他任何东西实际上都没有多大意义。

所以可能发生的事情是这样的:菜单显示,并抓住焦点。

使用下一个命令,您将焦点移动到文本字段。由于弹出框没有焦点,没有焦点的弹出框也没用,它再次隐藏。

于 2009-07-24T19:23:00.980 回答