Java 弹出按钮

发布于 2024-12-27 20:36:35 字数 3728 浏览 1 评论 0原文

注意:您可能需要编译并运行我的示例才能完全理解我的问题。如果这不符合犹太洁食,我提前道歉。

我正在尝试创建一个基于 JToggleButtonJPopupMenu 的 Swing 控件。

如果弹出菜单可见,则选择切换按钮;如果弹出菜单不可见,则取消选择切换按钮。因此,其行为类似于 JComboBox,只不过弹出窗口可以包含任意组件。

下面的代码是我如何创建控件的示例(除了它在自己的类中......类似于 JPopupToggleButton )。不幸的是,它在不同的外观和感觉下表现出不同的行为(我已经使用 Metal 和 Nimbus 对其进行了测试)。

此处发布的代码在 Metal 中的行为符合预期,但在 Nimbus 中则不然。使用 Nimbus 时,只需通过重复单击切换按钮来显示和隐藏弹出窗口,您就会明白我的意思。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class PopupButtonExample extends JFrame
{
    public static void main( String[] args )
    {
        java.awt.EventQueue.invokeLater( new Runnable()
        {
            @Override
            public void run()
            {
                PopupButtonExample example = new PopupButtonExample();
                example.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                example.setVisible( true );
            }
        });
    }

    public PopupButtonExample()
    {
        super( "Components in Popup" );

        JPanel popupPanel = new JPanel();
        popupPanel.setLayout( new BorderLayout() );
        popupPanel.add( new JLabel( "This popup has components" ),
                BorderLayout.NORTH );
        popupPanel.add( new JTextArea( "Some text", 15, 20 ),
                BorderLayout.CENTER );
        popupPanel.add( new JSlider(), BorderLayout.SOUTH );

        final JPopupMenu popupMenu = new JPopupMenu();
        popupMenu.add( popupPanel );

        final JToggleButton popupButton = new JToggleButton( "Show Popup" );
        popupButton.addActionListener( new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                if( popupButton.isSelected() )
                    popupMenu.show( popupButton, 0, popupButton.getHeight() );
            }
        });

        popupMenu.addPopupMenuListener( new PopupMenuListener()
        {
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {}

            @Override
            public void popupMenuCanceled(PopupMenuEvent pme) {}

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {
                Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
                Point componentLoc = popupButton.getLocationOnScreen();
                mouseLoc.x -= componentLoc.x;
                mouseLoc.y -= componentLoc.y;
                if( !popupButton.contains( mouseLoc ) )
                    popupButton.setSelected( false );
            }
        });

        JPanel toolBarPanel = new JPanel();
        toolBarPanel.add( popupButton );
        JToolBar toolBar = new JToolBar();
        toolBar.add( toolBarPanel );

        setLayout( new BorderLayout() );
        add( toolBar, BorderLayout.PAGE_START );
        setPreferredSize( new Dimension( 640, 480 ) );
        pack();
    }
}

注释掉以下几行会使代码在 Nimbus 中按预期运行,但在 Metal 中则不然。再次,只需继续单击切换按钮即可明白我的意思。

//                Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
//                Point componentLoc = popupButton.getLocationOnScreen();
//                mouseLoc.x -= componentLoc.x;
//                mouseLoc.y -= componentLoc.y;
//                if( !popupButton.contains( mouseLoc ) )

所以这是我的两个问题:

(1)在 Nimbus 中,为什么隐藏弹出面板的点击不会像 Metal 那样传递到切换按钮?

(2) 我怎样才能解决这个问题,使其适用于所有外观和感觉?

Note: You may have to compile and run my example to fully understand my question. If this is not kosher, I apologize in advance.

I am trying to create a Swing control that is based on a JToggleButton and a JPopupMenu.

The toggle button is selected iff the popup menu is visible, and the toggle button is deselected iff the popup menu is not visible. Thus, the behavior is similar to a JComboBox, except that the popup can contain arbitrary components.

The code that follows is an example of how I would create the control (except that it would be in its own class... something like a JPopupToggleButton). Unfortunately, it exhibits different behavior under different look and feels (I have tested it with Metal and Nimbus).

