Как сделать правильный шаблон MVC с помощью Javafx и Scene Builder - PullRequest
1 голос
/ 30 мая 2019

Привет, я новичок в Java и Javafx, поэтому надеюсь, что вы поможете мне с проблемой. Я пытаюсь создать правильный шаблон MVC с помощью Scene Builder, но мой код не работает, и я не знаю почему.

Я понял, что класс Model должен получать данные, а класс Controller должен использовать и обрабатывать данные, но у меня большие проблемы с тем, что конструктор Scene действительно принимает один класс контроллера для одного файла FXML. Вот почему я попытался использовать геттеры и сеттеры, чтобы установить связь между моделью и контроллером.

Но я также думаю, что делаю это неправильно.

Основной класс:

package application;

import javafx.application.Application;
import javafx.fxml.*;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application{

    @Override
    public void start(Stage primaryStage) throws Exception{

        try {
        Parent root = FXMLLoader.load(getClass().getResource("/login/LoginUI.fxml"));
        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void startApp(Stage Stage) throws Exception{

        try {
            Parent root = FXMLLoader.load(getClass().getResource("/financeApp/UI.fxml"));
            Scene scene = new Scene(root, 1022, 593);
            Stage.setScene(scene);
            Stage.show();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

Класс контроллера:

package login;

import application.Main;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import login.ModelLogin;

public class ControllerLogin {

    @FXML TextField userNameField;
    @FXML PasswordField passwordField;
    @FXML Button loginButton;
    ModelLogin model = new ModelLogin();

    public void setUserName() {
        model.setUserNameField(userNameField);
    }

    public void setPassword() {
        model.setPasswordField(passwordField);
    }

    public void login(ActionEvent event) {
        if (model.getUserNameField().getText().equals("test") && model.getPasswordField().getText().equals("1234")) {
            Stage stage = new Stage();
            Main startUI = new Main();

            try {
                startUI.startApp(stage);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else {
            System.out.println("Try again");
        }
    }
}

Класс модели:

package login;

import javafx.scene.control.Button;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;

public class ModelLogin {

    private TextField userNameField;
    private PasswordField passwordField;

    public TextField getUserNameField() {
        return userNameField;
    }
    public void setUserNameField(TextField userNameField) {
        this.userNameField = userNameField;
    }
    public PasswordField getPasswordField() {
        return passwordField;
    }
    public void setPasswordField(PasswordField passwordField) {
        this.passwordField = passwordField;
    }

}

и это файл FXML, созданный с помощью Scene Builder:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="290.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="login.ControllerLogin">
   <children>
      <AnchorPane prefHeight="290.0" prefWidth="400.0">
         <children>
            <Label alignment="CENTER" layoutX="150.0" layoutY="38.0" prefHeight="30.0" prefWidth="100.0" text="Login">
               <font>
                  <Font name="System Bold" size="20.0" />
               </font>
            </Label>
            <Label layoutX="159.0" layoutY="108.0" text="Benutzername">
               <font>
                  <Font name="System Bold" size="12.0" />
               </font>
            </Label>
            <TextField fx:id="userNameField" layoutX="126.0" layoutY="125.0" onAction="#setUserName" />
            <Label layoutX="175.0" layoutY="165.0" text="Passwort">
               <font>
                  <Font name="System Bold" size="12.0" />
               </font>
            </Label>
            <PasswordField fx:id="passwordField" layoutX="126.0" layoutY="182.0" onAction="#setPassword" />
            <Button fx:id="loginButton" layoutX="175.0" layoutY="233.0" mnemonicParsing="false" onAction="#login" text="Login" />
         </children>
      </AnchorPane>
   </children>
</VBox>

Папка

enter image description here

Буду рад обратной связи. Спасибо !!

1 Ответ

2 голосов
/ 30 мая 2019

Все элементы пользовательского интерфейса должны быть в представлении. Модель должна иметь только информацию и логику, которые используют представление и контроллер.

public class ModelLogin {

    private final String userName;
    private final String password;

    ModelLogin(String userName, String password) {

        this.userName = userName;
        this.password = password;
    }

    boolean isCorrectCredentials(String userName, String password){

        return this.userName.equals(userName)&&this.password.equals(password);
    }
}

Контроллер «связывает» вид и модель: он выполняет проверку учетных данных и смена сцены. Обратите внимание, что он модифицирован, чтобы принимать ссылку Main, чтобы он мог изменить сцену:

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;

public class ControllerLogin {

    @FXML TextField userNameField;
    @FXML PasswordField passwordField;

    private ModelLogin model;
    private Main main;

    @FXML
    void initialize() {
        model = new ModelLogin("test", "1234");
    }

    public void login(ActionEvent event) {

        if (model.isCorrectCredentials(userNameField.getText(), passwordField.getText() )) {

            try {
                main.startApp();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else {
            System.out.println("Try again");
        }
    }

    void setMain(Main main) {
        this.main = main;
    }
}

Текстовое поле onAction не используется, поэтому оно было удалено из fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="290.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8" 
xmlns:fx="http://javafx.com/fxml/1" fx:controller="login.ControllerLogin">
   <children>
      <AnchorPane prefHeight="290.0" prefWidth="400.0">
         <children>
            <Label alignment="CENTER" layoutX="150.0" layoutY="38.0" prefHeight="30.0" prefWidth="100.0" text="Login">
               <font>
                  <Font name="System Bold" size="20.0" />
               </font>
            </Label>
            <Label layoutX="159.0" layoutY="108.0" text="Benutzername">
               <font>
                  <Font name="System Bold" size="12.0" />
               </font>
            </Label>
            <TextField fx:id="userNameField" layoutX="126.0" layoutY="125.0"/>
            <Label layoutX="175.0" layoutY="165.0" text="Passwort">
               <font>
                  <Font name="System Bold" size="12.0" />
               </font>
            </Label>
            <PasswordField fx:id="passwordField" layoutX="126.0" layoutY="182.0" />
            <Button fx:id="loginButton" layoutX="175.0" layoutY="233.0" mnemonicParsing="false" onAction="#login" text="Login" />
         </children>
      </AnchorPane>
   </children>
</VBox>

Main был изменен, чтобы получить ссылку на контроллер и изменить сцену:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application{

    private Stage primaryStage;
    private Parent root;

    @Override
    public void start(Stage primaryStage) throws Exception{

        try {

            this.primaryStage = primaryStage;
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/login/LoginUI.fxml"));
            root = loader.load();
            ControllerLogin controller = loader.getController();
            controller.setMain(this);

            Scene scene = new Scene(root, 400, 400);
            primaryStage.setScene(scene);
            primaryStage.show();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void startApp() throws Exception{

        try {
            root = FXMLLoader.load(getClass().getResource("/financeApp/UI.fxml"));
            Scene scene = new Scene(root, 1022, 593);
            primaryStage.setScene(scene);
            primaryStage.show();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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