2013-08-07 2 views
2

Я пытаюсь получить мой JMenuBar, чтобы моделировать поведение панелей меню Firefox и iTunes. Поведение: панель меню изначально скрыта. Но когда вы нажимаете Alt, появляется строка меню (при первом выбранном элементе), а когда вы не выбрали пункт меню, панель меню исчезает. Моя идея состояла в том, чтобы прослушать изменения выбора на JMenuBar через ChangeListener на своем SelectionModel.JMenuBar SelectionModel ChangeListener только срабатывает один раз

Однако поведение прилагаемого SSCCE не соответствует желанию. При загрузке кадра JMenuBar не отображается. Когда вы нажимаете Alt, появляется строка меню с выбранным первым меню (благодаря WindowsLookAndFeel). Тем не менее, каждый последующий Alt нажал стрелки ChangeEvents. Я не могу понять, почему ...

У кого-нибудь есть свет для пролить?

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; 
} 
+0

Я не получаю указанное поведение. – maxf130

ответ

3

Похоже, в строке меню никогда не отбирается, как только он был выбран. Не уверен, что это ошибка или нет.

Может быть, лучше всего прислушиваться непосредственно к 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); 

Update

Здоровенный недостатком скрытие строки меню в том, что ускорители на его MenuItems перестают работать. Причина заключается в том, что только обрабатывать компоненты componentInputMaps компонентов, которые отображаются. Это делается глубоко в недрах свинг-пакета, а именно в пакете private class 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; 
    } 

} 
+0

Отлично, что работает. Я бы никогда не нашел 'MenuSelectionManager' самостоятельно. Я все равно хотел бы знать, почему 'ChangeListener' в' SelectionManager' непосредственно из 'JMenuBar' не работает. Но он работает, поэтому я счастлив! Благодарю. – ryvantage

+0

почему-то этот подход отключает ускорители меню. Несмотря на то, что в документах для 'setAccelerator' в частности говорится:« Обратите внимание, что когда клавиатурный ускоритель вводится, он будет работать независимо от того, отображается ли в настоящее время меню ». но это не тот случай ... – ryvantage

+0

Если вы добавите этот код: 'jMenuItem2.setAccelerator (javax.swing.KeyStroke.getKeyStroke (java.awt.event.KeyEvent.VK_F, java.awt.event.InputEvent. CTRL_MASK)); jMenuItem2.setText («Найти»); jMenuItem2.addActionListener (новый java.awt.event.ActionListener() { public void actionPerformed (java.awt.event.ActionEvent evt) { Строка what = JOptionPane.showInputDialog (MenuBarTest.this, «Поиск чего?») System.out.println (что); } }); ' к вышеуказанному SSCCE – ryvantage

2

Однако каждый последующий Alt нажатой пожары не ChangeEvents. Я не могу выяснить, почему ...

  • ChangeListener стрельбы события из SelectionModel, события мыши или клавиатуры, эти события ожидаются

  • Вы можете, чтобы моделировать события из ChangeListener например сбросить выбор на меню (положить, что вместо того, чтобы двигаться фокус в JTextField)

  • есть подъезд еще слушателей, что стрельба собственные события и правильно

см

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import javax.swing.ButtonModel; 
import javax.swing.JTextField; 
import javax.swing.UIManager; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 
import javax.swing.event.MenuEvent; 
import javax.swing.event.MenuListener; 

public class MenuBarTest extends javax.swing.JFrame { 

    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; 
    private JTextField text = new JTextField("text", 10); 

