有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java javafx使用来自MainController或适当控制器类中其他控制器的对象

我有以下代码:

package pl.javastart.youtufy.controller;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;

public class ConnectionErrorController implements Initializable {

    @FXML
    private Label infoLabel;

    @FXML
    private Button tryButton;

    @FXML
    private Button exitButton;


    @Override
    public void initialize(URL location, ResourceBundle resources) {

        MainController mc = new MainController();

        infoLabel.setText("Connection lost, please try again");
        tryButton.setText("try again");
        exitButton.setText("exit");

        tryButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {

                WebEngine webEngine = mc.getContentPaneController().getVideoWebView().getEngine(); // 1
                ToggleButton playButton = mc.getControlPaneController().getPlayButton(); // 2
                Node source = (Node) event.getSource();
                Stage stage = (Stage) source.getScene().getWindow();
                if (mc.testInet()) {
                    stage.close();
                    mc.play(webEngine, playButton);
                } else {
                    stage.close();
                    MainController.exist = false;
                }
            }
        });

        exitButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Platform.exit();
            }
        });
    }

}

我正在尝试从MainController中的控制器使用WebEngine和ToggleButton对象(我在MainController中为它们生成了getter和setter):

public class MainController implements Initializable {

@FXML
private ContentPaneController contentPaneController;

@FXML
private ControlPaneController controlPaneController;

@FXML
private MenuPaneController menuPaneController;

@FXML
private SearchPaneController searchPaneController;

private Youtube youtubeInstance;

public static boolean exist = false;

public ControlPaneController getControlPaneController() {
    return controlPaneController;
}

public void setControlPaneController(ControlPaneController controlPaneController) {
    this.controlPaneController = controlPaneController;
}

public ContentPaneController getContentPaneController() {
    return contentPaneController;
}

public void setContentPaneController(ContentPaneController contentPaneController) {
    this.contentPaneController = contentPaneController;
}

但它仍然返回NullPointerException。当我试图简单地引用ConnectionErrorController中的控制器时,我也遇到了同样的问题。如何从ConnectionErrorController中的控制器正确引用ToggleButton i WebEngine对象? 问候


共 (1) 个答案

  1. # 1 楼答案

    您正在使用“手动”创建控制器实例

    MainController mc = new MainController();
    

    @FXML-当FXMLLoader在加载FXML文件的过程中为您创建控制器时,带注释的字段由FXMLLoader初始化。由于您创建的控制器不是由FXMLLoader创建的控制器实例,其@FXML注释的字段未初始化(即它们为null),因此您会得到null指针异常

    在调用load()之后,可以通过调用getController()实例上的FXMLLoader来获取对FXMLLoader创建的控制器的引用

    如果希望一个控制器与另一个控制器通信,则通过在第二个控制器中定义适当的方法,将对一个控制器的引用传递给另一个控制器:

    public class ConnectionErrorController implements Initializable {
    
        private MainController mainController ;
    
        public void setMainController(MainController mainController) {
            this.mainController = mainController ;
        }
    
        // ...
    
        @Override
        public void initialize(URL location, ResourceBundle resources) {
    
            infoLabel.setText("Connection lost, please try again");
            tryButton.setText("try again");
            exitButton.setText("exit");
    
            tryButton.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent event) {
    
                    WebEngine webEngine = mainController.getContentPaneController().getVideoWebView().getEngine(); // 1
                    ToggleButton playButton = mainController.getControlPaneController().getPlayButton(); // 2
                    if (mainController.testInet()) {
                        mainController.play(webEngine, playButton);
                    } else {
                        // obviously you can now do something better than the "public static field hack" here:
                        MainController.exist = false;
                    }
                    tryButton.getScene().getWindow().hide();
                }
            });
    
            // ...
        }
    }    
    

    假设您正在MainController中的方法中加载第二个fxml文件,则可以执行以下操作:

    public class MainController {
    
        // ...
    
        public void showConnectionErrorWindow(String fileName) {
    
            FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/ConnectionError.fxml"));
            Parent root = loader.load();
            ConnectionErrorController connectionErrorController = loader.getController();
            connectionErrorController.setMainController(this);
    
            Scene scene = new Scene(root);
            Stage stage = new Stage();
            // etc...
        }
    
        // ...
    }
    

    注意,解决这个问题有很多更优雅的方法,例如将ConnectionErrorController传递回叫函数(以lambda表达式的形式)来处理对play(...)的调用,这避免了ConnectionErrorControllerMainController之间的紧密耦合。然而,由于您似乎是Java新手,这种更简单的方法可能更合适

    有关向控制器传递值的更多信息,请参见Passing Parameters JavaFX FXML