Romano C de la respuesta inicial y aceptada no será AUTO. Cierre el menú con elementos de menú secundarios como parte de JMenuBar.
Ejecutando un ((JMenu) e.getSource()). DoClick(); en el mouseEntered simula el clic en uno de los padres de JMenu, pero no se puede agregar simplemente al método mouseExited ya que el MouseListener se debe adjuntar a los elementos de menú secundarios así como a los padres de JMenu. (Lo cual no ocurre en la asignación normal a MenuBar, solo se conecta a los objetos JMenu padre).
Además, surge un problema al intentar que el oyente MouseExit dispare un método "cerrado" SÓLO cuando el mouse ha abandonado toda la estructura del Menú (es decir, las listas desplegables del menú Niño).
a continuación es una respuesta totalmente funcional tomado de mi aplicación en vivo:
La forma en que resolvió el menú de cerca a cabo ratón era correr una variable booleana "isMouseOut" en la parte superior del constructor para realizar un seguimiento , y luego asigne MouseListener de una manera más amigable para OO para realizar un seguimiento de los múltiples eventos MouseIn-MouseOut a medida que el usuario interactúa con el menú. Lo cual llama a un método de menú separado que actúa sobre el estado del booleano "isMouseOut". La clase implementa MouseListener. Así es como se hace.
Cree una ArrayList agregando primero todos los elementos del menú a esta matriz.Al igual que:
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);
entonces iterar sobre la arrayList en esta etapa la adición de un MouseListener usando el for() bucle:
for (Component c : aMenuItms) {
if (c instanceof JMenuItem) {
c.addMouseListener(ml);
}
}
ahora establecido padres JMenu para el 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);
A continuación, agregue el menú desplegable Ítems hijos a los padres de 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);
Añadir los mouseListeners a los padres JMenu como un paso separado:
for (Component c : menuBar.getComponents()) {
if (c instanceof JMenu) {
c.addMouseListener(ml);
}
}
Ahora que los elementos lineaMenu niño, todos tienen sus propios oyentes, que están separados de los elementos del padre JMenu y el propio BarraDeMenús - Es importante identificar el tipo de objeto dentro de la instanciación MouseListener() para que el menú se abra automáticamente al pasar el mouse (en este ejemplo los 3x JMenu parents) PERO TAMBIÉN evita los errores de excepción hijo y permite la identificación limpia de mouseOUT de la estructura del menú sin intentar monitorear dónde la posición del mouse es. El MouseListener es el siguiente:
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();
}
}
};
Lo anterior sólo simula el clic del ratón en el JMenu 'padres' (3x en este ejemplo), ya que son los desencadenantes de los menús desplegables del menú infantil. El método timerMenuClear() llama a la MenuSelectionManager para vaciar cualquier punto selectedpath estaba en vivo en el momento de mouseOut real:
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();
}
Me tomó un poco de pruebas, control ¿Qué valores pude acceder dentro de la JVM durante su desarrollo - pero funciona un placer! incluso con menús anidados :) Espero que muchos encuentren este ejemplo completo muy útil.
¿Hay alguna buena razón por la que quieres hacer esto? Todas las barras de menús en todas las aplicaciones se comportan así – Robin
Bueno, mi menú tiene un aspecto personalizado y este comportamiento se ajusta de forma más natural. Además, creo que este comportamiento es mucho más interactivo para el usuario. – springcorn