JavaFX UI-Thread und DB-Thread trennen um z.B. Ladebalken anzuzeigen

dior

Bekanntes Mitglied
Hi,

ich habe eine mittlerweile lauffähige Anwendung die je nachdem welchen Button ich anklicke eine SQL DB Abfrage macht und das Ergebnis in eine TableView schreibt.

Leider habe ich den UI und DB Thread ziemlich vermischt und weiß nicht wie ich die am besten trennen kann damit ich neben der Abfrage und dem befüllen der TableView die GUI mit einem Ladebalken oder einer anderen Animation ständig updaten kann bis alles fertig ist.

TreeView mit der Auswahl der einzelnen Abfragen:
Java:
.
.
public static ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
  public static ObservableList<String> row = FXCollections.observableArrayList();
.
.
@FXML
  TableView tableview1;
.
.
public void BuildTreeView() {
.
.
************************************************************************************************** */
         treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {

             @Override
             public void changed(ObservableValue observable, Object oldVal, Object newVal) {
                 System.out.println(oldVal + " neuer: " + newVal);

                 switch (newVal.toString()) {
case "TreeItem [ value: USW ]":
                         sqlDatei = "USW.txt";
                         xlsxSheetName = sqlDatei.substring(0, sqlDatei.lastIndexOf('.'));
                         pIVisible();
                         AuswahlClicked();
                         buildData();
                         break;
case "TreeItem [ value: GHA ]":
                         sqlDatei = "gha.txt";
                         AuswahlClicked();
                         buildData();
                         break;
.
.
.

pIVisible()
Java:
public void pIVisible() {

        Platform.runLater(new Runnable() {
            public void run() {
                progressBarStatus.setVisible(true);
                labelStatus.setText("loading...");
            }
        });
    }

AuswahlClicked()
Hier lade ich das jeweilige SQL Statement aus einer Textdatei

buildData(); // -> DB-Abfrage und TableView updaten...

Java:
public void buildData() {
      tableview1.getItems().clear();
      tableview1.getColumns().clear();
       System.out.println("index: " + data.indexOf(c));
        try {
            c = DB._DB_Connection.getConnection();
            System.out.println("real SQL: " + SQL);
            ResultSet rs = c.createStatement().executeQuery(SQL);
            TableColumn col = new TableColumn();
            for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
                //making dynamic table
                final int j = i;
                col = new TableColumn(rs.getMetaData().getColumnName(i + 1));
                col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() {
                    public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) {
                      //  System.out.println("param.getValue(): " + param.getValue().toString());
                        return new SimpleStringProperty(param.getValue().get(j).toString());
                    }
                });
                int rowNr = i + 1;
                System.out.println("Column [" + rowNr + "] " + rs.getMetaData().getColumnName(rowNr));
                tableview1.getColumns().addAll(col);
            }
            /* Data added to ObservableList */
            while (rs.next()) {
                //Iterate Row
                row = FXCollections.observableArrayList();
                for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                    Object o = rs.getObject(i);
                    row.add(o == null ? "" : o.toString()); // wenn ein NULL Value gefunden wird, wird dieser durch "" ersetzt
                }
                data.addAll(row);
                System.out.println("row: " + row.get(0));
            }
            Platform.runLater(() -> tableview1.setItems(data));
           
            ausgabe1.setText("" + data.size());
            System.out.println("Anzahl der Zeilen: " + data.size());
            // RechtsklickMenü in TableView initialisieren!
            RechtsKlickMenue();

            rs.close();
            c.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Error on Building Data");
        }

    }


Wie kann ich die buildData() so anpassen das der progressBar updated während die Abfrage noch läuft? Und dann nat. fertig ist wenn die Abfrage und das befüllen der TableView fertig ist.

ich hoffe ich habe das Problem halbwegs verständlich erklärt
danke im Voraus für eure Hilfe,
 
Im Prinzip überall wo du etwas an der GUI manipulierst, was direkt angezeigt werden würde, muss dies per Platform#runLater ausgelöst werden (siehe dein Lambda-Ausdruck im anderen Thread).

ABER: Das setzt voraus, dass du die DB-Operation vorher bereits auf einem anderen Thread gemacht hast.

