2016-09-14 6 views
3

Auf meine Frage hier zu erklären, ist ein MCVE wo KLICKEN Klicken ein JButton auf JDialog A öffnet JDialog B:Lange Prozess unter Swing-GUI: unerwartete Verzögerung

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.FlowLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JDialog; 

public class DiagA extends JDialog { 

    private DiagB diag; 

    public DiagA() { 

     super(); 
     setTitle("main diag"); 
     setSize(200, 150); 
     setLocation(400,400); 

     JButton btn = new JButton("Show DiagB"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 

       showDiag(); 
      } 
     }); 
     add(btn, BorderLayout.NORTH); 

     //make main frame visible 
     setVisible(true); 
    } 

    void showDiag() { 

     if(diag == null) { 

      diag = new DiagB(); 

      //this prints out as expected 
      System.out.println("set visible done"); 

      try { 
       Thread.sleep(3000); 
      } catch (InterruptedException ex) {} 

      //only after the delay diag shows in full 
     } 
    } 

    public static void main(String[] args) { 
     new DiagA(); 
    } 
} 

class DiagB extends JDialog { 

    public DiagB() { 

     super(); 
     setTitle("2nd diag"); 
     setSize(150, 100); 
     setLocation(600,420); 
     setLayout(new FlowLayout(FlowLayout.CENTER)); 
     getContentPane().setBackground(Color.YELLOW); 
     setVisible(true); 
    } 
} 

Wie Sie im Code sehen kann ich eine 3 Sekunden hinzugefügt Verzögerung nach dem Erstellen DiagB. Klick auf den Button DiagB zeigt wie folgt aus:

enter image description here

Erst nach 3 Sekunden Verzögerung endet, DiagB zeigt in voller Länge:

enter image description here

Meine Fragen sind:
a. Warum zeigt DiagB nicht vollständig, nachdem es aufgebaut ist? (Es zeigt sich nur dann vollständig, wenn showDiag() zurückkehrt).
b. Der Grund für meine Frage ist, dass DiagB aktualisiert werden muss, durch lange Prozesse in DiagA.
Was ist der richtige Weg zu aktualisieren? Ist für jedes Update ein erforderlich?

+1

Wenn es für die Anzeige ist, anstatt Benutzer-Interaktion, sollte es keine 'JDialog' sein, die für, nun ja, mit der Benutzer-Dialog. Und in einem Event-Handler sollte es niemals einen Sleep (oder irgendeinen anderen langen Vorgang) geben. – RealSkeptic

+1

@RealSkeptic Ich verstehe, was Sie über lange Operationen in einem Event-Handler sagen. ('JDialog' oder' JFrame' wird in diesem Fall keinen großen Unterschied machen. Ein 'JDialog' könnte zum Beispiel für die Modalität benötigt werden). – c0der

+1

Modalität bedeutet Benutzerinteraktion wird sofort benötigt. Ansonsten wird es nicht korrekt verwendet. – RealSkeptic

Antwort

4

a. showDiag läuft auf dem GUI-Thread. Die GUI ist vollständig inaktiv, während Sie den GUI-Thread in den Ruhezustand versetzen.

b. Ja, verwenden Sie SwingWorker für lange laufende Aufgaben und verwenden Sie SwingUtilities.invokeLater(), um GUI-Update-Aufgaben zurück an den GUI-Thread zu senden. Alternativ implementieren Sie SwingWorker#done(), eine bequeme Methode, die auf dem GUI-Thread ausgeführt wird, nachdem der Task SwingWorker abgeschlossen ist.

+0

Danke. Ich sehe, was Sie sagen, "planen Sie die Aktion für später". Die Verwendung eines 'SwingWorker' für jeden Update-Prozess ist umständlich. Ich würde es lieber im aktualisierten ("DiagB") Objekt implementieren. Irgendein Rat ? – c0der

+1

@MarkoTopolnik Beachten Sie, dass das OP den Schlaf verwendet hat, um eine langwierige Aufgabe zu simulieren ***, daher scheint ihr Vorschlag eines ** 'SwingWorker' ** am unteren Ende des Beitrags die beste Strategie dafür zu sein. –

+2

@AndrewThompson True, ich aktualisiert, um 'SwingWorker' +' invokeLater' zu empfehlen. –

0

Basierend auf Marko Topolnik Antwort und Andrew Thompson Kommentar, ich verzog den langen Prozess mit einem SwingWorker.
Dies funktioniert:

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.FlowLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.SwingWorker; 

public class DiagA extends JDialog { 

    private FrameB frame; 
    private JButton btn; 

    public DiagA() { 

     super(); 
     setTitle("main frame"); 
     setSize(200, 150); 
     setLocation(400,400); 

     btn = new JButton("Show Frame B"); 
     btn.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 

       show2ndFrame(); 
      } 
     }); 
     add(btn, BorderLayout.NORTH); 
     setVisible(true); 
    } 

    void show2ndFrame() { 

     if(frame == null) { 

      frame = new FrameB(); 
      btn.setText("Exit"); 

     }else { 

      System.exit(0); 
     } 

     doWork(); 
    } 

    private void doWork() { 

     SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>() { 

      @Override 
      protected Void doInBackground() throws Exception { 

       try { 

        for(int i = 1 ; i<=100 ; i++) { 
         //represents a long process 
         Thread.sleep(100); 
         frame.update(i); 
        } 

       } catch (InterruptedException ex) {} 
       return null; 
      } 
     }; 
     sw.execute(); 
    } 

    public static void main(String[] args) { 
     new DiagA(); 
    } 
} 

class FrameB extends JFrame { 

    JLabel label; 

    public FrameB() { 

     super(); 
     setTitle("2nd frame"); 
     setSize(150, 100); 
     setLocation(600,420); 
     setLayout(new FlowLayout(FlowLayout.CENTER)); 
     getContentPane().setBackground(Color.YELLOW); 
     label = new JLabel("0"); 
     add(label); 
     setVisible(true); 
    } 

    void update(int progress) { 

     label.setText(String.valueOf(progress)); 
    } 
} 
Verwandte Themen