Fortschrittsanzeige bei Datenbankzugriff

Athropos

Grünschnabel
Hi!

Ich bastel gerade an einem Programm, welches unter anderem Datensätze in eine (mySQL) Datenbank schreibt. Nachdem das mitunter (>1000DS) schon mal etwas länger dauern kann, hab ich mir gedacht, vertreibst du dem User die Zeit mit einem Fortschrittsbalken (oder eine Animation oder irgendwas anderes, damit er nicht denkt, das Programm hat sich aufgehängt).

Nur WIE?

Testhalber hab ich 2 Klassen geschrieben (eine in der ein JProgressBar in einem Frame gezeigt wird und eine, die die Datenbankspielerei macht). Dazu eine dritte, die die 2 vorigen Klassen in Threads packt und startet (wobei ich das gewünschte Ergebnis, nämlich daß der Fortschrittsbalken wächst, während die Daten geschaufelt werden nur erhalte, wenn ich mit Thread.start() arbeite, Thread.run() tut irgendwie gar nix).

Folgend der Code meiner 3 Classfiles:
1) Class für den ProgressBar
Code:
public class HelloLoop implements Runnable {

  private int pValue = 0;
  private JFrame frame = new JFrame("Progress Bar Trial");
  private JProgressBar progress = new JProgressBar();
  
  public void setMaximumSize(int max) {
    progress.setMaximum(max);
  }
  public void setActualValue(int val) {
      pValue = val;
  }
  public void disableProgressBar() {
    frame.setVisible(false);
  }
  public void enableProgressBar() {
    frame.setVisible(true);
    pValue = 0;
  }
  public void run() {
      progress.setPreferredSize(new Dimension(250,25));
      progress.setValue(0);
      progress.setStringPainted(true);
      progress.setIndeterminate(false);
      frame.setLayout(new FlowLayout());
      frame.add(progress);
      frame.pack();
      
      while (true) {      
          progress.setValue(pValue);
          try { Thread.sleep(50); }
          catch (InterruptedException e) {}
    }
  }
}

2) Class mit den Datenbankspielereien (es wird einfach ein table kopiert)

Code:
public class HelloDatabase implements Runnable {
    private HelloLoop pbar;
    private int step = 0;
    
    public void setProgressBar(HelloLoop p) {
        pbar = p;
    }    
    public void rumbleDatabase() {
        pbar.setMaximumSize(variable);
        pbar.setActualValue(0);
        pbar.enableProgressBar();
        //query: daten einlesen
        //query: neuen table anlegen
        //query: daten in neuen table einfügen
        //+jeweils erhöhung der zählvariable
        pbar.disableProgressBar();
    } //end rumbleDatabase
    
    public void run() {
        while (true) {
            pbar.setActualValue(step);
            try { Thread.sleep(50); }
            catch (InterruptedException e) {}
      }
    }
}

3) "Main" class mit dem Threadstart
Code:
public class HelloThreads {
  public static void main (String[] args) {
    HelloDatabase  database = new HelloDatabase();
    HelloLoop myProgress = new HelloLoop();
    database.setProgressBar(myProgress);
    
    Thread data = new Thread (database);
    Thread bar = new Thread (myProgress);
    
    data.start();
    bar.start();
    database.rumbleDatabase();
  }
}

Wie gesagt, so funktioniert es ja schon fast zu meiner Zufriedenheit, nur wenn ich das Ganze ins "Hauptprogramm" integriere (wobei das Hauptprogramm da auch in einem run() mit while(true) loop läuft, wird nur der Rahmen vom Fenster des Fortschrittsbalkens angezeigt aber sonst passiert nix (sprich kein Inhalt und auch keine (optische) Änderung desselben. Outputs in der Kommandozeile würden passen.

Wo liegt der Fehler?
Bzw. gibts evtl. irgendwo Cookbook oder Codesnips, die ich verwenden könnte?

thx & lg,
Athropos
 
so mal aus der hohlen hand... swing ist nicht threadsafe. versuchsmal mit SwingUtilities.invokeAndWait()

gruss
 
Hallo,

das ist ganz klar. Wenn du die Methode run aufrufst, ist das wie ein normaler Methodenaufruf. Wenn du den Thread mit start() startest, passiert ja was ganz anderes. Wenn es wie bei dir ist und eine Klasse hat nur das Interface Runnable implementiert, solltest du um den Thread zu starten den ExecuterService nutzen.
Code:
ExecuterService service = Executers.newSingleThreadExecutor();
service.execute(new HelloDatabase());

Wenn du aber was an der GUI bei Swing verändern möchtest, wie beispielsweise eine ProgressBar hochzählen, dann solltest du es machen wie limago schon gesagt hat.
Also mit SwingUtilities.invokeAndWait() oder SwingUtilities.invokeLater().

MFG

Sascha
 
Zurück