SwingWorker: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K (-Leerzeichen nach API, da Bug aufgehoben)
K (Beispiel)
 
(2 dazwischenliegende Versionen von einem anderen Benutzer werden nicht angezeigt)
Zeile 1: Zeile 1:
Da [[Swing]] nicht threadsicher ist, kann es Probleme bereiten, wenn man aus anderen [[Thread|Threads]] auf die UI zugreifen will, beispielsweise um einen Fortschrittsbalken zu akzualisieren. In den Java-Versionen bis 1.5 konnte man sich da nur mit den Methoden invokeLater und invokeAndWait aus den {{API|javax/swing/SwingUtilities|SwingUtilities}} behelfen. Seit Java6 ist auch in der Standard-API eine weitere Möglichkeit als die SwingUtilities Methoden enthalten, die das ganze ein wenig automatisiert. Mit Hilfe der Klasse [http://download.java.net/jdk6/doc/api/javax/swing/SwingWorker.html SwingWorker] lassen sich solche Gui-Updates leicht darstellen.
+
Da [[Swing]] nicht threadsicher ist, kann es Probleme bereiten, wenn man aus anderen [[Thread|Threads]] auf die UI zugreifen will, beispielsweise um einen Fortschrittsbalken zu aktualisieren. In den Java-Versionen bis 1.5 konnte man sich da nur mit den Methoden invokeLater() und invokeAndWait() aus den {{JAPI|SwingUtilities}} behelfen. Seit Java 6 ist auch in der Standard-API eine weitere Möglichkeit als die SwingUtilities Methoden enthalten, die das ganze ein wenig automatisiert. Mit Hilfe der Klasse {{JAPI|SwingWorker}} lassen sich solche GUI-Updates leicht darstellen.
 
==Funktionsweise==
 
==Funktionsweise==
Die Funktionsweise der [[Klasse]] ist folgende: Der startende [[Thread]] erstellt eine Instanz und ruft die execute Methode auf. Diese erstellt einen neuen [[Thread]], in dem die - abstrakte, vom eigenen Programm überschriebene - Methode doInBackground aufruft. Diese kann der publish Methode Objekte übergeben, die dann der (aus dem Event-Dispatch-Thread aufgerufenen!) Methode process übergeben werden - diese sollte dann auch überschrieben werden, um hier die Gui zu verändern. Außerdem kann sie setProgress aufrufen, dann wird aus dem EDT ein evtl. registrierter PropertyChangeListener benachrichtigt. Wenn doInBackground zurückkehrt, ruft der Event-Dispatch-Thread done() auf, und die get Methode, die bis dahin geblockt hat, gibt den Rückgabewert von doInBackground zurück.
+
Die Funktionsweise der [[Klasse]] ist folgende: Der startende [[Thread]] erstellt eine [[Instanz]] und ruft die execute()-[[Methode]] auf. Diese erstellt einen neuen Thread, in dem die - abstrakte, vom eigenen Programm überschriebene - Methode doInBackground() aufruft. Diese kann der publish()-Methode Objekte übergeben, die dann der (aus dem Event-Dispatch-Thread aufgerufenen!) Methode process() übergeben werden - diese sollte dann auch überschrieben werden, um hier die GUI zu verändern. Außerdem kann sie setProgress() aufrufen, dann wird aus dem EDT ein evtl. registrierter {{JAPI|PropertyChangeListener}} benachrichtigt. Wenn doInBackground() zurückkehrt, ruft der Event-Dispatch-Thread done() auf, und die get()-Methode, die bis dahin geblockt hat, gibt den Rückgabewert von doInBackground() zurück.
 
==Grafische Darstellung==
 
==Grafische Darstellung==
 
[[Bild:SwingWorker.gif]]
 
[[Bild:SwingWorker.gif]]
Zeile 7: Zeile 7:
 
==Beispiel==
 
==Beispiel==
 
Hier ein Beispiel, das ein Verzeichnis kopiert:
 
Hier ein Beispiel, das ein Verzeichnis kopiert:
<code=java>import java.awt.*;
+
<syntaxhighlight lang="java">
 +
import java.awt.*;
 
import java.awt.event.*;
 
import java.awt.event.*;
 
import javax.swing.*;
 
import javax.swing.*;
Zeile 54: Zeile 55:
 
   }
 
   }
 
}
 
}
 +
 
class Copier extends SwingWorker<Boolean,File>
 
class Copier extends SwingWorker<Boolean,File>
 
{
 
{
Zeile 144: Zeile 146:
 
     }
 
     }
 
   }
 
   }
}</code=java>
+
}</syntaxhighlight>
  
 
[[Kategorie:Java]]
 
[[Kategorie:Java]]
 
[[Kategorie:Tutorials (Java)]]
 
[[Kategorie:Tutorials (Java)]]
 
[[Kategorie:Swing]]
 
[[Kategorie:Swing]]

Aktuelle Version vom 5. März 2019, 16:31 Uhr

