Активировать JMenuBar при наведении курсора

JMenuBar не начинает показывать JMenuItem как выбрал или отобразил всплывающие окна JMenu до тех пор, пока они не станут нажал первым. После того, как вы нажмете где-нибудь в JMenuBar, все эти элементы реагируют на наведение курсора мыши.

Я хотел бы обойти требуемый начальный щелчок и активировать его автоматически при наведении курсора мыши. Есть ли способ сделать это?


person springcorn    schedule 25.08.2012    source источник
comment
Есть ли веская причина, по которой вы хотите это сделать? Все строки меню во всех приложениях ведут себя так   -  person Robin    schedule 26.08.2012
comment
Что ж, у моего меню индивидуальный вид, и такое поведение подходит ему более естественно. Кроме того, я считаю, что такое поведение намного более интерактивно для пользователя.   -  person springcorn    schedule 26.08.2012


Ответы (2)


Способ состоит в том, чтобы добавить MouseListener в JMenu и прослушивать события mouseEntered. В обработчиках событий вам просто нужно щелкнуть по нему с помощью doClick. Например,

jMenuFile.addMouseListener(new MouseListener(){
    public void mouseEntered(MouseEvent e) {
       jMenuFile.doClick();
    }
  ...
});

После того, как программный щелчок мыши введен, всплывающее меню открывается автоматически. Чтобы активировать весь JMenuBar, вы должны добавить слушателя для каждого JMenu. Для этого лучше создать объект слушателя отдельно.

У меня есть два пункта меню на панели, поэтому я сделал:

