JavaFX多场景开启,场景复制

时间:2021-04-29 03:59:12

标签: javafx

我想要一个登录页面(我有工作),然后进入一个新场景(我还没有工作)。

然后我希望这个场景有你可以点击的项目。每个项目打开另一个场景/窗口。但是您可以根据需要打开任意数量。它们包含不同的数据,但相同的 fxml/scene。

这可能吗?

enter image description here

1 个答案:

答案 0 :(得分:0)

是的,这是可能的。它需要您为场景创建一个控制器,然后为该场景的每个新实例创建该控制器对象的新实例。我认为它也需要每次都通过一个新阶段。

编辑: 未能为场景的每个新实例创建新的控制器实例意味着有可能从另一个窗口中的打开场景覆盖一个窗口中打开场景中的数据窗口。

如果您不熟悉 JavaFX,我将提供一些创建新视图的示例。这个问题主要是关于这样做的方法。

假设您遵循 MVC 模式,您的项目的结构可能类似于:

编辑:更正了 FXMLLoader 的不当使用

MainApp.java

import java.io.IOException;

import javafx.application.Application;

import javafx.fxml.FXMLLoader;

import javafx.stage.Modality;
import javafx.stage.Stage;

import Controller.LoginController;

public class Main
        extends Application
{

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

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

            FXMLLoader loader = new FXMLLoader(Main.class.getResource("/View/Login.fxml"));
            Parent     root   = loader.load();

            stage.setScene(new Scene(root));

            LoginController loginController = loader.getController();

            // Pass this stage by calling the controller's stage setter.
            // Conversely we could call a singleton class here to
            // give us a stage object that we can re-use many times 
            loginController.setStage(stage);

            stage.initStyle(StageStyle.UNIFIED);

            stage.setResizable(false);
            stage.getIcons().add(new Image("Resources/icon.png"));
            stage.setTitle("");

            stage.centerOnScreen();
            stage.show();

        } catch (IOException ex) {
            // exception handling
        }
    }
}

登录控制器.java

import java.net.URL;

import java.io.IOException;

import java.util.ResourceBundle;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;

import javafx.event.EventHandler;

import javafx.scene.control.Button;

import javafx.stage.Modality;
import javafx.stage.Stage;

import Controller.MainController;

public class LoginController implements Initializable
{
    @FXML
    private Button loginButton;
    private Stage stage;

    public LoginController() {}

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    
        loginButton.addEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
            doLogin();
        });
    }

    @FXML
    private void doLogin() {
    
        // handle login
        
        showMainApplicationView();
    
    }

    @FXML
    private void showMainApplicationView() {
        
        try {

        loader = new FXMLLoader(LoginController.class.getResource("View/mainView.fxml"));

        Parent         root           = (Parent) loader.load();
        MainController mainController = new MainController();

        loader.setController(mainController);

        mainController.setStage(new Stage());

        stage.initModality(m);
        stage.setResizable(isResizable);
        stage.getIcons().add(new Image("Resources/icon.png"));
        stage.setTitle(title);
        stage.setScene(new Scene(root));

        return stage;
        } catch (IOException e) {

            // exception handling

        }
    }

    @FXML
    public void setStage(Stage stage) {
    
        this.stage = stage;

    }

}

MainController.java

import java.net.URL;

import java.util.ResourceBundle;

import javafx.fxml.FXML;
import javafx.fxml.Initializable;

import javafx.stage.Stage;

public class LoginController implements Initializable
{

    public LoginController() {}

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


    @FXML
    private void showSubview() {
        /* Same code as the prior examples for launching a new view
         * It will work for creating as many new "windows" of the same
         * view as you desire. If you need to pass different types of
         * data to each view you can use a DAO model, or some kind of
         * "Instance" object that works for sending/receiving data to/from
         * the subview from this class.
         */

    }

    @FXML
    public void setStage(Stage stage) {
    
        this.stage = stage;

    }

}

如果您想多次重复使用一个舞台并以不同的深度进入子视图,我建议使用 Singleton 类。

StageHolder.java

import javafx.stage.Stage;

public final StageHolder
{
    private Stage stage;
    
    private final static StageHolder INSTANCE = new StageHolder();

    private StageHolder() {}

    public static StageHolder getInstance() {

        return INSTANCE;
    }

    public Stage getStage() {

        return this.stage;
    }

    // you can omit this setter if you only want to re-use a single stage over and over.
    public void setStage(Stage stage) {

        this.stage = stage;

    }
}