JavaFX : How to populate data to TableView from different Thread(Netty)

标签 java multithreading tableview javafx-8 netty

我有以下代码。 TableView 在 GUI 上不显示记录,为空。 如何将值从 ServerHandler 线程传递到 JAVAFX UI 线程。

你能推荐一下吗? 谢谢

更新

主类

public class Main extends Application {
private static Stage stage;
@Override
public void start(Stage primaryStage){
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("mainpane.fxml"));
    fxmlLoader.load();
    setStage(primaryStage);
    Parent root = fxmlLoader.getRoot(); 
    Scene scene = new Scene(root,800,800);
    primaryStage.setScene(scene);
    primaryStage.show();
}
public static void main(String[] args) {
    new Thread(() -> launch(Main.class, args)).start();
    new MyServer().startDownload();
}

Controller

public class SampleController {
private ObservableList<Model> tableData = FXCollections.observableArrayList();
@FXML
private TableView<Model> table;
@FXML
private TableColumn<Model, String> firstCol;
@FXML
private TableColumn<Model, String> secondCol;   
@FXML
public void initialize() {
    table.setEditable(false);
    firstCol.setCellValueFactory(cellData -> cellData.getValue().getName());
    secondCol.setCellValueFactory(cellData -> cellData.getValue().getCurrent());
    table.setItems(tableData);
}
public void addModel(ChannelFuture sendFileFeture,Model model){
    table.getItems().add(Model);
    System.out.println("row model= "+model.getName().get());// it works fine;
    sendFileFeture.addListener(model);
}

Netty 4 的服务器类

public class ServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
    //some codes
    Model model=new Model(file.getName(),fileLength+"");
    SampleController sc=new SampleController();
    sc.addModel(sendFileFeture, model);
}

Netty的ChannelProgressiveFutureListener的Model类

public class Model implements ChannelProgressiveFutureListener{
private SimpleStringProperty name=null;
private SimpleStringProperty current=null;

public Model(String name,String current){
    this.name=new SimpleStringProperty(name);
    this.current=new SimpleStringProperty(current);
}

@Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) throws Exception {
    System.out.println("current: "+current+",progress: "+progress); //it works fine
    current.set(progress+""); // can not update the TableView
}
@Override
public void operationComplete(ChannelProgressiveFuture future) throws Exception {
}

public void setName(String name) {
    this.name.set(name);
}
public SimpleStringProperty getName() {
    return name;
}
public void setCurrent(String current) {
    this.current.set(current);
}
public SimpleStringProperty getCurrent() {
    return current;
}

更新

tableview 没有以正确的大小更新,我加载的图像是 2,407,257 字节。您可以在下面的图像中找到错误。

image1 image2

secondCol.setCellValueFactory(cellData -> cellData.getValue().getCurrent());
secondCol.setCellFactory(column -> {return new TableCell<Model, String>() {
            @Override
            protected void updateItem(String item, boolean empty) {
                System.out.println(item); //UPDATING NOT CURRECT
                super.updateItem(item, empty);
                setText(empty ? "" : getItem().toString());
            }
        };

最佳答案

UI 没有显示任何内容,因为您正在填充与正在显示的表不同的表,而不是因为线程(尽管您也有线程问题,或者一旦解决了初始问题就会这样做)。

start() 方法中,您加载 FXML,该 FXML 创建一个 TableView 及其列,并创建一个 Controller 实例。您的 ServerHandler 类创建了一个新的 Controller 实例,而该 Controller 又创建了一个新的 TableView 实例(初始化变量总是是一个错误注释为 @FXML)。该 TableView 实例永远不会显示。因此,当您的 ServerHandler 填充表时,它填充的表实际上并不是 UI 的一部分,并且您看不到任何内容。

MyServer 的创建移至 start() 方法,并将现有 Controller 实例传递给它:

public class Main extends Application {

    private Stage stage;
    @Override
    public void start(Stage primaryStage){
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("mainpane.fxml"));
        fxmlLoader.load();
        setStage(primaryStage);
        Parent root = fxmlLoader.getRoot(); 
        Scene scene = new Scene(root,800,800);
        primaryStage.setScene(scene);
        primaryStage.show();
        SampleController controller = loader.getController();
        new Thread(() -> new MyServer(controller).startDownload()).start();
    }
    public static void main(String[] args) {
        launch(args);
    }

}

您的 MyServer 类应该依次将 Controller 传递给 ServerHandler 实例。由于 ServerHandler 方法是在后台线程上调用的,因此它们需要使用 Platform.runLater(...) 来更新 UI:

public class ServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{

    private final SampleController sc ;

    public ServerHandler(SampleController sc) {
        this.sc = sc ;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
        //some codes
        Model model=new Model(file.getName(),fileLength+"");
        Platform.runLater(() -> {
            sc.addModel(sendFileFeture, model);
            sc.addRowModel(sendFileFeture, rowModel);
        });
    }

}

最后,不要初始化应该由 FXMLLoader 初始化的字段。这只会起到抑制任何指示 Controller -FXML 绑定(bind)未正确设置的 NullPointerException 的效果:

public class SampleController {

    private ObservableList<Model> tableData = FXCollections.observableArrayList();
    @FXML
    private TableView<RowModel> table ;
    @FXML
    private TableColumn<Model, String> firstCol ;
    @FXML
    private TableColumn<Model, String> secondCol ;

    @FXML
    public void initialize() {
        table.setEditable(false);
        firstCol.setCellValueFactory(cellData -> cellData.getValue().getName());
        secondCol.setCellValueFactory(cellData -> cellData.getValue().getProgress());
        table.setItems(tableData);
    }
    public void addModel(ChannelFuture sendFileFeture,Model model){
        table.getItems().add(model);
        System.out.println("row model= "+model.getName().get());// it works fine;
        sendFileFeture.addListener(rowModel);
    }

}

关于JavaFX : How to populate data to TableView from different Thread(Netty),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45583469/

相关文章:

wpf - 如何从其他线程访问主UI线程中的System.Windows.Threading.Dispatcher?

Ruby:如何将多线程合并到这个网络抓取场景中?

swift -4 : How to assign NSArray of NSDictionary values to another NSDictionary variable and how do i get value for key from NSDictionary

ios - 如何在 TableViewController 中显示 Firestore 文档名称?

swift - 如何对 UITableViewCell 中的 TextView 中的数字进行排序?

java - Macintosh 上的 Swing GUI 问题

java - 反转数组的内容

java 3D渲染距离

java - 签名 APK 的配置出现错误 "configuration is still incorrect"

java - java中线程池的类型