且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

JMenuBar SelectionModel ChangeListener仅触发一次

更新时间:2022-12-26 17:13:57

看起来菜单栏永远不会一旦被选中,未被选中。不确定这是不是一个错误。

Looks like the menubar is never unselected, once it had been selected. Not sure if that's a bug or not.

直接收听MenuSelectionManager可能是一个更好的主意,因为在那里您会收到有关菜单选择的所有更改的通知。需要一些逻辑来过滤掉与menuBar无关的那些,类似于:

Could be a better idea to listen directly to the MenuSelectionManager as that's where you are notified about all changes to menu selection anywhere. Needs some logic to filter out those unrelated to the menuBar, something similar to:

ChangeListener listener = new ChangeListener() {
    @Override
    public void stateChanged(ChangeEvent e) {
        MenuElement[] elements = MenuSelectionManager.defaultManager().getSelectedPath();
        jMenuBar1.setVisible(elements.length > 0 && elements[0] == jMenuBar1);
    }
};
MenuSelectionManager.defaultManager().addChangeListener(listener);

更新

隐藏菜单栏的一个巨大缺点是它的menuItems的加速器停止工作。原因是只要求显示的组件的componentInputMaps处理它们。这是在swing包的内部深处完成的,即由包私有类KeyboardManager完成。无法挂钩自定义管理器(可以实现处理未显示的菜单栏)。

A hefty drawback of hiding the menubar is that accelerators to its menuItems stop working. The reason is that only componentInputMaps of components which are showing are asked to handle them. This is done deep down in the bowels of the swing package, namely by the package private class KeyboardManager. No way to hook-in a custom manager (which might be implemented to handle menubars that are not showing).

在链的另一端,我们可以干扰,虽然。基本上有两个选项,都是子类化菜单栏:

At the other end of the chain, we can interfer, though. Basically two options, both subclassing menubar:


  • (非常脏的技巧!)覆盖isShowing总是返回true。我已经看到了这一点,但不能真正推荐,因为可能是我不知道的副作用

  • 一个有点脏的伎俩:添加隐藏属性并实现getPreferredSize以在隐藏时返回0高度。肮脏是它依赖RootPaneLayout尊重pref高度......

  • (extremely dirty trick!) override isShowing to always return true. I've seen this done, but can't really recommend because there might be side-effects that I don't know
  • a slightly dirty trick: add a property hidden and implement getPreferredSize to return a 0 height if hidden. The dirtyness is its reliance on RootPaneLayout respecting the pref height ...

修订后的ChangeListener:

The revised ChangeListener:

bar.setHidden(true);
ChangeListener listener = new ChangeListener() {
    @Override
    public void stateChanged(ChangeEvent e) {
        MenuElement[] elements = MenuSelectionManager.defaultManager().getSelectedPath();
        bar.setHidden(!(elements.length >0 && elements[0] == bar));
    }
};
MenuSelectionManager.defaultManager().addChangeListener(listener);

自定义menuBar:

The custom menuBar:

public static class JHideableMenuBar extends JMenuBar {

    private boolean hidden;

    public void setHidden(boolean hidden) {
        if (this.hidden == hidden) return;
        this.hidden = hidden;
        revalidate();
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension pref = super.getPreferredSize();
        if (hidden) {
            pref.height = 0;
        }
        return pref;
    }

}