有 Java 编程相关的问题?

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

如何使用Java/JavaFXMVC跨多个控制器持久化用户模型的单个实例?

概述

我正在使用MVC架构模式开发一个具有多个场景的简单JavaFX应用程序。我已经准备好了设计,但是在不同场景中持久化用户模型时遇到了问题。目前我没有任何后端。我希望在应用程序启动时只实例化用户模型,并在我的应用程序中显示单个实例。对该用户模型的任何更改都将在整个场景中更新。我不希望在应用程序关闭后继续使用

我相信这个问题源于我在开发早期的一个设计选择。我使用名为SceneNavigatorControl的控制器,该控制器调用类Navigator,该类处理应用程序中不同场景的表示。这些场景非常有趣。fxml文件

场景激活控制

public class SceneNavigatorControl implements Initializable {

@FXML
private BorderPane mainStage;


@FXML
private void displayHomeScene() {
    Navigator object = new Navigator();
    Pane view = object.getScene("Home");
    handleButtonChange("Home");

    mainStage.setCenter(view);
}

@FXML
private void displayProfileScene() {
    Navigator object = new Navigator();
    Pane view = object.getScene("Profile");
    handleButtonChange("Profile");
    mainStage.setCenter(view);
}


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

    // Called when the application starts, should this be where I instantiate User?
    //User user = new User();
    //user.setName("Bob");

    displayHomeScene();


}

}

上面的代码处理将用户带到哪个场景。取决于点击哪个按钮。调用上述函数之一,并使用Navigator类显示场景。我想这就是我实例化用户并将其传递给所有其他控制器的地方

导航器类

public class Navigator {
private Pane view;

public Pane getScene(String fileName) {
    try {
        URL fileUrl = ActivityTracker.class.getResource("/ActivityTracker/Views/" + fileName + ".fxml");
        if (fileUrl == null) {
            throw new java.io.FileNotFoundException("FXML File cannot be found");
        }

        view = new FXMLLoader().load(fileUrl);
    } catch (Exception e) {
        System.out.print("No page " + fileName + " please check FXMLLoader");
    }
    return view;
}

}

navigator类简单检查。存在具有给定名称的fxml文件。如果是,它将用给定的场景替换舞台上的当前场景

HomeView

<AnchorPane fx:id="Home" prefHeight="500.0" prefWidth="500.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ActivityTracker.Controllers.HomeController">
<children>
    <Label fx:id="clockLabel" layoutX="90.0" layoutY="32.0" textFill="WHITE" AnchorPane.leftAnchor="90.0" AnchorPane.topAnchor="32.0">
     <font>
        <Font name="Lucida Grande" size="100.0" />
     </font></Label>
  <Pane layoutX="410.0" layoutY="-1.0" prefHeight="500.0" prefWidth="90.0" style="-fx-background-color: #1d1d1d;" />
</children>

这是我们的视图,它是使用。fxml文件。在第一行中,我们声明哪个视图与哪个控制器关联

家庭控制器

public class HomeController implements Initializable {

@FXML
private Pane Home;

@Override
public void initialize(URL location, ResourceBundle resources) {
    // Print users details 
}

}

活动跟踪器(主)

public class ActivityTracker extends Application {

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

@Override
public void start(Stage primaryStage) {
    try {
        Parent root = FXMLLoader.load(ActivityTracker.class.getResource("Views/Stage.fxml"));
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    } catch (Exception ex) {
        Logger.getLogger(ActivityTracker.class.getName()).log(Level.SEVERE, null, ex);
    }
}

}

用户模型

public class User {

// Define all user stat variables for the model
private String userName;

/**
 * Method that returns the users name
 * @return users name of type String
 */
public String getUsersName() {
    return userName;
}

/**
 * Method that takes in a string value and sets it as the current users name
 * @param  name  the current users weight
 */
public void setUsersName(String name) {
    this.userName = name;
}

}


