ObjectOutputStream 在 PlayerList.java 中不可用 - 无法获取 table 的数据

ObjectOutputStream not available in PlayerList.java - impossible to get data for table

好的,再来一次。这是一个带有相关代码的新项目。正如您在文本字段中看到的,即使 initData 应该已经初始化了 testVar 变量,但它并没有发生,并且在 initialize() 中变量为空。不过,我需要在那里获取变量,这样我就可以将数据从网络连接中获取到 table。这里的代码:

FXMLController.java:

package de.freakyonline.testproject;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;

public class FXMLController implements Initializable {
    String testVar;

    @FXML
    private ResourceBundle resources;

    @FXML
    private URL location;

    @FXML
    private TextArea testTextArea;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    // Here it's null    
        testTextArea.appendText("TestVar: " + testVar);

    }

    void initData(Remote remoteObj) {
        this.testVar = remoteObj.getVar();
    }    
}

MainApp.java:

package de.freakyonline.testproject;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;


public class MainApp extends Application {
    Thread remote;
    Remote remoteObj;

    String testVar = new String("success");

    @Override
    public void start(Stage stage) throws Exception {

        FXMLLoader root = new FXMLLoader(
            getClass().getResource("/fxml/Scene.fxml")
        );

        try {
            remoteObj = new Remote(testVar);
            remote = new Thread(remoteObj);
        } catch (Exception ex) { ex.printStackTrace(); }
        remote.start();

        Scene scene = new Scene((Parent) root.load());
        FXMLController controller = root.<FXMLController>getController(); 
        controller.initData(remoteObj);

        scene.getStylesheets().add("/styles/Styles.css");

        stage.setTitle("TestProjects ...");
        stage.setScene(scene);
        stage.show();


    }

    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

Scene.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.BorderPane?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.freakyonline.testproject.FXMLController">
   <center>
      <TextArea fx:id="testTextArea" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
   </center>
</BorderPane>

Remote.java:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package de.freakyonline.testproject;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

/**
 *
 * @author uwe
 */
public class Remote implements Runnable {
    private String testVar;

    public Remote (String testVar) {
        this.testVar = testVar;
    }

    public String getVar() {
        return testVar;
    }

    public void run() {
    }
}

控制器的 initialize() 方法在加载 FXML 时由 FXMLLoader 调用,即在调用 load() 期间调用。在您的示例代码中,您在调用 load() 之后调用 initData() ,因此很明显 testVarinitialize() 方法时无法初始化被执行。由于示例代码中的控制器是由 FXMLLoader 创建的,因此您不能在调用 initialize() 之前调用 initData(...)

(另外:使用一些简单的调试技术,例如使用逐步调试器,或者甚至只是在调用每个方法时打印一条消息,就会非常清楚这里的问题是什么。)

最简单的修复方法就是将依赖于 testVar 的代码移动到 initData() 方法(或其他一些调用 after 的方法 testVar 初始化):

public class FXMLController implements Initializable {
    String testVar;

    @FXML
    private ResourceBundle resources;

    @FXML
    private URL location;

    @FXML
    private TextArea testTextArea;

    @Override
    public void initialize(URL url, ResourceBundle rb) {

    }

    void initData(Remote remoteObj) {
        this.testVar = remoteObj.getVar();
        testTextArea.appendText("TestVar: " + testVar);
    }    
}

这里的小缺点是控制器的初始化分布在多个方法中,在控制器生命周期的不同点执行。其他选项包括在代码中设置控制器,而不是在 FXML 文件中指定控制器 class,或使用控制器工厂。在代码中设置控制器的缺点是,如果您使用工具(例如 Scene Builder)设计 FXML,它不会意识到正在使用的控制器 class。使用控制器工厂更复杂,但可以避免这个问题。