The code as posted here behaves as expected in Metal, but not in Nimbus. When using Nimbus, just show and hide the popup by repeatedly clicking the toggle button and you will see what I mean.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class PopupButtonExample extends JFrame
{
    public static void main( String[] args )
    {
        java.awt.EventQueue.invokeLater( new Runnable()
        {
            @Override
            public void run()
            {
                PopupButtonExample example = new PopupButtonExample();
                example.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
                example.setVisible( true );
            }
        });
    }

    public PopupButtonExample()
    {
        super( "Components in Popup" );

        JPanel popupPanel = new JPanel();
        popupPanel.setLayout( new BorderLayout() );
        popupPanel.add( new JLabel( "This popup has components" ),
                BorderLayout.NORTH );
        popupPanel.add( new JTextArea( "Some text", 15, 20 ),
                BorderLayout.CENTER );
        popupPanel.add( new JSlider(), BorderLayout.SOUTH );

        final JPopupMenu popupMenu = new JPopupMenu();
        popupMenu.add( popupPanel );

        final JToggleButton popupButton = new JToggleButton( "Show Popup" );
        popupButton.addActionListener( new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                if( popupButton.isSelected() )
                    popupMenu.show( popupButton, 0, popupButton.getHeight() );
            }
        });

        popupMenu.addPopupMenuListener( new PopupMenuListener()
        {
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent pme) {}

            @Override
            public void popupMenuCanceled(PopupMenuEvent pme) {}

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent pme) {
                Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
                Point componentLoc = popupButton.getLocationOnScreen();
                mouseLoc.x -= componentLoc.x;
                mouseLoc.y -= componentLoc.y;
                if( !popupButton.contains( mouseLoc ) )
                    popupButton.setSelected( false );
            }
        });

        JPanel toolBarPanel = new JPanel();
        toolBarPanel.add( popupButton );
        JToolBar toolBar = new JToolBar();
        toolBar.add( toolBarPanel );

        setLayout( new BorderLayout() );
        add( toolBar, BorderLayout.PAGE_START );
        setPreferredSize( new Dimension( 640, 480 ) );
        pack();
    }
}

Commeting out the following lines makes the code behave as expected in Nimbus, but not in Metal. Again, just keep clicking the toggle button to see what I mean.

//                Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
//                Point componentLoc = popupButton.getLocationOnScreen();
//                mouseLoc.x -= componentLoc.x;
//                mouseLoc.y -= componentLoc.y;
//                if( !popupButton.contains( mouseLoc ) )

So here are my two questions:

(1) In Nimbus, why does the click that hides the popup panel not get passed to the toggle button, as it does with Metal?

(2) How can I solve this problem so that it works with all look and feels?

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

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

发布评论

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

评论(2

冬天旳寂寞 2025-01-03 20:36:35
  • Nimbus 问题太多(开发在中间某个地方结束)我发现与 Metal 相比,您需要在 JToggleButton 上单击三次鼠标

  • 每个标准 L&F 都有自己的特定问题,尤其是 SystemLookAndFeel

  • 使用 JWindow 而不是 JPopup,因为使用 JPopup 也存在另一个错误,例如 JPopup 与 JCombobox

  • Nimbus is too buggy (and development ended somewhere in the middle) I see that you need three mouse click to the JToggleButton in compare with Metal

  • every standard L&F have got own specific issues, especially SystemLookAndFeel

  • use JWindow rather that JPopup, because with JPopup there are another Bugs too e.g. JPopup with JCombobox

|煩躁 2025-01-03 20:36:35

经过一番调查,我找到了 Nimbus 和 Metal 之间差异的原因。使用以下标志(至少 BasicPopupMenuUI)来控制弹出窗口关闭时事件的消耗:

UIManager.getBoolean( "PopupMenu.consumeEventOnClose" );

使用 Nimbus 时,此标志返回 true。使用 Metal 时,返回 false。因此,方法 popupMenuWillBecomeInvisible 应定义如下:

if( UIManager.getBoolean( "PopupMenu.consumeEventOnClose" ) )
{
    popupButton.setSelected( false );
}
else
{
    Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
    Point componentLoc = popupButton.getLocationOnScreen();
    mouseLoc.x -= componentLoc.x;
    mouseLoc.y -= componentLoc.y;
    if( !popupButton.contains( mouseLoc ) )
    {
        popupButton.setSelected( false );
    }
}

After some investigation, I found the cause for the difference between Nimbus and Metal. The following flag is used (at least by BasicPopupMenuUI) to control the consumption of events when a popup is closed:

UIManager.getBoolean( "PopupMenu.consumeEventOnClose" );

When using Nimbus, this returns true. When using Metal, this returns false. Thus, the method popupMenuWillBecomeInvisible should be defined as follows:

if( UIManager.getBoolean( "PopupMenu.consumeEventOnClose" ) )
{
    popupButton.setSelected( false );
}
else
{
    Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
    Point componentLoc = popupButton.getLocationOnScreen();
    mouseLoc.x -= componentLoc.x;
    mouseLoc.y -= componentLoc.y;
    if( !popupButton.contains( mouseLoc ) )
    {
        popupButton.setSelected( false );
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文