Da Swing nicht threadsicher ist, kann es Probleme bereiten, wenn man aus anderen Threads auf die UI zugreifen will, beispielsweise um einen Fortschrittsbalken zu aktualisieren. In den Java-Versionen bis 1.5 konnte man sich da nur mit den Methoden invokeLater() und invokeAndWait() aus den SwingUtilities behelfen. Seit Java 6 ist auch in der Standard-API eine weitere Möglichkeit als die SwingUtilities Methoden enthalten, die das ganze ein wenig automatisiert. Mit Hilfe der Klasse SwingWorker lassen sich solche GUI-Updates leicht darstellen.

Funktionsweise

Die Funktionsweise der Klasse ist folgende: Der startende Thread erstellt eine Instanz und ruft die execute()-Methode auf. Diese erstellt einen neuen Thread, in dem die - abstrakte, vom eigenen Programm überschriebene - Methode doInBackground() aufruft. Diese kann der publish()-Methode Objekte übergeben, die dann der (aus dem Event-Dispatch-Thread aufgerufenen!) Methode process() übergeben werden - diese sollte dann auch überschrieben werden, um hier die GUI zu verändern. Außerdem kann sie setProgress() aufrufen, dann wird aus dem EDT ein evtl. registrierter PropertyChangeListener benachrichtigt. Wenn doInBackground() zurückkehrt, ruft der Event-Dispatch-Thread done() auf, und die get()-Methode, die bis dahin geblockt hat, gibt den Rückgabewert von doInBackground() zurück.

Grafische Darstellung

SwingWorker.gif

Beispiel

Hier ein Beispiel, das ein Verzeichnis kopiert:

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

public class SwingWorkerExample extends JFrame
{
  public SwingWorkerExample(String title, File sourceDir, File destDir)
  {
    super(title);
    setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    setLayout(new BorderLayout());
    JProgressBar probar = new JProgressBar (0,100);
    probar.setStringPainted(true);
    JTextArea fileArea = new JTextArea();
    add (probar, BorderLayout.NORTH);
    add (new JScrollPane (fileArea), BorderLayout.CENTER);
    setSize (512, 384);
    setLocationByPlatform (true);
    setVisible(true);
    Copier c = new Copier(fileArea, sourceDir, destDir);
    c.addPropertyChangeListener(new ProgressBarChanger(probar));
    c.execute();
    try{
      boolean b = c.get();
      if (b) System.out.println("Errors occurred");
      else System.out.println("Everything was fine");
    }catch (Exception e){
      e.printStackTrace (System.console().writer());
      System.exit (1);
    }
  }
  /*
   *args[0] = source directory
   *args[1] = destination directory
   */
  public static void main(String[] args)
  {
    if (args.length < 2){
      System.out.println("Usage: java SwingWorkerExample sourceDirectory destinationDirectory");
    }
    File sourceDir = new File (args[0]);
    File destDir = new File (args[1]);
    new SwingWorkerExample("SwingWorkerExample", sourceDir, destDir);
  }
}

class Copier extends SwingWorker<Boolean,File>
{
  private JTextArea appendTo;
  private File srcDir;
  private File destDir;
  private float fileNum;
  private int copied = 0;
  public Copier (JTextArea appendTo, File srcDir, File destDir)
  {
    this.appendTo = appendTo;
    this.srcDir = srcDir;
    this.destDir = destDir;
    fileNum = count (srcDir);
  }
  @Override
  protected Boolean doInBackground()
  {
    boolean errorOccurred = copyFile(srcDir, destDir);
    return Boolean.valueOf(errorOccurred);
  }
  @Override
  protected void process (File... chunks)
  {
    for (File f : chunks){
      appendTo.append (f.getAbsolutePath());
      appendTo.append ("\n");
    }
  }
  
  private int count(File f)
  {
    if (f.isDirectory()){
      int ret = 0;
      for (File sf : f.listFiles()){
        ret += count(sf);
      }
      return ret;
    }else{
      return 1;
    }
  }
  private boolean copyFile(File src, File dest)
  {
    if (src.isDirectory()){
      dest.mkdirs();
      boolean ret = false;
      for (File fil : src.listFiles()){
        boolean b = copyFile (fil, new File (dest, fil.getName()));
        if (b) ret = true;
      }
      return ret;
    }else{
      try{
         copy (src, dest);
         return false;
      }catch(IOException e){
        e.printStackTrace(System.console().writer());
        return true;
      }
    }
  }
  private void copy(File src, File dest) throws IOException
  {
    InputStream is = new FileInputStream(src);
    OutputStream os = new FileOutputStream(dest);
    int len;
    byte[] buf = new byte[1024];
    while ((len = is.read(buf)) >= 0){
      os.write (buf, 0, len);
    }
    is.close();
    os.close();
    copied++;
    setProgress((int)(copied / fileNum * 100 + 0.5f));
    publish (src);
  }
}
class ProgressBarChanger implements PropertyChangeListener
{
  private JProgressBar jpb;
  public ProgressBarChanger (JProgressBar myBar)
  {
    jpb = myBar;
  }
  public void propertyChange(PropertyChangeEvent evt)
  {
    if ("progress".equals(evt.getPropertyName())){
      jpb.setValue((Integer)evt.getNewValue());
    }
  }
}