    public MenuBarTest() { 
     jMenuBar1 = new javax.swing.JMenuBar(); 
     jMenu1 = new javax.swing.JMenu(); 
     jMenu1.addMenuListener(new MenuListener() { 
      @Override 
      public void menuSelected(MenuEvent e) { 
       System.out.println("MenuListener - Selected: " + e.toString()); 
      } 

      @Override 
      public void menuDeselected(MenuEvent e) { 
       System.out.println("MenuListener - Deselected: " + e.toString()); 
      } 

      @Override 
      public void menuCanceled(MenuEvent e) { 
       System.out.println("MenuListener - Canceled: " + e.toString()); 
      } 
     }); 
     jMenu1.getModel().addChangeListener(new ChangeListener() { 
      @Override 
      public void stateChanged(ChangeEvent e) { 
       ButtonModel model = (ButtonModel) e.getSource(); 
       if (model.isArmed()) { 
        System.out.println("ButtonModel - Armed: " + e.toString()); 
       } else if (model.isEnabled()) { 
        System.out.println("ButtonModel - Enabled: " + e.toString()); 
       } else if (model.isPressed()) { 
        System.out.println("ButtonModel - Pressed: " + e.toString()); 
       } else if (model.isRollover()) { 
        System.out.println("ButtonModel - Rollover: " + e.toString()); 
       } else if (model.isSelected()) { 
        System.out.println("ButtonModel - Selected: " + e.toString()); 
       } else { 
        System.out.println("ButtonModel - !!!!!????: " + e.toString()); 
       } 
      } 
     }); 
     jMenuItem1 = new javax.swing.JMenuItem(); 
     jMenu2 = new javax.swing.JMenu(); 
     jMenuItem2 = new javax.swing.JMenuItem(); 
     jMenu1.setText("File"); 
     jMenuItem1.setText("jMenuItem1"); 
     jMenu1.add(jMenuItem1); 
     jMenuBar1.add(jMenu1); 
     jMenu2.setText("Edit"); 
     jMenuItem2.setText("jMenuItem2"); 
     jMenu2.add(jMenuItem2); 
     jMenuBar1.add(jMenu2); 
     jMenuBar1.setVisible(false); 
     jMenuBar1.addPropertyChangeListener(new PropertyChangeListener() { 
      @Override 
      public void propertyChange(PropertyChangeEvent evt) { 
       String strPropertyName = evt.getPropertyName(); 
       System.out.println("PropertyChangeListener - NewValue: " + evt.getNewValue()); 
       System.out.println("PropertyChangeListener - OldValue: " + evt.getOldValue()); 
       System.out.println("PropertyChangeListener - PropagationId: " + evt.getPropagationId()); 
       System.out.println("PropertyChangeListener - PropertyName: " + evt.getPropertyName()); 
       if ("MENU.MP_BARBACKGROUND".equals(strPropertyName)) { 
        System.out.println("PropertyChangeListener - MENU.MP_BARBACKGROUND: " + evt.getNewValue()); 
       } 
      } 
     }); 
     jMenuBar1.getSelectionModel().addChangeListener(new ChangeListener() { 
      @Override 
      public void stateChanged(ChangeEvent e) { 
       System.out.println("ChangeListener - " + e.toString()); 
       jMenuBar1.setVisible(jMenuBar1.isSelected()); 
       System.out.println("ChangeListener - " + jMenuBar1.isSelected()); 
       System.out.println("ChangeListener - " + jMenuBar1.getSelectionModel().isSelected()); 
       java.awt.EventQueue.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         text.grabFocus(); 
         text.requestFocusInWindow(); 
         text.setText(text.getText()); 
         text.selectAll(); 
        } 
       }); 
      } 
     }); 
     setJMenuBar(jMenuBar1); 
     add(text, BorderLayout.NORTH); 
     add(new JTextField("text", 10), BorderLayout.SOUTH); 
     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
     setPreferredSize(new Dimension(400, 300)); 
     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() { 
      @Override 
      public void run() { 
       new MenuBarTest().setVisible(true); 
      } 
     }); 
    } 
} 
+0

это не решает проблему, делает это ;-) – kleopatra

+0

хм ... или, может быть, я не понимаю, что вы предлагаете? – kleopatra

+0

@ kleopatra 1. Я не отвечаю на что-то, есть какой-либо ответ 2. Игра с доступными событиями 3. Моделирование, которое JMenuBar всегда возвращает не ожидаемое значение из методов, реализованных в API, может быть, ошибка, возможно, функция, 4. только ее дочерний элемент, например. JMenu может это сделать, jMenuBar1.setVisible (jMenu1.isSelected()); доступный из ButtonModel EDIT (isEnabled, остальные события доступны из MenuListener), 5. Я должен проверять события из PropertyChangeListener, – mKorbel

Смежные вопросы