Schau dir dazu bitte die Klasse Task an:
https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html

Und hier noch etwas Doku/Tutorial dazu:
http://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm

Das sollte eigentlich genügen, um das Problem angehen zu können. Wenn nicht... Fragen!
 
Danke für die Tips.

Ich habe jetzt folgendes versucht (bin nicht sicher ob das Zielführend ist...)
2 Tasks definiert. In einem wird die DB Abfrage gemacht, im anderen der ProgressIndicator angezeigt.

Java:
Task buildDatatask = new Task<Void>() {
        @Override
        public Void call() {
            System.out.println("Abfrage gestartet:");
            buildData();
            return null;
        }
    };
    Thread thBuildDatatask = new Thread(buildDatatask);

    Task pIVisibletask = new Task<Void>() {
        @Override
        public Void call() {
            System.out.println("Abfrage gestartet:");
            pIVisible();
            return null;
        }
    };
    Thread thPIVisibletask = new Thread(pIVisibletask);

beim klick auf das den Button starte ich die Threads:
Java:
thPIVisibletask.start();
thBuildDatatask.start();

Gut ist das am Ende das Ergebnis in der TableView angezeigt wird und auch der ProgressIndicator gleich beim klick gestartet wird, aber es kommt auch nach jeder Column eine Fehlermeldung:
Column [1] Name
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.updatePlaceholderRegionVisibility(TableViewSkinBase.java:836)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.updateVisibleColumnCount(TableViewSkinBase.java:799)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.lambda$new$71(TableViewSkinBase.java:302)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.FXCollections$UnmodifiableObservableListImpl.lambda$new$52(FXCollections.java:929)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.setAll(ModifiableObservableListBase.java:90)
at javafx.scene.control.TableView.updateVisibleLeafColumns(TableView.java:1634)
at javafx.scene.control.TableView.access$200(TableView.java:355)
at javafx.scene.control.TableView$5.onChanged(TableView.java:634)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
Column [2] WERT1
at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:102)
at javafx.collections.ObservableListBase.addAll(ObservableListBase.java:245)
at FX.FXMLDocumentController.buildData(FXMLDocumentController.java:163)
at FX.FXMLDocumentController$1.call(FXMLDocumentController.java:119)
at FX.FXMLDocumentController$1.call(FXMLDocumentController.java:115)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.updatePlaceholderRegionVisibility(TableViewSkinBase.java:838)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.updateVisibleColumnCount(TableViewSkinBase.java:799)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.lambda$new$71(TableViewSkinBase.java:302)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.FXCollections$UnmodifiableObservableListImpl.lambda$new$52(FXCollections.java:929)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.setAll(ModifiableObservableListBase.java:90)
at javafx.scene.control.TableView.updateVisibleLeafColumns(TableView.java:1634)
at javafx.scene.control.TableView.access$200(TableView.java:355)
at javafx.scene.control.TableView$5.onChanged(TableView.java:634)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.addAll(ModifiableObservableListBase.java:102)
at javafx.collections.ObservableListBase.addAll(ObservableListBase.java:245)
at FX.FXMLDocumentController.buildData(FXMLDocumentController.java:163)
at FX.FXMLDocumentController$1.call(FXMLDocumentController.java:119)
at FX.FXMLDocumentController$1.call(FXMLDocumentController.java:115)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.updatePlaceholderRegionVisibility(TableViewSkinBase.java:838)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.updateVisibleColumnCount(TableViewSkinBase.java:799)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.lambda$new$71(TableViewSkinBase.java:302)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.FXCollections$UnmodifiableObservableListImpl.lambda$new$52(FXCollections.java:929)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.setAll(ModifiableObservableListBase.java:90)
at javafx.scene.control.TableView.updateVisibleLeafColumns(TableView.java:1634)
at javafx.scene.control.TableView.access$200(TableView.java:355)
at javafx.scene.control.TableView$5.onChanged(TableView.java:634)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
.
.
.
.
.

Fehler taucht beim befüllen der tableview auf:
Java:
tableview1.getColumns().addAll(col);
 
