2013-09-24 2 views
5

Wenn Sie versuchen, auf ein Element in einem Untermenü zu klicken, ist es natürlich, Ihre Maus schnell über die Menüelemente darunter zu ziehen. Sowohl Windows als auch Mac behandeln dies nativ, indem sie eine kleine Verzögerung vor dem Öffnen eines Menüs setzen. Swing JMenus geht damit nicht klar, und das Menü, über das die Maus kurz schwebt, würde geöffnet werden, bevor die Maus den gewünschten Menüpunkt erreicht.Java Swing - Bei der Auswahl von Elementen in Untermenüs nachgiebiger machen

Zum Beispiel, in dem Bild unten, wenn ich versuchte, Item 3 auszuwählen, aber in dem Prozess meine Maus rutschte kurz über Menu 2, das Menu 1 Untermenü würde verschwinden, bevor ich dazu kam.

Hat jemand irgendwelche Tipps oder Vorschläge, um dies zu umgehen? Meine Idee war, ein benutzerdefiniertes MenuUI zu definieren, das seinem Maushandler einen Timer hinzufügte.

a screen

Hier sind einige einfache Beispiel-Code, der mein Problem veranschaulicht:

public class Thing extends JFrame { 
    public Thing() 
    { 
     super(); 
     this.setSize(new Dimension(500, 500)); 
     final JPopupMenu pMenu = new JPopupMenu(); 
     for (int i = 0; i < 5; i++) 
     { 
      JMenu menu = new JMenu("Menu " + i); 
      pMenu.add(menu); 
      for (int j = 0; j < 10; j++) 
      { 
       menu.add(new JMenuItem("Item " + j)); 
      } 
     } 

     this.addMouseListener(new MouseAdapter() { 

      @Override 
      public void mouseReleased(MouseEvent e) { 
       pMenu.show(Thing.this, e.getX(), e.getY()); 
      } 
     }); 
    } 

    public static void main(String[] args) 
    { 
     Thing t = new Thing(); 
     t.setVisible(true); 
    } 
} 
+0

[Dieser Beitrag] (http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown) einen Algorithmus verwendet ist, dass die durch die Prüfung dieses Problem löst, Pfad, den die Maus des Benutzers nimmt, wenn sie sich von dem Objekt wegbewegt, gegen ein Dreieck, aber ich bin mir nicht sicher, wie portierbar das jQuery-Skript, das am Ende dieses Beitrags verlinkt ist, mit dem Swing-Framework wäre. – akbiggs

Antwort

0

Ich kam mit einer sehr hacky Lösung.

Ich habe eine UI-Klasse, die BasicMenuUI erweitert. Ich überschreibe die createMouseInputListener Methode, um eine benutzerdefinierte MouseInputListener anstelle des privaten handler Objekts innerhalb BasicMenuUI zurückzugeben.

Ich habe dann den Code für die MouseInputListener Implementierung in handler von GrepCode [1], und kopierte es in meine benutzerdefinierten Listener. Ich habe eine Änderung vorgenommen, indem ich einen Timer in mouseEntered gesetzt habe. Mein letzter Code für mouseEntered sieht wie folgt aus:

public void mouseEntered(MouseEvent e) { 
     timer.schedule(new TimerTask() { 

      @Override 
      public void run() { 
       if (menuItem.isShowing()) 
       { 
        Point mouseLoc = MouseInfo.getPointerInfo().getLocation(); 
        Point menuLoc = menuItem.getLocationOnScreen(); 
        if (mouseLoc.x >= menuLoc.x && mouseLoc.x <= menuLoc.x + menuItem.getWidth() && 
          mouseLoc.y >= menuLoc.y && mouseLoc.y <= menuLoc.y + menuItem.getHeight()) 
        { 
         originalMouseEnteredStuff(); 
        } 
       } 
      } 
     }, 100); 
    } 

Bevor die den ursprünglichen Code aufrufen, die in mouseEntered war, habe ich die Maus überprüfen, um sicherzustellen innerhalb dieses Menüs Bereich ist nach wie vor. Ich möchte nicht, dass alle Menüs, die meine Maus überstreicht, nach 100 ms angezeigt werden.

Bitte lassen Sie mich wissen, wenn jemand eine bessere Lösung dafür gefunden hat.

[1] http://www.grepcode.com/file_/repository.grepcode.com/java/root/jdk/openjdk/7-b147/javax/swing/plaf/basic/BasicMenuUI.java/?v=source

2

Anruf setDelay(delay) auf menu Variable, wobei der delay Parameter die Menge von Millisekunden ist für das Menü warten, um zu zeigen, als int.

Diese folgende Codezeile wird die Verzögerung auf 1 Sekunde eingestellt, so dass der Benutzer den Menüpunkt „Menü n“ zu Mouseover hat 1 Sekunde, bevor das Untermenü angezeigt wird: menu.setDelay(1000);

Hier ist ein Ausschnitt aus dem bearbeiteten Code:

for (int i = 0; i < 5; i++) 
{ 
    JMenu menu = new JMenu("Menu " + i); 
    pMenu.add(menu); 
    for (int j = 0; j < 10; j++) 
    { 
     menu.add(new JMenuItem("Item " + j)); 
    } 
    menu.setDelay(1000); 
} 
+0

Dies würde nicht funktionieren, da, obwohl die Verzögerung 1 Sekunde für das Untermenü wäre, in dem der Menüpunkt "versehentlich verschoben über" angezeigt wird, das gewünschte Untermenü sofort verschwindet, sobald Sie mit der Maus über ein anderes Menü fahren. – flutillie

+0

Hier ist ein Screencast von dem, was ich oben mit dem SetDelay (1000) beschrieben habe: http://tinypic.com/r/22wel1dy/5 – flutillie