2017-08-16 2 views
1

Ich habe ein System, in dem ich in der Lage sein muss, ein einfaches "weiter?" Stilfrage. Es gibt ein Textfeld und eine Schaltfläche. Ändere entweder das Textfeld isoliert oder drücke den Knopf isoliert und ich muss einen Benutzer zur Bestätigung auffordern können. Das gibt mir einen Fokus-Listener auf das Textfeld und einen Aktions-Listener auf der Schaltfläche.Wie wird JOptionPane nicht synchronisiert?

Wenn ich jedoch das Feld bearbeite und sofort auf die Schaltfläche klicke, erscheinen zwei Bestätigungsdialoge - der aus dem Fokus-Listener und dann der aus dem Aktions-Listener unmittelbar danach. Jetzt brauche ich natürlich nur noch eine Bestätigung, also habe ich versucht, die Funktion zu synchronisieren, die den JOptionPane auslöst, so dass er nicht zweimal eingegeben wird, aber das scheint keine Wirkung zu haben.

Einige Code dies demonstrieren:

public class Main extends JFrame { 
    static public void main(String [] args) { 
     SwingUtilities.invokeLater(() -> { 
      Main m = new Main(); 
      m.setVisible(true); 
     }); 
    } 

    private JTextField field; 
    private JButton button; 

    private boolean isValid; 

    public Main() { 
     isValid = false; 

     setLayout(new BorderLayout()); 

     field = new JTextField(15); 
     field.addFocusListener(new FocusListener() { 
      @Override 
      public void focusGained(FocusEvent arg0) {} 

      @Override 
      public void focusLost(FocusEvent e) { 
       doValidate(); 
      } 
     }); 
     add(field, BorderLayout.CENTER); 

     button = new JButton("Push Me"); 
     button.addActionListener((ActionEvent e) -> { 
      doValidate(); 
      doAction(); 
     }); 
     add(button, BorderLayout.SOUTH); 

     pack(); 
    } 

    private synchronized void doValidate() { 
     System.out.println("Validating"); 
     if(!isValid) { 
      int answer = JOptionPane.showConfirmDialog(this, "Really do it?"); 
      if(answer == JOptionPane.YES_OPTION) 
       isValid = true; 
     } 
    } 

    private void doAction() { 
     System.out.println("Action done!"); 
    } 
} 

Zunächst einmal, diese etwas überraschende Verhalten ist. Ich würde mich freuen, wenn jemand eine Erklärung dafür hätte, wie Swing/JOptionPane in der Lage ist, das synchronisierte Keyword zu umgehen.

Wie zu behandeln, ist mein Denken, dass ich einen Thread implementieren muss, der auf die Antwort auf den Bestätigungsdialog wartet. Dann muss ich überprüfen, ob der Thread aktiv ist oder nicht (wenn das Dialogfeld bereits aktiv ist), und wenn es abgelaufen ist, muss ich einen Listener hinzufügen, wenn die Antwort gegeben wird. Ich wäre bereits vorangegangen und hätte dies getan, aber es fühlt sich an, als würde ich eine Lösung für das Problem übersteuern, zumal ich so wenig Verständnis dafür habe, warum dies überhaupt geschieht. Außerdem kann ich mir schon einige Fälle vorstellen, in denen ich in Schwierigkeiten geraten würde, was es wahrscheinlich fehleranfälliger macht.

=== === EDIT

klar sein, pop diese Meldungsfelder in der gleichen Zeit auf, nicht in Folge. Zum Beispiel:

Two panes

Antwort

1

Synchronized bedeutet, dass 2 Fäden um den Block in der gleichen Zeit nicht betreten können, nicht immer. Sie werden einfach darauf warten, dass andere Threads ihre Sperre für diese Methode freigeben und sie dann aufrufen. Daher Ihre 2 Dialoge.

Das ist wahrscheinlich sowieso nicht relevant, da ich denke, die UI-Rendering ist der gleiche Thread, so dass Sie nur die gleiche Methode zweimal aus zwei separaten UI-Ereignisse aufrufen (ich kann falsch daran sein).

Damit es funktioniert, mach dir keine Sorgen über Threads, stattdessen schauen Sie auf die DocumentListener.

+0

Also, was verwirrend ist, dass JOptionPane.showConfirmDialog() soll eine Sperrfunktion. Die Dialoge erscheinen nicht nacheinander (das wäre sinnvoll), sie öffnen sich parallel! Wenn Sie den Code ausprobieren, sehen Sie, dass die Meldung "Validieren" zweimal erscheint, bevor Sie eine beliebige Taste drücken. –

0

Ich empfehle das Folgende hinzuzufügen, so dass ein Klick auf das rote X das Programm beendet.

setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //new 

Bitte beachten Sie, dass Sie Ihr gewünschtes Verhalten einfach durch Entfernen der Schaltfläche Listener erhalten können. Hier

ist der Code, den ich glaube, bekommt man das Verhalten, das Sie wollen:

package swingdemo1; 

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 

public class SwingDemo1 extends JFrame { 
    static public void main(String [] args) { 
     SwingUtilities.invokeLater(() -> { 
      SwingDemo1 m = new SwingDemo1(); 
      m.setVisible(true); 
     }); 
    } 

    private JTextField field; 
    private JButton button; 

    private boolean isValid; 
    private boolean validationDone; 
    String state; 

    public SwingDemo1() { 

     setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //new 

     isValid = false; 

     setLayout(new BorderLayout()); 

     field = new JTextField(15); 
     field.addFocusListener(new FocusListener() { 
      @Override 
      public void focusGained(FocusEvent arg0) { 

      } 
      @Override 
      public void focusLost(FocusEvent e) {    
        doValidate(); 
        doAction();          
      } 
     }); 
     add(field, BorderLayout.CENTER); 

     button = new JButton("Push Me"); 
     /*               //new 
     button.addActionListener((ActionEvent e) -> { 
      System.out.println("ActionEvent: " + e.getActionCommand());    
       doValidate(); 
       doAction(); 
      }); 
     */               //new 
     add(button, BorderLayout.SOUTH); 

     pack(); 
    } 

    private synchronized void doValidate() { 
     System.out.println("Validating"); 
     if(!isValid) { 
      int answer = JOptionPane.showConfirmDialog(this, "Really do it?"); 
      if(answer == JOptionPane.YES_OPTION) 
       isValid = true; 
     }   
    } 

    private void doAction() { 
     System.out.println("Action done!"); 
    } 
} 
+0

Im Produktionssystem gibt es also mehrere Felder. Daher wäre es nicht wünschenswert, die Aktion abzuschließen, wenn der Fokus auf eine der Gruppen verloren geht.Wenn keines der Felder berührt wird (angenommen, sie werden von einer Datei geladen), würde ich vor dem Ausführen der Aktion einen Validierungsschritt benötigen. –

+0

Ich empfehle, dass Sie die Aktion nicht ausführen, wenn Sie den Fokus verlieren. Ich dachte nur anhand Ihrer Frage und Ihres Beispiels, dass dies eine Voraussetzung ist. Es macht mehr Sinn, die Aktion nur mit Tastenhörern zu beenden. – Charles

Verwandte Themen