Die Antwort steht vor dir:
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread;
Dann ist auch klar, das es in der Zeile auftritt:
Java:
tableview1.getColumns().addAll(col);
Du musst diese Zeile in ein Lamdda und Platform#runLater wrappen:
Java:
Platform.runLater(() -> tableview1.getColumns().addAll(col));

Edit: Ungestetet, natürlich 😉
 
Aber, ich habe das so gelöst... keine Ahnung ob das gut ist, aber es funktioniert zumindest.

Java:
TableColumn finalCol = col;
                Platform.runLater(() -> tableview1.getColumns().addAll(finalCol));
 
Ich dachte jetzt hätte ich es, aber wenn ich jetzt eine 2. Abfrage starte kommt:
Exception in thread "JavaFX Application Thread" java.lang.IllegalThreadStateException

at java.lang.Thread.start(Thread.java:705)
at FX.FXMLDocumentController$4.changed(FXMLDocumentController.java:391)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:74)
at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:102)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
at javafx.scene.control.SelectionModel.setSelectedItem(SelectionModel.java:102)
at javafx.scene.control.MultipleSelectionModelBase.lambda$new$34(MultipleSelectionModelBase.java:67)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyIntegerPropertyBase.fireValueChangedEvent(ReadOnlyIntegerPropertyBase.java:72)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:102)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68)
at javafx.scene.control.MultipleSelectionModelBase.select(MultipleSelectionModelBase.java:404)
at javafx.scene.control.MultipleSelectionModelBase.clearAndSelect(MultipleSelectionModelBase.java:356)
at javafx.scene.control.TreeView$TreeViewBitSetSelectionModel.clearAndSelect(TreeView.java:1477)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.simpleSelect(CellBehaviorBase.java:256)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.doSelect(CellBehaviorBase.java:220)
at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mousePressed(CellBehaviorBase.java:150)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:95)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:388)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
 
Beim 2. mal starten ist der Task (getState()) -> "Terminated" und lässt sich nicht nochmal starten.
Java:
Task buildDatatask = new Task<Void>() {
        @Override
        public Void call() {
           // System.out.println("Abfrage gestartet:");
           // System.out.println("ThreadStatus_buildDatatask: " + buildDatatask.getState().toString());
            buildData();
            return null;
        }
    };

was muss ich tun damit das doch geht bzw. wie kann ich den wieder "reseten" das es ein 2., 3., 4., .. mal geht?
 
