UI durch separaten Thread aktualisieren

Hallo Forum,

ich arbeite mich gerade in JavaFX ein und bastel zu diesem Zweck eine Anwendung, die mir alle Bilder eines Ordners wie in einem Filmstreifen nebeneinander anzeigt. Ich habe daher der Scene eine HBOx zugefügt und durchlaufe dann in einer Schleife für alle Bilddateien folgende Schritte:

  • Erzeugen eines Image-Objekts durch Einlesen der Bilddatei mittels FileInputStream
  • Erzeugen eines ImageView-Objekts und Einfügung des eingelesenen Bildes
  • Erzeugen eines BorderPanes und Einfügung des ImageView-Objekts
  • Einfügen des BorderPanes in die HBox

Es funktioniert, hat nur den Schönheitsfehler, dass die Bilder erst nach Abarbeiten der kompletten Schleife angezeigt werden, was je nach Anzahl der Bilder schonmal 1 bis 2 Minuten dauern kann. Schöner wäre, wenn nach jedem Schleifendurchlauf das aktuelle Bild angezeigt wird. Wenn ich mich richtig informiert habe, muss dazu ein separater Thread her. Also verlagere ich die Schleife in folgenden Task:

   @Override
   protected File call() throws Exception {
       ... // meine Schleife
   }
};

und starte den Thread:

th.setDaemon(true);
th.start();

Es funktioniert bis auf die letzte Aktion der Schleife, in der die BorderPane in die HBOx eingefügt werden soll. Dieses passiert offensichtlich nicht (es wird allerings auch keine Exception geworfen). Nach Recherche habe ich herausgefunden, dass Änderungen am UI nur im Application-Thread erfolgen können, dann wird es wohl daran liegen, dass mein separater Thread die BorderPane nicht einfügen kann. Mir ist bisher aber nicht klar geworden, wie ich es anstellen muss, damit beide Threads quasi kommunizieren können und der Application-Thread das im “Task-Thread” erzeugte BorderPane-Objekt übernehmen und in die HBox einfügen kann. Hättet Ihr da einen Tip für mich?

der nötige Befehl ist vielleicht
java - JavaFx response to SwingUtilities.invokeLater - Stack Overflow
(Platform.runLater)

in Swing gesprochen gibt es zwar auch die Regel, dass besser alles vom AWT-Thread ausgeführt werden sollte,
aber eher als Nummer sicher-Regel, von woanders aus sollte es meist auch funktionieren,
oder falls nicht, sich durch Exception bemerkbar machen,
zumindest für Testläufe Verwendung separater Threads nicht dramatisch, Langzeitlösung natürlich auch besser korrekt!

noch zwei Weisheiten aus Swing-Erfahrung wahllos geraten:

  • Änderungen auf einem zweiten GUI-Objekt, welches gar nicht in der Anzeige verwendet ist, sind allgemein wirkungslos,
    darauf achten nicht zwei GUIs getrennt zu verwenden

  • ‘neue Panes einfügen’ klingt eher ungeeignet für Laufzeit, wenn dann evtl. noch auf Layout-Neuberechnung achten (revalidate() + repaint() in Swing),
    besser aber am Anfang die GUI komplett aufbauen und später maximal z.B Bilder in Label einfügen oder was auch immer unterhalb von Pane-/ Panel-Ebene

[QUOTE=SlaterB]der nötige Befehl ist vielleicht
java - JavaFx response to SwingUtilities.invokeLater - Stack Overflow
(Platform.runLater)
[/QUOTE]

Yes! Das war’s!

habe einfach die Zeile:

hBoxIn.getChildren().add(bPane);

ersetzt durch:

   @Override
   public void run() {
      hBoxIn.getChildren().add(bPane);
   }
});

und schon läuft’s. War doch viel einfacher, als befürchtet. 1000 Dank für die Hilfe! :slight_smile: