gpt4 book ai didi

JavaFX。尝试在 Controller 内实例化阶段不会检索其中的值?是吗?

转载 作者:行者123 更新时间:2023-12-02 04:26:32 25 4
gpt4 key购买 nike

环境:使用场景生成器的 Java FX 8

上下文:我试图使用 ObservableList 创建一个包含 TableViewTableColumn 的简单阶段。调用create_ConfigStage()来创建阶段,并初始化initialize()。 FXML 的 Controller 类是 ControllerA(就是这个类),一切都很顺利,直到..

问题:无法弄清楚为什么在 create_ConfigStage() 中调用 words.size 会导致 NullPointerException(或 0),但在 initialize() 中调用相同的内容 没有问题。

问题类型:java.lang.NullPointerException,或者准确地说,在initialized()中初始化的值在阶段创建(或类似的东西)后未初始化。

仅供引用:没有其他东西会干扰 words 变量甚至 templates 变量。

附加测试:

  1. 刚刚添加了按钮来使用 buttonhandleButton 测试单词的大小。结果又OK了。但空指针仍然在同一个老地方。

  2. 刚刚添加了一个字符串 testVal 以查看值是否发生变化。显然,事实并非如此。

    class ControllerA {

    @FXML TableView<Words> templatesTable;
    @FXML TableColumn<Words, String> templateHeaders;
    @FXML Button button;

    Stage stage;
    ObservableList<Words> templates;
    List<Words> words = new ArrayList<Words>();
    String testVal = "Nothing Happened";

    @FXML
    public void initialize(){
    words = FileUtil.readMacroFile(new File("macros.dat"));
    templates = FXCollections.observableArrayList();
    templates.addAll(words);
    templatesTable.setItems(templates);
    templateHeaders.setCellValueFactory(new PropertyValueFactory<Words, String>("header"));
    testVal = "Something Happened";

    System.out.println(words.size()); //<<-- size = 5 (THIS IS PRINTED)
    }

    public void create_ConfigStage() {
    stage = new Stage();
    FXMLLoader loader = new FXMLLoader(ClassLoader.getSystemResource("windows/configureTemplates.fxml"));
    AnchorPane root = null;

    try {
    root = loader.load();
    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.showAndWait();
    } catch (IOException e) {
    e.printStackTrace();
    }

    System.out.println(testVal); //This one prints "Nothing Happened" instead of "Something happened"!!!
    System.out.println(words.size()); //<<-- The line showing null pointer(if wasnt initialized in initializer() else shows 0)
    }

    @FXML
    public void handleButton(){
    System.out.println(words.size()); // <<-- this one prints 5(THIS IS PRINTED AS WELL)
    }

调用create_ConfigStage()的代码

public class Main_Controller {
@FXML Button createConfig;

@FXML
public void handleConfigTemplateRequest(){
main.getControllerA().create_ConfigStage();
//This method is invoked by "createConfig" button
}
}

这是调用创建主阶段的类

public class Main extends Application{

public void start(Stage mainStage) throws Exception{
this.primaryStage = mainStage;
mainStage.setTitle("Scratch GLSL Editor");

FXMLLoader loader = new FXMLLoader(ClassLoader.getSystemResource("main.fxml")); //main.fxml's controller is class Main_Controller
AnchorPane root = loader.load();

Scene mainScene = new Scene(root);
mainStage.setScene(mainScene);
mainStage.show();

ControllerA controllerA = new ControllerA();
controllerA.setMain(this); //to get the controller from this class
setControllerA(controllerA);

}

//setter and getter for ControllerA here

public static void main(String[] args){
launch(args);
}
}

最佳答案

ControllerA的实例您调用create_ConfigStage()由该行创建

ControllerA controllerA = new ControllerA();

换句话说,它不是作为 load(...) 的一部分为您创建的。 FXMLLoader的过程。因此,任何 FXML -注入(inject)的字段未初始化,并且 initialize()永远不会在该实例上调用方法。

稍后,当您加载 FXML 时,FXMLLoader创建 ControllerA另一个实例,并作为 load(...) 的一部分进程调用initialize()那个实例上。当按下按钮时,将在同一个 FXMLLoader 上调用事件处理程序方法。 -创建的实例。

因此,words已从您的 FileUtil.readMacroFile(...) 正确初始化FXMLLoader中的方法- 创建的实例,但从未在您自己创建的实例中正确初始化。因此,对于您调用 create_ConfigStage() 的实例, words是空的ArrayList您在声明中创建内联(或 null,如果您在声明中省略 = new ArrayList<Words>())。

您想要做什么还不是很清楚,因为您没有真正显示 FXML 文件和各种 Controller 之间的关系,而是获取由 FXMLLoader 加载的 Controller 实例。你会使用类似的代码

FXMLLoader loader = new FXMLLoader(ClassLoader.getSystemResource("windows/configureTemplates.fxml"));

AnchorPane root = null;

try {
root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.showAndWait();
ControllerA controllerA = loader.getController();
System.out.println(controllerA.getWords().size());
} catch (IOException e) {
e.printStackTrace();
}

有合适的getWords() ControllerA中定义的方法:

public List<Words> getWords() {
return words ;
}

显然你不能在 ControllerA 的实例方法中执行此操作,因为您创建了先有鸡还是先有蛋的情况(您需要从 FXMLLoader 获取 Controller 实例,但在获得 Controller 实例之前不要调用 FXMLLoader )。

您在这里遇到问题的原因是您试图反转通常的 FXML 加载过程。通常的流程是这样的:

  1. 创建 FXMLLoader
  2. 调用 load(...)关于FXMLLoader
  3. FXMLLoader读取 FXML 文件
  4. FXMLLoader创建 Controller ,如 fx:controller 指定的那样FXML 文件中的属性

换句话说,FXML 文件( View )为您实例化 Controller 。

您正在尝试以相反的方式做事,即您正在尝试让 Controller 实例创建 FXMLLoader然后加载 View 。您可以让事情以这种方式进行,但您必须以不同的方式进行设置。以下假设您没有在其他任何地方加载此 FXML 文件(您至少必须相应地修改该代码)。

首先,删除 fx:controller来自 configureTemplates.fxml 的属性 (因为您要在创建 FXMLLoader 之前创建 Controller ,所以您不希望加载程序再实例化 Controller 类)。

然后修改你的create_ConfigStage()方法如下:

public void create_ConfigStage() {
stage = new Stage();
FXMLLoader loader = new FXMLLoader(ClassLoader.getSystemResource("windows/configureTemplates.fxml"));

// Tell the FXMLLoader to use this object as the controller.
// Note that if the fxml file has a fx:controller attribute,
// loading it will fail with an IllegalStateException:

loader.setController(this);


AnchorPane root = null;

try {
// Since we set this object as the controller, loading will
// initialize all the @FXML fields defined in this instance, and will
// invoke initialize() on this instance:
root = loader.load();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.showAndWait();
} catch (IOException e) {
e.printStackTrace();
}

System.out.println(testVal); // This should show the value updated in initialize()
System.out.println(words.size()); // This should give the number loaded by FileUtil.readMacroFile(...)
}

您可能还想阅读 this related technique .

关于JavaFX。尝试在 Controller 内实例化阶段不会检索其中的值?是吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32075725/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com