JavaFX:fxmlloader 是递归的,我不断在控制器类中的实例变量上收到空指针异常

问题描述 投票:0回答:1

这是PostView的类定义,也是其fxml文件的控制器类。我正在尝试为一项名为 rogerbook 的大学作业(几个小时后到期,哈哈)制作一个 javaFX 社交媒体应用程序。此类扩展自 AnchorPane,因为它是要添加到用户的提要页面的 post 元素。每次我创建一个

new PostView();
时,它都会递归地调用相同的错误消息,LoadException如下:

at javafx.fxml@21/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2722)
    at javafx.fxml@21/javafx.fxml.FXMLLoader$ValueElement.processAttribute(FXMLLoader.java:946)
    at javafx.fxml@21/javafx.fxml.FXMLLoader$RootElement.processAttribute(FXMLLoader.java:1302)
    at javafx.fxml@21/javafx.fxml.FXMLLoader$Element.processStartElement(FXMLLoader.java:230)
    at javafx.fxml@21/javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:757)
    at javafx.fxml@21/javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2853)
    at javafx.fxml@21/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2649)
    at javafx.fxml@21/javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2563)
    at javafx.fxml@21/javafx.fxml.FXMLLoader.load(FXMLLoader.java:2531)
    at com.rogerbook.ui/com.rogerbook.ui.PostView.<init>(PostView.java:31)

然后它在 PostView 类中的所有实例变量上打印出另一个 NullPointerException。

这是类(减去导入):


package com.rogerbook.ui;

public class PostView extends AnchorPane {
    PicPost post;
    @FXML
    private ImageView imageView = new ImageView();
    @FXML
    private Label Username = new Label();
    @FXML
    private Label Title = new Label();

    public PostView(PicPost post){
        this();
        this.post = post;
        initializePostView();
    }

    public PostView() {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Post.fxml"));
        fxmlLoader.setRoot(this);
        try{
            fxmlLoader.load();
        }catch(IOException e){
            e.printStackTrace();
        }
    }

    private void initializePostView() {
        if (post != null) {
            imageView.setImage(post.getImage());
            Username.setText(post.getAuthor().getProfile().getUserName());
            Title.setText(post.getTitle());
        }
    }
}

该程序从注册页面开始。 这是运行程序启动的主要应用程序方法:


public class HelloApplication extends Application {

    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
        Scene scene = new Scene(fxmlLoader.load());
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
    }

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

注册时,其控制器类调用以下方法:

public class HelloController {

    private Stage stage;
    private Scene scene;
    private Parent root;

    @FXML
    private TextField username;
    @FXML
    public TextField password;
    @FXML
    public TextField name;
    @FXML
    private TextField password2;
    @FXML
    private Label errmsg;

    @FXML
    public void switchToHome(ActionEvent event) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("scenefeedpage.fxml"));
        stage = (Stage)((Node)event.getSource()).getScene().getWindow();
        root = fxmlLoader.load();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    @FXML
    public void onSignup(ActionEvent event) throws IOException {
        System.out.println(password.getText());
        if(password.getText().isEmpty() || username.getText().isEmpty() || name.getText().isEmpty() || password2.getText().isEmpty()){
            errmsg.setText("Please fill all the fields");
            return;
        }
        if(password.getText().equals(password2.getText())){
            if(Roger.signup(username.getText().toLowerCase().strip(), password.getText())) {
                switchToHome(event);
            }
            else {
                errmsg.setText("Incorrect Password, or user does not exist");
            }
        }
        else{
            errmsg.setText("Passwords do not match");
        }
    }
}

注册按钮将用户重定向到 feed 页面,其中 feed 控制器将一些 PostView 组件添加到页面的 feed 区域(VBox):

public class FeedController implements Initializable {
    private Stage stage;
    private Scene scene;
    private Parent root;
    Post post;

    @FXML
    ImageView imageView;

    @FXML
    VBox view;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        System.out.println("Initializing Feed");
        ArrayList<Post> feed = Roger.getFeed();
        System.out.println("Feed done");

        feed.add(new PicPost("Hi", new Image("com/RogerBook/ui/R.png"), new User("maro", "aa")));

        //PostView postView1 = new PostView((PicPost)feed.get(0));
        post = feed.get(0);
        view.getChildren().add(new PostView((PicPost)post));
        //view.getChildren().add(new PostView());
    }

    public void ViewPost(ActionEvent event) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("Post.fxml"));
        stage = (Stage)((Node)event.getSource()).getScene().getWindow();
        root = fxmlLoader.load();
        scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }
}

我真的不知道现在该怎么办,我已经连续几个小时寻找解决方案并尝试了一切。请帮忙:D

java image javafx fxml fxmlloader
1个回答
0
投票

修复

查看使用fx:root方法的

FXML自定义控件的Oracle教程
,它与您的代码不同。

  1. 在本教程中,FXML 中没有定义
    fx:controller
    属性。
  2. 教程中有一个对
    fxmlLoader.setController(this);
    的调用,但您没有。

我没有尝试你的代码来看看它是否适用于这些修复(这需要你的 FXML,但我没有)。但是,我假设如果您进行了这些修复,您的应用程序将按预期工作(没有其他错误)。

解释

如果您在 FXML 中提供控制器,而不是在代码中在 FXMLLoader 上设置控制器,则加载器将创建控制器的新实例,而不是使用现有实例。这可能就是您遇到空字段等问题的原因(FXMLLoader 将字段值注入到它创建的实例中,而不是您创建的实例中)。

您将进入递归循环,因为您在控制器构造函数中加载 FXML,而没有事先在加载器上设置控制器实例。然后加载器创建控制器的一个新实例,然后再次加载 FXML,然后创建一个新的控制器,依此类推。

© www.soinside.com 2019 - 2024. All rights reserved.