如何创建“下拉菜单” Java Swing 工具栏中的菜单?

发布于 2024-08-14 20:35:03 字数 2536 浏览 6 评论 0原文

我在 Swing JToolBar 上创建了一个下拉菜单。但它并没有按照我想要的方式创造行为。我的目标是让它像 Firefox 的“智能书签”按钮一样工作。

当用户选择菜单项时它会消失:正确!

当用户按 ESC 时它消失:正确!

当用户单击菜单之外的主框架中的某个位置时,它就会消失:正确!

但是,当用户第二次单击显示下拉菜单的按钮时,它不会消失:不正确...:-(

我的问题是如何添加此行为,当单击再次显示菜单的按钮

这是我当前的代码,来自 Mac 上的 Java 6:

import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

public class ScratchSpace {

    public static void main(String[] arguments) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("Toolbar with Popup Menu demo");

                final JToolBar toolBar = new JToolBar();
                toolBar.add(createMoreButton());

                final JPanel panel = new JPanel(new BorderLayout());
                panel.add(toolBar, BorderLayout.NORTH);
                panel.setPreferredSize(new Dimension(600, 400));
                frame.getContentPane().add(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private static AbstractButton createMoreButton() {
        final JToggleButton moreButton = new JToggleButton("More...");
        moreButton.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    createAndShowMenu((JComponent) e.getSource(), moreButton);
                }
            }
        });
        moreButton.setFocusable(false);
        moreButton.setHorizontalTextPosition(SwingConstants.LEADING);
        return moreButton;
    }

    private static void createAndShowMenu(final JComponent component, final AbstractButton moreButton) {
        JPopupMenu menu = new JPopupMenu();
        menu.add(new JMenuItem("Black"));
        menu.add(new JMenuItem("Red"));

        menu.addPopupMenuListener(new PopupMenuListener() {
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            }

            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                moreButton.setSelected(false);
            }

            public void popupMenuCanceled(PopupMenuEvent e) {
                moreButton.setSelected(false);
            }
        });

        menu.show(component, 0, component.getHeight());
    }
}

I've created a drop-down menu on my Swing JToolBar. But it doesn't create behave the way I want. I'm aiming for it to work like Firefox's "Smart Bookmarks" button.

It disappears when the user selects a menu item: CORRECT!

It disappears when the user presses ESC: CORRECT!

It disappears when the user clicks somewhere in the main frame outside of the menu: CORRECT!

But it doesn't disappear when the user clicks a second time on the button that shows the drop-down menu: INCORRECT... :-(

My question is how can I add this behaviour, that it does disappear when the clicks on the button that shows the menu a second time.

Here's my current code, from Java 6 on the Mac:

import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

public class ScratchSpace {

    public static void main(String[] arguments) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("Toolbar with Popup Menu demo");

                final JToolBar toolBar = new JToolBar();
                toolBar.add(createMoreButton());

                final JPanel panel = new JPanel(new BorderLayout());
                panel.add(toolBar, BorderLayout.NORTH);
                panel.setPreferredSize(new Dimension(600, 400));
                frame.getContentPane().add(panel);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private static AbstractButton createMoreButton() {
        final JToggleButton moreButton = new JToggleButton("More...");
        moreButton.addItemListener(new ItemListener() {
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    createAndShowMenu((JComponent) e.getSource(), moreButton);
                }
            }
        });
        moreButton.setFocusable(false);
        moreButton.setHorizontalTextPosition(SwingConstants.LEADING);
        return moreButton;
    }

    private static void createAndShowMenu(final JComponent component, final AbstractButton moreButton) {
        JPopupMenu menu = new JPopupMenu();
        menu.add(new JMenuItem("Black"));
        menu.add(new JMenuItem("Red"));

        menu.addPopupMenuListener(new PopupMenuListener() {
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
            }

            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                moreButton.setSelected(false);
            }

            public void popupMenuCanceled(PopupMenuEvent e) {
                moreButton.setSelected(false);
            }
        });

        menu.show(component, 0, component.getHeight());
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

邮友 2024-08-21 20:35:03

好吧,这是一个潜在的解决方案,但它并非没有缺点。只有您可以决定这是否适合您的应用程序。问题是弹出窗口关闭发生在其他鼠标处理事件触发之前,因此再次单击“更多..”按钮会导致弹出窗口隐藏,从而在按钮被告知已按下之前将按钮状态重置为取消选择。

简单的解决方法是在主程序中添加以下调用:

UIManager.put("PopupMenu.consumeEventOnClose", Boolean.TRUE);

这样做的结果是,每当弹出菜单由于鼠标按下事件而关闭时,该鼠标事件将在菜单关闭时被消耗并赢得'不会被传递到鼠标下的任何其他组件。如果您可以忍受限制,这是一个简单的解决方案。

Well, here is a potential solution that is not without it's drawbacks. Only you can decide if this is acceptable for your application. The issue is that the popup closing occurs before other mouse-handling events are fired so clicking on your More.. button again causes the popup to hide, thus resetting the buttons state to deselected BEFORE the button even gets told it was pressed.

The easy workaround is to add the following call within your main program:

UIManager.put("PopupMenu.consumeEventOnClose", Boolean.TRUE);

The result of this is that whenever a popup menu is closed because of a mouse-pressed event, that mouse event will be consumed at the time the menu is closed and won't be passed on to any other components under the mouse. If you can live with limitation, this is an easy solution.

不爱素颜 2024-08-21 20:35:03

发生的情况是,当您单击菜单时,它会取消弹出菜单,因此您取消选择该按钮,但下一个立即事件是单击该按钮,现在它被取消选择,因此它再次显示菜单。

我还没有确切的解决方案,但给我一点......

What's happening is that when you click off the menu, it cancels the popup menu, so you deselect the button, but the next immediate event is clicking the button, and now its deselected so it shows the menu again.

I don't have the exact solution yet, but give me a little bit ...

柠檬色的秋千 2024-08-21 20:35:03

我不使用 Firefox,所以我不知道智能书签按钮是什么样的,但也许使用 JMenu 作为“按钮”。您可以尝试使用 JButton 的边框使其看起来更像一个按钮。

I don't use Firefox so I don't know what the Smart Bookmarks button looks like, but maybe use a JMenu as the "button". You could try using the Border of a JButton to make it look more like a button.

染墨丶若流云 2024-08-21 20:35:03

嗯,按钮上的侦听器仅在按下时做出反应,因为您仅侦听 ItemEvent.SELECTED 事件。如何在此处添加另一个 if 子句来侦听 ItemEvent.DESELECTED 事件:

    moreButton.addItemListener(new ItemListener() {
        public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                createAndShowMenu((JComponent) e.getSource(), moreButton);
            }
        }
    });

您可以在某处存储对 menu 的引用,或者您可以使菜单本身向按钮添加另一个侦听器。后一种解决方案可能更简单,因为您似乎已经发送了对菜单的按钮引用。

Well, the listener on the button reacts only when it is pushed down, because you listen for ItemEvent.SELECTED events only. How about adding another if clause to listen for ItemEvent.DESELECTED events here:

    moreButton.addItemListener(new ItemListener() {
        public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
                createAndShowMenu((JComponent) e.getSource(), moreButton);
            }
        }
    });

You could either store a reference to the menu somewhere, or you could make the menu itself add another listener to the button. The latter solution could be more straightforward, since you already seem to send a button reference to the menu.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文