MouseListener ml = new MouseListener(){
    public void mouseClicked(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {
        ((JMenu)e.getSource()).doClick();
    }
  };
  jMenuFile.addMouseListener(ml);
  jMenuHelp.addMouseListener(ml);

Если у вас так много пунктов меню на панели, вы можете просто перебрать его:

for (Component c: jMenuBar1.getComponents()) {
    if (c instanceof JMenu){
        c.addMouseListener(ml);
    }
}
person Roman C    schedule 25.08.2012
comment
Я понимаю слушателя mouseEntered, но как активировать весь JMenuBar из mousentered? - person springcorn; 26.08.2012
comment
Спасибо. Это поставило меня на правильный путь, но я полагаю, я надеялся, что есть более простой способ сделать это, например jMenuBar.activate (), а не индивидуальное принудительное нажатие. Для JMenuItem вы не можете вместо этого вызвать doClick (), я считаю, что лучший способ сгенерировать это поведение - setArmed (true) - person springcorn; 26.08.2012
comment
Также рассмотрите MouseAdapter вместо MouseListener. - person trashgod; 26.08.2012

Первоначальный и принятый ответ Roman C не будет автоматически закрывать меню с дочерними MenuItems как часть JMenuBar.

Запуск ((JMenu) e.getSource ()). DoClick (); on the mouseEntered имитирует щелчок по одному из родительских элементов JMenu, но его нельзя просто добавить в метод mouseExited, поскольку MouseListener необходимо прикрепить к дочерним элементам MenuItems, а также к родительским элементам JMenu. (Этого не происходит при обычном назначении MenuBar - только присоединение к родительским объектам JMenu).

Кроме того, проблема возникает из-за попытки заставить прослушиватель MouseExit запускать метод «закрытия» ТОЛЬКО, когда мышь покидает всю структуру меню (то есть раскрывающееся меню дочернего меню).

Ниже приведен полностью рабочий ответ, взятый из моего действующего приложения:

Способ, которым я решил закрывать меню при выходе мыши, заключался в том, чтобы запустить логическую переменную isMouseOut в верхней части конструктора для отслеживания, а затем выделить MouseListener более удобным для объектно-ориентированным способом способом отслеживания нескольких событий MouseIn-MouseOut. когда пользователь взаимодействует с меню. Это вызывает отдельный метод menuClear, действующий на состояние логического "isMouseOut". Класс реализует MouseListener. Вот как это делается.

Создайте ArrayList, сначала добавив все элементы меню в этот массив. Вот так:

    Font menuFont = new Font("Arial", Font.PLAIN, 12);
    JMenuBar menuBar = new JMenuBar();
    getContentPane().add(menuBar, BorderLayout.NORTH); 

// Array of MenuItems
    ArrayList<JMenuItem> aMenuItms = new ArrayList<JMenuItem>();
    JMenuItem mntmRefresh = new JMenuItem("Refresh");
    JMenuItem mntmNew = new JMenuItem("New");
    JMenuItem mntmNormal = new JMenuItem("Normal");
    JMenuItem mntmMax = new JMenuItem("Max");
    JMenuItem mntmStatus = new JMenuItem("Status");
    JMenuItem mntmFeedback = new JMenuItem("Send Feedback");
    JMenuItem mntmEtsyTWebsite = new JMenuItem("EtsyT website");
    JMenuItem mntmAbout = new JMenuItem("About");

    aMenuItms.add(mntmRefresh);
    aMenuItms.add(mntmNew);
    aMenuItms.add(mntmNormal);
    aMenuItms.add(mntmMax);
    aMenuItms.add(mntmStatus);
    aMenuItms.add(mntmFeedback);
    aMenuItms.add(mntmEtsyTWebsite);
    aMenuItms.add(mntmAbout);

затем перебрать arrayList на этом этапе, добавив MouseListener, используя цикл for ():

  for (Component c : aMenuItms) {
        if (c instanceof JMenuItem) {
            c.addMouseListener(ml);
        }
    }

Теперь установите родителей JMenu для MenuBar:

// Now set JMenu parents on MenuBar
    final JMenu mnFile = new JMenu("File");
    menuBar.add(mnFile).setFont(menuFont);
    final JMenu mnView = new JMenu("View");
    menuBar.add(mnView).setFont(menuFont);
    final JMenu mnHelp = new JMenu("Help");
    menuBar.add(mnHelp).setFont(menuFont);

Затем добавьте дочерние элементы раскрывающегося меню к родительским элементам JMenu:

// Now set menuItems as children of JMenu parents
    mnFile.add(mntmRefresh).setFont(menuFont);
    mnFile.add(mntmNew).setFont(menuFont);
    mnView.add(mntmNormal).setFont(menuFont);
    mnView.add(mntmMax).setFont(menuFont);
    mnHelp.add(mntmStatus).setFont(menuFont);
    mnHelp.add(mntmFeedback).setFont(menuFont);
    mnHelp.add(mntmEtsyTWebsite).setFont(menuFont);
    mnHelp.add(mntmAbout).setFont(menuFont);

Добавьте mouseListeners к родителям JMenu как отдельный шаг:

    for (Component c : menuBar.getComponents()) {
        if (c instanceof JMenu) {
            c.addMouseListener(ml);
        }
    }

Теперь, когда все дочерние элементы menuItem имеют своих собственных слушателей, которые отделены от родительских элементов JMenu и самого MenuBar - важно определить тип объекта в экземпляре MouseListener (), чтобы вы могли автоматически открывать меню при наведении курсора мыши (в в этом примере 3x родителей JMenu) НО ТАКЖЕ избегает ошибок дочерних исключений и позволяет четко идентифицировать mouseOUT в структуре меню, не пытаясь отслеживать, где находится позиция мыши. MouseListener выглядит следующим образом:

MouseListener ml = new MouseListener() {
        public void mouseClicked(MouseEvent e) {
        }

        public void mousePressed(MouseEvent e) {
        }

        public void mouseReleased(MouseEvent e) {
        }

        public void mouseExited(MouseEvent e) {
            isMouseOut = true;
            timerMenuClear();
        }

        public void mouseEntered(MouseEvent e) {
            isMouseOut = false;
            Object eSource = e.getSource();
            if(eSource == mnHelp || eSource == mnView || eSource == mnFile){
                ((JMenu) eSource).doClick();
            }
        }
    }; 

Вышеупомянутое только имитирует щелчок мышью по «родителям» JMenu (3 раза в этом примере), поскольку они являются триггерами для раскрывающихся списков дочернего меню. Метод timerMenuClear () вызывает MenuSelectionManager, чтобы очистить любую точку selectedpath, которая была активна во время реального mouseOUT:

public void timerMenuClear(){
    ActionListener task = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
          if(isMouseOut == true){
              System.out.println("Timer");
          MenuSelectionManager.defaultManager().clearSelectedPath();
          }
      }
  };        
    //Delay timer half a second to ensure real mouseOUT
  Timer timer = new Timer(1000, task); 
  timer.setInitialDelay(500);        
  timer.setRepeats(false);
  timer.start();
}

Мне потребовалось небольшое тестирование, отслеживание того, к каким значениям я мог получить доступ в JVM во время ее разработки - но это работает! даже с вложенными меню :) Надеюсь, этот полный пример многим будет очень полезен.

person Martin Sansone - MiOEE    schedule 02.01.2015