7

Ich habe viel über Swing, Threading, invokeLater(), SwingWorker usw. gelesen, aber ich kann es einfach nicht verstehen, also habe ich versucht, ein wirklich einfaches Programm zur Veranschaulichung zu erstellen . Ich habe mir viele Beispiele angesehen, aber keine von ihnen scheint zu zeigen, was ich gerade versuche. Es ist lange her, dass ich in Java programmiert habe (ich habe wirklich nichts in Java gemacht, seit ich AP Informatik 2003 in der High School genommen habe), also bitte, nimm mich mit.Aktualisiere ich Swing-Komponente außerhalb von EDT?

Hier ist, was ich in meinem Beispiel versuche. Ich habe einen Button und ein Label, und wenn ich auf den Button klicke, möchte ich, dass das Programm für 3 Sekunden pausiert, bevor ich einen Punkt an den Text des Labels anschließe. Während dieser 3 Sekunden möchte ich, dass die GUI normal erscheint und weiterhin auf weitere Klicks reagiert. Hier ist, was ich schrieb:

import javax.swing.SwingWorker; 

public class NewJFrame extends javax.swing.JFrame 
{ 
    private javax.swing.JButton jButton1; 
    private javax.swing.JLabel jLabel1; 

    public NewJFrame() 
    { 
     initComponents(); 
    } 
    private void initComponents() 
    { 
     jButton1 = new javax.swing.JButton(); 
     jLabel1 = new javax.swing.JLabel(); 
     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 
     jButton1.setText("Button"); 
     jButton1.addActionListener(new java.awt.event.ActionListener() 
     { 
      public void actionPerformed(java.awt.event.ActionEvent evt) 
      { 
       jButton1ActionPerformed(evt); 
      } 
     }); 
     getContentPane().add(jButton1, java.awt.BorderLayout.CENTER); 
     jLabel1.setText("Text"); 
     getContentPane().add(jLabel1, java.awt.BorderLayout.PAGE_END); 
     pack(); 
    } 

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) 
    { 
     SwingWorker worker=new SwingWorker() 
     { 
      protected Object doInBackground() 
      { 
       try{Thread.sleep(3000);} 
       catch (InterruptedException ex){} 
       return null; 
      } 
     }; 
     worker.execute(); 
     jLabel1.setText(jLabel1.getText()+"."); 
    } 

    public static void main(String args[]) 
    { 
     java.awt.EventQueue.invokeLater(new Runnable() 
     { 
      public void run(){ new NewJFrame().setVisible(true); } 
     }); 
    } 
} 

mit diesem Code, wenn ich auf die Schaltfläche klicken, wird die Zeit unmittelbar auf dem Etikett angehängt, das macht Sinn für mich, weil ich schaffe und einen Hintergrund-Thread schlafen, so dass die EDT verfügbar, um das Etikett sofort zu aktualisieren. Also habe ich versucht, dies:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) 
{ 
    Thread thread = new Thread(); 
    try{ thread.sleep(3000);} 
    catch (InterruptedException ex){} 
    jLabel1.setText(jLabel1.getText()+"."); 
} 

Das funktioniert fast außer dass es blockiert die EDT verursacht die Taste drei Sekunden blau werden, bevor die Zeit auf dem Etikett der Text angehängt. Ich will nicht die Taste, um aussieht es für die ganzen 3 Sekunden gedrückt ist wird, wenn es wurde wirklich geklickt nur schnell, so dass ich versuchte, dies:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) 
{ 
    SwingWorker worker=new SwingWorker() 
    { 
     protected Object doInBackground() 
     { 
      try{Thread.sleep(3000);} 
      catch (InterruptedException ex){} 
      jLabel1.setText(jLabel1.getText()+"."); 
      return null; 
     } 
    }; 
    worker.execute(); 
} 

Dies scheint zu funktionieren, sind aber nicht ich Aufruf jLabel1 .setText (...) vom Hintergrund-Thread und nicht vom EDT, und damit die "Swing Single Threading Rule?" Wenn ja, gibt es einen besseren Weg, um den gewünschten Effekt zu erzielen? Wenn nicht, können Sie bitte erklären warum?

+2

+1 für Mühe und Forschung !! – MadProgrammer

Antwort

4

Sie ganz in der Nähe ist ...

stattdessen so etwas wie dies versucht.

SwingWorker worker=new SwingWorker() 
{ 
    protected Object doInBackground() 
    { 
     try{ 
      Thread.sleep(3000); 
     }catch (InterruptedException ex){} 
     return null; 
    } 

    // This is executed within the context of the EDT AFTER the worker has completed...  
    public void done() { 
     jLabel1.setText(jLabel1.getText()+"."); 
    } 
}; 
worker.execute(); 

Sie können überprüfen, um zu sehen, wenn Sie in der EDT durch den Einsatz von EventQueue.isDispatchingThread()

Aktualisiert

Du läufst auch eine javax.swing.Timer die ... einfacher sein könnte nutzen könnten

Timer timer = new Timer(3000, new ActionListener() { 
    public void actionPerformed(ActionEvent evt) { 
     jLabel1.setText(jLabel1.getText()+"."); 
    } 
}); 
timer.setRepeats(false); 
timer.start(); 
+0

Danke für die schnellen und prägnanten Antworten! Diese done() Methode macht genau das, wonach ich gesucht habe. Der Timer ist auch ziemlich geschickt. –

+0

Vielen Dank für eine wirklich gute und durchdachte Frage !! – MadProgrammer