如何使用 JavaFX 将对象从一个控制器传递到另一个控制器

How to pass an object from one controller to another with JavaFX

我目前正在尝试构建具有登录和注销功能的客户端-服务器应用程序。在 LoginViewController 中,我正在创建一个客户端对象。我希望能够在 ClientViewController 中使用这个对象,例如用于注销。如何将此对象从 LoginViewController 传递到 ClientViewController?由于登录成功我不想实例化一个新对象,我想使用通过登录并且当前在服务器端处于活动状态的对象。

如何实现?


Main.java

public class Main extends Application {
    private static Stage primaryStage;
    private static BorderPane mainLayout;

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        this.primaryStage = primaryStage;
        showLoginView();
    }

    public static void showLoginView() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("LoginView.fxml"));
        mainLayout = loader.load();
        Scene scene = new Scene(mainLayout, 540, 400);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }

    public static void showClientView() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("ClientView.fxml"));
        mainLayout = loader.load();
        Scene scene = new Scene(mainLayout, 900, 600);
        primaryStage.setScene(scene);
        primaryStage.setResizable(true);
        primaryStage.show();
    }
}

LoginViewController.java

public class LoginViewController implements Initializable {
    @FXML
    private Main main;
    @FXML
    private TextField username;
    @FXML
    private PasswordField password;
    @FXML
    private Button login;
    @FXML
    private Button register;

    private Client client;

    private Login userLogin;

    private String loginStatus;

    @FXML
    private Label loginInfo;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        loginInfo.setVisible(false);
    }

    @FXML
    public void login() throws IOException {
        loginStatus = "timeout";
        loginInfo.setVisible(false);
        client = new Client("127.0.0.1", 3250, this); // Client object created
        userLogin = new Login(username.getText(), password.getText());
        client.setOnConnected(() -> client.sendToServer(userLogin));
        client.start();
        int waitForLoginStatusCounter = 0;
        while(loginStatus.equals("timeout")) {
            try {
                Thread.sleep(250);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            waitForLoginStatusCounter++;
            if(waitForLoginStatusCounter >= 20) {
                break;
            }
        }
        if(loginStatus.equals("success")) {
            main.showClientView();
        }
        else if(loginStatus.equals("failed")) {
            loginInfo.setVisible(true);
            loginInfo.setText("Login failed: Wrong username or password");
        }
        else {
            loginInfo.setVisible(true);
            loginInfo.setText("Timeout: Check connection");
        }
    }

    public String getLoginStatus() {
        return loginStatus;
    }

    public void setLoginStatus(String loginStatus) {
        this.loginStatus = loginStatus;
    }
}

ClientViewController.java

public class ClientViewController implements Initializable {

    @FXML
    private Main main;
    @FXML
    private TreeView<String> treeview;
    @FXML
    private Button logout;

    private Client client;

    private String username;

    private Logout userLogout;

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

    }

    @FXML
    public void logout() throws IOException {
        userLogout = new Logout(username);
        client.sendToServer(userLogout); // Null at this point
        main.showLoginView();
    }
}

Client.java(从服务器发送和接收对象)

public class Client extends Thread {
    private String ip;
    private int port;
    private Socket socket;
    private ObjectOutputStream oos;
    private ObjectInputStream ois;
    private Runnable onConnected;
    private LoginViewController lvc;
    private RegisterViewController rvc;

    public void setOnConnected(Runnable onConnected) {
        this.onConnected = onConnected;
    }

    public Client(String ip, int port, LoginViewController lvc) {
        this.ip = ip;
        this.port = port;
        this.lvc = lvc;
    }

    public Client(String ip, int port, RegisterViewController rvc) {
        this.ip = ip;
        this.port = port;
        this.rvc = rvc;
    }

    public void run() {
        try {
            socket = new Socket(ip, port);
            oos = new ObjectOutputStream(socket.getOutputStream());
            ois = new ObjectInputStream(socket.getInputStream());
            if(onConnected != null) {
                onConnected.run();
            }
            while (true) {
                try {
                    Object obj = ois.readObject();
                    if (obj instanceof Login) {
                        String loginStatus = ((Login) obj).getLoginStatus();
                        lvc.setLoginStatus(loginStatus);
                    }
                    else if(obj instanceof Register) {
                        String registerStatus = ((Register) obj).getRegisterStatus();
                        rvc.setRegisterStatus(registerStatus);
                    }
                } catch (IOException | ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendToServer(Object obj) {
        try {
            oos.writeObject(obj);
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

执行以下代码后问题解决:

LoginViewController.java

    if(loginStatus.equals("success")) {
        main.showClientView(client); // Passing the client-object to showClientView method
    }

Main.java

public static void showClientView(Client client) throws IOException { // Taking the client-object as an argument from LoginViewController
    FXMLLoader loader = new FXMLLoader();
    loader.setLocation(Main.class.getResource("ClientView.fxml"));
    mainLayout = loader.load();

    ClientViewController cvc = loader.getController(); // This did the "trick"
    cvc.setClient(client); // Passing the client-object to the ClientViewController

    Scene scene = new Scene(mainLayout, 900, 600);
    primaryStage.setScene(scene);
    primaryStage.setResizable(true);
    primaryStage.show();
}

ClientViewController.java

public void setClient(Client client) { // Setting the client-object in ClientViewController
    this.client = client;
}