Ich muss den Benutzer stoppen, der mehrere Klicks auf ein JButton macht, während der erste Klick noch ausgeführt wird.
Ich war in der Lage, eine Lösung für dieses Problem zu bekommen, aber ich verstehe nicht ganz, warum es funktioniert.
Ich habe den (auf ein Minimum getrimmten) Code gepostet, der funktioniert und der, der nicht funktioniert.
Im ersten Beispiel (gut) Wenn Sie es ausführen und mehrmals auf die Schaltfläche klicken, wird nur eine Aktion wie im zweiten Beispiel berücksichtigt (schlecht) Wenn Sie mehrmals auf die Maus klicken, wird die Aktion mindestens zweimal ausgeführt.
Das zweite (schlechte) Beispiel verwendet einfach nicht die Methode invokeLater ().
Woher kommt der Unterschied im Verhalten?
%Vor%Und jetzt der "falsche" Code
%Vor%Nach den Informationen, die von @kleopatra und @Boris Pavlović zur Verfügung gestellt wurden, ist der Code, den ich erstellt habe, ziemlich anständig.
%Vor%Sie haben zwei Möglichkeiten
1) JButton # setMultiClickThreshhold
2) Sie müssen diese Idee auf die zwei getrennten Aktionen in actionListener oder Action
aufteilenjavax.swing.Action
(von und nach javax.swing.Timer
), SwingWorker
oder Runnable#Thread
Okay, hier ist ein Codeausschnitt, der eine Aktion verwendet
Der Code:
%Vor%Es gibt zwei weitere Möglichkeiten.
Sie können ein Flag definieren. Stellen Sie es ein, wenn die Aktion gestartet und nach dem Ende zurückgesetzt wird. Überprüfen Sie die Flags in actionPerformed
. Wenn inProgress==true
einfach nichts tut.
Eine andere Möglichkeit besteht darin, den Listener zu entfernen und ihn nach dem Ende der Aktion zuzuweisen.
Der richtige Weg ist ein SwingWorker . Wenn der Benutzer auf die Schaltfläche klickt, bevor er einen Auftrag an SwingWorker
sendet, sollte der Status der Schaltfläche in deaktiviert JButton#setEnabled(false)
geändert werden. Nachdem der SwingWorker
beendet ist, sollte der Job-Status der Schaltfläche auf enabled zurückgesetzt werden. Hier ist Oracles Tutorial zu SwingWorker
Nach Jahren des Umgangs mit der Frustration dieses Problems habe ich eine Lösung implementiert, die meiner Meinung nach die beste ist.
Erstens, warum nichts anderes funktioniert:
JButton::setMutliclickThreshold()
ist nicht wirklich eine optimale Lösung, weil (wie Sie sagten) es keine Möglichkeit gibt zu wissen, wie lange der Schwellenwert gesetzt werden soll. Dies ist nur zum Schutz vor Doppelklick-Happy-Endbenutzern gut, da Sie einen beliebigen Schwellenwert festlegen müssen. JButton::setEnabled()
ist eine offensichtlich fragile Lösung, die das Leben nur viel schwieriger machen wird. Also, ich habe SingletonSwingWorker
erstellt. Singletons werden jetzt Anti-Patterns genannt, aber wenn sie richtig implementiert werden, können sie sehr mächtig sein. Hier ist der Code:
Damit können Sie Klassen erstellen, die SingletonSwingWorker
erweitern und garantieren, dass nur eine Instanz dieser Klasse gleichzeitig ausgeführt werden kann. Hier ist eine Beispielimplementierung:
In meinen SwingWorker
Implementierungen lade ich gerne JProgressBar
, also mache ich das immer bevor ich doInBackground()
starte. Bei dieser Implementierung lade ich JProgressBar
in die initAndGo()
-Methode und ich rufe auch execute()
auf, die in die initAndGo()
-Methode eingefügt werden muss oder die Klasse funktioniert nicht .
Wie auch immer, ich denke, das ist eine gute Lösung und es sollte nicht so schwer sein, den Code zu refaktorieren, um Ihre Anwendungen damit neu zu gestalten.
Sehr interessiert an der Rückmeldung zu dieser Lösung.
Beachten Sie, dass der Code bei der Änderung von Elementen in der GUI im Thread "Event Dispatch" mit invokeLater oder invokeAndWait ausgeführt werden muss, wenn Sie sich in einem anderen Thread befinden. Ein zweites Beispiel ist also falsch, da Sie versuchen, den aktivierten Status von einem anderen Thread zu ändern, was zu unvorhersehbaren Fehlern führen kann.
Tags und Links java thread-safety swing jbutton