Как можно сохранить один экземпляр модели User на нескольких контроллерах с Java / JavaFX MVC? - PullRequest
0 голосов
/ 19 апреля 2020

Обзор

Я работаю над простым приложением JavaFX с несколькими сценами, используя MVC Архитектурный шаблон. У меня есть дизайн, но у меня проблемы с сохранением модели User в разных сценах. На данный момент у меня нет никакого бэкэнда. Я хочу просто создать экземпляр модели User при запуске приложения и отобразить этот единственный экземпляр в моем приложении. Любые изменения в этой пользовательской модели будут обновляться по всем сценам. Я не собираюсь упорствовать после закрытия приложения.

Я считаю, что проблема возникает из-за выбора дизайна, который у меня был на ранней стадии разработки. Я использую контроллер с именем SceneNavigatorControl , который вызывает класс Navigator , который обрабатывает представление различных сцен в приложении. Эти сцены представляют собой файлы .f xml.

SceneNavigatorControl

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();


}

}

Приведенный выше код указывает, в какую сцену может попасть пользователь. В зависимости от того, какая кнопка нажата. Вызывается одна из вышеуказанных функций, и сцена отображается с помощью класса навигатора. Я думаю, что именно здесь я создаю экземпляр User и передаю его всем другим контроллерам

Класс навигатора

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;
}

}

Класс навигатора просто проверяет, если .f xml файл с заданным именем существует. Если это так, то он заменяет текущую сцену на сцене на данную.

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>

Это наш вид, созданный с использованием файла .f xml. В первой строке мы объявляем, какое представление связано с каким контроллером.

HomeController

public class HomeController implements Initializable {

@FXML
private Pane Home;

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

}

ActivityTracker (Main)

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 Ответ

0 голосов
/ 21 апреля 2020

Ниже приведено 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;
    }
}

Определите два очень базовых c f xml представления, каждое с контроллером:

FirstName. f xml

<?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>

LastName.f xml

<?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.fxml и LastName.fxml: Main.f xml

<?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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...