Was spricht dagegen, wieder einen neuen Task zu erstellen? Die Idee eines Tasks ist nun einmal, dass dieser einmal abgearbeitet wird. Also immer, wenn Du den Task ausführen willst, läuft der Code mit Task buildTask = new Task<Void>() { .... erneut durch.
 
Kann ich machen, ich wollte halt ein paar Codezeilen einsparen und den Task nicht immer neu schreiben.
Ich habe jetzt einen neuen Task erstellt und starte diesen dann mit:
Java:
Task buildDatatask2 = new Task<Void>() {
        @Override
        public Void call() {
           // System.out.println("Abfrage gestartet:");
           // System.out.println("ThreadStatus_buildDatatask: " + buildDatatask.getState().toString());
            buildData();
            return null;
        }
    };
                        Thread thBuildDatatask2 = new Thread(buildDatatask2);
                        thBuildDatatask2.start();

Es wird das Ergebnis in der TableView angezeigt, aber es kommt noch ein Fehler:
Exception in thread "Thread-8" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-8
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.updatePlaceholderRegionVisibility(TableViewSkinBase.java:836)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.updateVisibleColumnCount(TableViewSkinBase.java:799)
at com.sun.javafx.scene.control.skin.TableViewSkinBase.lambda$new$71(TableViewSkinBase.java:302)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.FXCollections$UnmodifiableObservableListImpl.lambda$new$52(FXCollections.java:929)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(ListListenerHelper.java:164)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.setAll(ModifiableObservableListBase.java:90)
at javafx.scene.control.TableView.updateVisibleLeafColumns(TableView.java:1634)
at javafx.scene.control.TableView.access$200(TableView.java:355)
at javafx.scene.control.TableView$5.onChanged(TableView.java:634)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at com.sun.javafx.collections.ObservableListWrapper.clear(ObservableListWrapper.java:157)
at FX.FXMLDocumentController.buildData(FXMLDocumentController.java:152)
at FX.FXMLDocumentController$5$1.call(FXMLDocumentController.java:412)
at FX.FXMLDocumentController$5$1.call(FXMLDocumentController.java:407)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
 
Ach so, vom Task musst Du natürlich keine neue Instanz erzeugen sondern es müsste ein neuer Thread reichen.
Und den Punkt mit der "Not on FX application thread" hast Du ja gelöst - wollte dazu gerade auf die angegebene Lösung in diesem Thread hinweisen.
 
OK, das versteh ich nicht ganz, bzw. das klapp nicht so wie ich mir das denke.

Ich habe den Task:
Java:
Task buildDatatask = new Task<Void>() {
        @Override
        public Void call() {
            // System.out.println("Abfrage gestartet:");
            // System.out.println("ThreadStatus_buildDatatask: " + buildDatatask.getState().toString());
            buildData();
            return null;
        }
    };

beim 1. Mal starte ich ihn mit:
Java:
Thread thBuildDatatask = new Thread(buildDatatask);
thBuildDatatask.start();

Wenn ich jetzt beim 2. Button die Abfrage starte mit:
Java:
Thread thBuildDatatask2 = new Thread(buildDatatask);
                        Platform.runLater(() -> thBuildDatatask2.start());

dann passiert gar nichts.....

wenn ich aber auch den Task neu mache, dann klappt alles:

Java:
Task buildDatatask2 = new Task<Void>() {
                            @Override
                            public Void call() {
                                // System.out.println("Abfrage gestartet:");
                                // System.out.println("ThreadStatus_buildDatatask: " + buildDatatask.getState().toString());
                                buildData();
                                return null;
                            }
                        };
                        Thread thBuildDatatask2 = new Thread(buildDatatask);
                        Platform.runLater(() -> thBuildDatatask2.start());
 
Hmm .... sorry für die Verwirrung. War da selbst etwas verwirrt, denn ein Task hat zwar die Möglichkeit, auch mehrfach ausgeführt zu werden aber beim run Aufruf ist dies nicht der Fall.

Task hat (von FutureTask) zwei Methoden, die betrachtet werden müssen:
a) run() - hier wird dann der Task ausgeführt und der Status wird gesetzt. Dadurch hast Du dann einen Endstatus und der Task kann kein zweites mal gestartet werden.
b) runAndReset() - hier wird der Task ausgeführt und danach dann aber in den Ursprungszustand zurückgesetzt. So lässt sich der Task dann auch mehrfach ausführen.

Daher ist es wohl für Dich am Einfachsten, auch den Task neu zu erstellen.
 
Noch mal zu deinem Final-Feld zurück (deine erste Frage, nach meinem letzen Post). Es ist halt so, das ein Lambda am Ende "nur" eine optisch aufgehübschte Version einer Anonymen Klasse ist. Ich würde dir empfehlen, dich mit dem Thema Lambda und Methoden-Referenz zu beschäftigen - hab ich auch erst kürzlich getan und danach erst richtig verstanden, wie das intern klappt - ich kann es leider nur nicht gut genug erläutern. Sorry.

Zum Einen: Wenn du den selben Task wieder und wieder verwendest, dann kannst du stattdessen auch einen Service implementieren (wenn man es so implementiert, wird immer ein neuer Task erstellt).
Auf der bereits geposteten Seite (http://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm) suche nach "The Service Class". Dort wird das erläutert.

Zum Anderen:
Java:
Platform.runLater(()-> thBuildDatatask2.start());
Das ist Käse! Mit dem Befehl führst du den Task wieder explizit auf dem UI-Thread auf und damit wird das UI wieder einfrieren. In den Lambdas von Platform#runLater darf nur Code stehen, der die GUI verändert!
 
Nachtrag: Ok. Der Thread wird nicht explizit auf dem UI Thread laufen, nur vorn dort gestartet. Sorry. Hab übersehen, dass du noch einen Thread um den Task wrappst.
Aber: Du wirst dadurch trotzdem nichts gewinnen. Wichtig ist einfach, dass am Ende nur GUI-Updates darin ausgeführt werden.
 

Zurück
Oben