Deaktivieren Sie JButton während des Hintergrundjobs, um mehrere Klicks zu vermeiden

8

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%     
Alex 08.12.2011, 09:34
quelle

6 Antworten

6

Sie haben zwei Möglichkeiten

1) JButton # setMultiClickThreshhold

2) Sie müssen diese Idee auf die zwei getrennten Aktionen in actionListener oder Action

aufteilen
  • 1.. Schritt, JButton # setEnabeld (false);
  • 2. Schritt, rufen Sie dann den restlichen Code auf, der in javax.swing.Action (von und nach javax.swing.Timer ), SwingWorker oder Runnable#Thread
  • eingeschlossen ist
mKorbel 08.12.2011, 10:06
quelle
2

Okay, hier ist ein Codeausschnitt, der eine Aktion verwendet

  • es deaktiviert sich selbst auf durchgeführt
  • es erzeugt eine Aufgabe, an deren Ende sich wieder aktiviert. Hinweis: Der Einfachheit halber wird hier die Aufgabe von einem Timer simuliert, in der realen Welt würde ein SwingWorker für die Hintergrundarbeit sorgen, seine Eigenschaftsänderungen abhören und sich beim Empfang eines done
  • aktivieren
  • wird als Aktion der Schaltfläche
  • festgelegt

Der Code:

%Vor%     
kleopatra 08.12.2011 11:55
quelle
1

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.

    
StanislavL 08.12.2011 09:39
quelle
1

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

    
Boris Pavlović 08.12.2011 09:42
quelle
1

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:

  1. 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.
  2. 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:

%Vor%

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:

%Vor%

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.

    
ryvantage 16.05.2014 21:12
quelle
0

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.

    
Ashwinee K Jha 08.12.2011 09:44
quelle

Tags und Links