共 (1) 个答案

  1. # 1 楼答案

    下面是将一个模型实例设置为两个控制器的mre
    定义两个控制器使用的简单模型:

    class User {
    
        private final String fName, lName;
    
        public User(String fName, String lName) {
            this.fName = fName;
            this.lName = lName;
        }
    
        public String getFirstName() {
            return fName;
        }
    
        public String getLastName() {
            return lName;
        }
    }
    

    定义两个非常基本的fxml视图,每个视图都有一个控制器:

    名字。fxml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.scene.text.Font?>
    
    <HBox alignment="CENTER_LEFT" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" 
    prefHeight="30.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" 
    fx:controller="fx_tests.FNameController">
       <children>
          <Label text="First Name: " HBox.hgrow="NEVER">
             <font>
                <Font size="16.0" />
             </font>
          </Label>
          <Label fx:id="fName" text="&quot;-&quot;">
             <font>
                <Font size="16.0" />
             </font>
          </Label>
       </children>
    </HBox>
    

    姓氏。fxml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.scene.text.Font?>
    
    <HBox alignment="CENTER_LEFT" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" 
    prefHeight="30.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" 
    fx:controller="fx_tests.LNameController">
       <children>
          <Label text="Last Name: " HBox.hgrow="NEVER">
             <font>
                <Font size="16.0" />
             </font>
          </Label>
          <Label fx:id="lName" text="&quot;-&quot;">
             <font>
                <Font size="16.0" />
             </font>
          </Label>
       </children>
    </HBox>
    

    定义一个简单的界面:

    interface Controller {
        void setModel(User model);
    }
    

    并由两个控制器来实现:

    import javafx.fxml.FXML;
    import javafx.scene.control.Label;
    
    public class FNameController implements Controller{
    
        @FXML
        private Label fName;
    
        @Override
        public void setModel(User model) {
            fName.setText(model.getFirstName());
        }
    }
    


    import javafx.fxml.FXML;
    import javafx.scene.control.Label;
    
    public class LNameController implements Controller{
    
        @FXML
        private Label lName;
    
        @Override
        public void setModel(User model) {
            lName.setText(model.getLastName());
        }
    }
    

    定义作为FirstName.fxmlLastName.fxml父视图的主视图:
    Main。fxml

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.geometry.Insets?>
    <?import javafx.scene.layout.BorderPane?>
    <?import javafx.scene.layout.VBox?>
    <?import javafx.scene.text.Font?>
    <?import javafx.scene.text.Text?>
    
    <BorderPane xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fx_tests.MainController">
       <top>
          <Text strokeType="OUTSIDE" strokeWidth="0.0" text="User Info" textAlignment="CENTER" wrappingWidth="250" BorderPane.alignment="CENTER">
             <font>
                <Font size="20.0" />
             </font>
          </Text>
       </top>
       <center>
          <VBox fx:id="infoPane" alignment="CENTER" spacing="10.0" BorderPane.alignment="CENTER">
             <BorderPane.margin>
                <Insets left="20.0" />
             </BorderPane.margin>
          </VBox>
       </center>
    </BorderPane>
    

    主视图的控制器将模型设置为两个控制器:

    import java.io.IOException;
    import javafx.fxml.FXML;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.layout.Pane;
    import javafx.scene.layout.VBox;
    
    public class MainController {
    
        @FXML
        private VBox infoPane;
    
        @FXML
        void initialize() throws IOException{
    
            try {
                User model = new User("Ann","Davis"); //initialize model
    
                FXMLLoader loader = new FXMLLoader(getClass().getResource("FirstName.fxml"));
                Pane fName =  loader.load();
                Controller controller = loader.getController();
                controller.setModel(model); //set model to first name controller
    
                loader = new FXMLLoader(getClass().getResource("LastName.fxml"));
                Pane lName =  loader.load();
                controller = loader.getController();
                controller.setModel(model); //set model to last name controller
    
                infoPane.getChildren().addAll(fName, lName);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    

    使用以下各项进行测试:

    import java.io.IOException;
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.stage.Stage;
    
    public class FxmlTest extends Application {
    
        @Override
        public void start(Stage primaryStage) throws IOException {
    
                Pane root = FXMLLoader.load(getClass().getResource("Main.fxml"));
                primaryStage.setScene(new Scene(root));
                primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(null);
        }
    }