Zeigt/versteckt ein JPopupMenu von einem JButton; FocusListener funktioniert nicht?
Brauchte ich einen JButton mit einer angebrachten dropdown-Menü "Stil". Also nahm ich ein JPopupMenu und befestigt Sie an den JButton im Wege und Sie können im code sehen Sie unten. Was er tun muss, ist dieses:
- zeigen Sie das popup beim anklicken
- es verstecken, wenn er gedrückt wird ein zweites mal
- verstecken, wenn ein Element ausgewählt ist, in dem popup -
- ausblenden, wenn der Benutzer klickt irgendwo sonst auf dem Bildschirm
Diese 4 Dinge funktionieren, aber da der boolean-flag, das ich verwende, wenn der Benutzer klickt irgendwo anders oder wählt ein Objekt aus, muss ich zweimal klicken Sie auf den button, bevor es wieder auftaucht. Deshalb habe ich versucht, um einen FocusListener (das ist absolut nicht mehr reagiert), um das zu beheben, und setzen Sie das flag false in diesen Fällen.
EDIT: Letzter Versuch eine Antwort zu posten...
Hier sind die Zuhörer: (Es ist in einer Klasse JButton erweitern, so dass der zweite Hörer ist auf den JButton.)
//Show popup on left click.
menu.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent e) {
System.out.println("LOST FOCUS");
isShowingPopup = false;
}
@Override
public void focusGained(FocusEvent e) {
System.out.println("GAINED FOCUS");
}
});
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("isShowingPopup: " + isShowingPopup);
if (isShowingPopup) {
isShowingPopup = false;
} else {
Component c = (Component) e.getSource();
menu.show(c, -1, c.getHeight());
isShowingPopup = true;
}
}
});
Ich ve wurde kämpfen mit diesem für viel zu lange jetzt. Wenn jemand kann mir eine Ahnung, was falsch mit diesem, wäre es toll!
Dank!
Code:
public class Button extends JButton {
//Icon.
private static final ImageIcon ARROW_SOUTH = new ImageIcon("ArrowSouth.png");
//Unit popup menu.
private final JPopupMenu menu;
//Is the popup showing or not?
private boolean isShowingPopup = false;
public Button(int height) {
super(ARROW_SOUTH);
menu = new JPopupMenu(); //menu is populated somewhere else
//FocusListener on the JPopupMenu
menu.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent e) {
System.out.println("LOST FOCUS");
isShowingPopup = false;
}
@Override
public void focusGained(FocusEvent e) {
System.out.println("GAINED FOCUS");
}
});
//ComponentListener on the JPopupMenu
menu.addComponentListener(new ComponentListener() {
@Override
public void componentShown(ComponentEvent e) {
System.out.println("SHOWN");
}
@Override
public void componentResized(ComponentEvent e) {
System.out.println("RESIZED");
}
@Override
public void componentMoved(ComponentEvent e) {
System.out.println("MOVED");
}
@Override
public void componentHidden(ComponentEvent e) {
System.out.println("HIDDEN");
}
});
//ActionListener on the JButton
addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("isShowingPopup: " + isShowingPopup);
if (isShowingPopup) {
menu.requestFocus();
isShowingPopup = false;
} else {
Component c = (Component) e.getSource();
menu.show(c, -1, c.getHeight());
isShowingPopup = true;
}
}
});
//Skip when navigating with TAB.
setFocusable(true); //Was false first and should be false in the end.
menu.setFocusable(true);
}
}
- Also, das Hauptproblem, das ich habe, ist, dass focusGained() und focuslost wurde (), nie ausgelöst, auch wenn ich halten Sie auf das popup erscheinen und verschwinden.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hier ist ein weiterer Ansatz, der nicht allzu schlecht der hack, wenn auch nicht elegant, und, die, soweit ich feststellen konnte, funktioniert. Zuerst, ganz oben, ich fügte hinzu, eine zweite boolean genannt
showPopup
.Den
FocusListener
muss wie folgt sein:Den
isShowingPopup
boolean nicht geändert, sonst nirgends-wenn es den Fokus erhält, nimmt er es gezeigt und wenn es den Fokus verliert, nimmt er es nicht.Nächsten, die
ActionListener
auf die Schaltfläche ist das anders:Jetzt kommt das wirklich neue etwas. Es ist ein
MouseListener
auf die Schaltfläche:Grundsätzlich
mousePressed
wird aufgerufen, bevor das Menü verliert den Fokus, soisShowingPopup
reflektiert, ob das popup angezeigt wurde, bevor die Taste gedrückt wird. Dann, wenn das Menü da war, setzen wir einfachshowPopup
zufalse
, so dass dieactionPerformed
Methode nicht im Menü anzeigen, sobald es aufgerufen wird (nachdem Sie die Maus loslassen).Diese verhielten sich, wie erwartet, in jedem Fall aber eins: wenn das Menü gezeigt und der Benutzer drückt mit der Maus auf den button, aber veröffentlicht es außen
actionPerformed
nie genannt wurde. Dies bedeutete, dassshowPopup
blieb falsch und das Menü wurde nicht angezeigt das nächste mal, wenn die Taste gedrückt wurde. Um dies zu beheben, diemouseReleased
Methode setztshowPopup
. DiemouseReleased
Methode wird aufgerufen, nachdemactionPerformed
, soweit ich das sagen kann.Ich spielte mit den daraus resultierenden Taste für ein bisschen, tut all die Dinge, die ich denken konnte, auf die Schaltfläche, und es funktionierte wie erwartet. Allerdings bin ich mir nicht 100% sicher, dass die Ereignisse passieren immer in der gleichen Reihenfolge.
Letztlich, ich denke, das ist zumindest einen Versuch Wert.
Hier ist eine Variante von Bernstein Shah, "big hack" Vorschlag, den ich gerade gemacht. Ohne die isShowingPopup Flagge...
Es ist nicht bulletproof, aber es funktioniert ganz gut, bis jemand kommt mit einer unglaublich langsamen klicken Sie zum schließen des popup (oder eine sehr schnelle zweite klicken, um Sie erneut zu öffnen...).
Wie gesagt in den Kommentaren, das ist nicht die eleganteste Lösung, aber es ist schrecklich einfach und es funktioniert in 98% der Fälle.
Offen für Vorschläge!
Könnten Sie die JPopupMenu.isVisible() statt deine Boolean variable, um den aktuellen Zustand des popup-Menü.
Haben Sie versucht, indem eine
ComponentListener
zu denJPopupMenu
, so dass Sie wissen, Wann es war-und ausgeblendet (und aktualisieren Sie IhreisShowingPopup
Flagge entsprechend)? Ich bin mir nicht sicher, hören für Fokus ändert, ist unbedingt der richtige Ansatz.Was Sie brauchen, ist ein PopupMenuListener:
Ich eingefügt, diese in Ihren code ein und bestätigt, dass es funktioniert.
Gut, ich kann nicht sein sicher, ohne dass alle Ihre code, aber ist es möglich, dass das popup eigentlich nie den Fokus erhält überhaupt? Ich hatte schon Probleme mit Dingen, die " nicht immer den Fokus richtig in Schwung vor, so könnte es die Ursache sein. Versuchen Sie anrufen
setFocusable(true)
auf das Menü und rufen dannrequestFocus()
wenn Sie das Menü erscheint.Ich habe versucht, die Antwort von Tichon Jelvis (Einführung einer intelligenten Kombination von focusListener und mouseListener). Es funktioniert nicht für mich auf Linux (Java7/gtk). 🙁
Lesen http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#requestFocus%28%29 es steht geschrieben: "Beachten Sie, dass die Verwendung dieser Methode wird abgeraten, da sein Verhalten ist Plattform abhängig."
Kann es sein, dass die Reihenfolge der listener ruft verändert mit Java7 oder es ändert sich mit GTK vs Windows. Ich würde nicht empfehlen, diese Lösung, wenn Sie möchten, um unabhängig von der Plattform sein.
BTW: ich habe einen neuen account auf stackoverflow zu geben, dieser Hinweis. Es scheint, ich bin nicht berechtigt einen Kommentar zu seiner Antwort (wegen Ruf). Aber es scheint, ich habe eine Schaltfläche, um es zu Bearbeiten. Diese stackoverflow ist eine sehr lustige Sache. 🙂