【发布时间】:2017-11-11 01:47:08
【问题描述】:
我有一个与服务器通信并从服务器获取数据的 JavaFX 应用程序。接收到的数据放入一个 ObservableList 中,并显示在一个 TableView 中。
与服务器的通信在其自己的线程中运行,并且在调用 ObservableList.add 时会触发 IllegalStateException(抱怨不是事件线程/不是 JavaFX 线程)
我发现了以下solution 来解决类似的问题,但我不确定如何采用它,因为在我的情况下,与服务器的通信需要不断保持,因此任务/线程一直运行到通讯终止。
我在这里有一个最小的工作示例,可以触发所述异常并粗略地模拟应用程序的工作方式。
主要:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
控制器:
package sample;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
public class Controller {
public TableView<Integer> timeTable;
public TableColumn<Integer, String> positionColumn;
private ObservableList<Integer> testList;
@FXML
private void initialize() {
testList = FXCollections.synchronizedObservableList(FXCollections.observableArrayList());
positionColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().toString()));
timeTable.setItems(testList);
Task<Integer> integerTask = new Test(testList);
Thread testThread = new Thread(integerTask);
testThread.start();
}
}
通讯任务:
package sample;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
public class Test extends Task<Integer> {
private ObservableList<Integer> testlist;
Test(ObservableList<Integer> list) {
testlist = list;
}
@Override
protected Integer call() throws Exception {
// Emulates the server communication thread. Instead of an endless loop, I used a fixed number of iterations.
// The real application has an endless while loop for server communication so a Task cannot be used to
// get the data
// getDataFromServer()
// parseData()
// putDataInList()
// loop
Thread.sleep(2000);
for (int i = 0; i < 500; ++i) {
testlist.add(i);
}
return 0;
}
}
FXML:
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.GridPane?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<TableView fx:id="timeTable" editable="true" prefHeight="498.0"
prefWidth="254.0">
<columns>
<TableColumn fx:id="positionColumn" prefWidth="73.0" text="Position"/>
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
</TableView>
</GridPane>
【问题讨论】:
标签: java multithreading javafx task