java-JMenuBar SelectionModel ChangeListener仅触发一次
作者:互联网
我正在尝试让我的JMenuBar建模Firefox和iTunes菜单栏的行为.行为:菜单栏最初是隐藏的.但是,当您按Alt时,菜单栏出现(选择了第一个项目),而当您没有选择菜单项时,菜单栏消失了.我的想法是通过其SelectionModel上的ChangeListener监听JMenuBar的选择更改.
但是,附加的SSCCE的行为不是所希望的.框架加载时,JMenuBar不可见.当您按Alt时,菜单栏出现,并选择了第一个菜单(这要归功于WindowsLookAndFeel).但是,随后按下的所有Alt都不会触发ChangeEvent.我不知道为什么…
有人要散发出光吗?
public class MenuBarTest extends javax.swing.JFrame {
public MenuBarTest() {
initComponents();
jMenuBar1.setVisible(false);
jMenuBar1.getSelectionModel().addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
System.out.println(e.toString());
jMenuBar1.setVisible(jMenuBar1.isSelected());
System.out.println(jMenuBar1.isSelected());
System.out.println(jMenuBar1.getSelectionModel().isSelected());
}
});
}
private void initComponents() {
jMenuBar1 = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
jMenuItem1 = new javax.swing.JMenuItem();
jMenu2 = new javax.swing.JMenu();
jMenuItem2 = new javax.swing.JMenuItem();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jMenu1.setText("File");
jMenuItem1.setText("jMenuItem1");
jMenu1.add(jMenuItem1);
jMenuBar1.add(jMenu1);
jMenu2.setText("Edit");
jMenuItem2.setText("jMenuItem2");
jMenu2.add(jMenuItem2);
jMenuBar1.add(jMenu2);
setJMenuBar(jMenuBar1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE));
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 279, Short.MAX_VALUE));
pack();
}
public static void main(String args[]) {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewClass().setVisible(true);
}
});
}
private javax.swing.JMenu jMenu1;
private javax.swing.JMenu jMenu2;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JMenuItem jMenuItem1;
private javax.swing.JMenuItem jMenuItem2;
}
解决方法:
看起来菜单栏一旦被选择就永远不会被取消选择.不知道这是否是一个错误.
直接听MenuSelectionManager可能是一个更好的主意,因为在那里您会收到有关菜单选择的所有更改的通知.需要一些逻辑来过滤掉与menuBar不相关的那些逻辑,类似于:
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);
更新
隐藏菜单栏的一个巨大缺点是其菜单项的加速器停止工作.原因是仅要求显示的组件的componentInputMaps处理它们.这是在swing包的肠子深处完成的,即通过包私有类KeyboardManager进行.无法挂接自定义管理器(可以实现为处理未显示的菜单栏).
但是,在链的另一端,我们可以进行干预.基本上有两个选项,都是子类化菜单栏:
>(极其肮脏的把戏!)覆盖isShowing总是返回true.我已经看过了,但是不能真正推荐,因为可能会有一些我不知道的副作用
>有点肮脏的技巧:添加一个隐藏的属性,并实现getPreferredSize如果隐藏则返回0高度.肮脏是它依赖RootPaneLayout尊重首选高度…
修改后的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:
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;
}
}
标签:java,swing,jmenubar,changelistener,jmenuitem 来源: https://codeday.me/bug/20191012/1900558.html