java - 如何使用 Javafx 和场景构建器创建正确的 MVC 模式

标签 java javafx scenebuilder

您好,我对 Java 和 Javafx 非常陌生,所以我希望您能帮助我解决问题。我正在尝试使用场景生成器执行正确的 MVC 模式,但我的代码无法正常工作,我不知道为什么。

我知道 Model 类必须获取数据,而 Controller 类应该使用和处理数据,但我有一个大问题,场景构建器确实接受一个 FXML 文件的一个 Controller 类。这就是为什么我尝试使用 getter 和 setter 来建立模型和 Controller 之间的连接。

但我也认为我做得不对。

主类:

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

Controller 类:

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 文件:

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

我很高兴收到一些反馈。谢谢!!

最佳答案

所有 UI 元素都应位于 View 中。 模型应该只包含 View 和 Controller 使用的信息和逻辑。

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

Controller “连接” View 和模型:它处理凭证验证和 场景改变。 请注意,它被修改为接受 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 以获取对 Controller 的引用,并更改场景:

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

关于java - 如何使用 Javafx 和场景构建器创建正确的 MVC 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56369152/

相关文章:

java - @NamedQuery INNER JOIN 不起作用

java - 如何调试外部 OSGI 包?

java - 根据 ArrayList 中存储的数据制作 CandleStick 图表动画

javafx-2 - 像在场景生成器中一样实现拖放

java - 如何使 JavaFX 对象出现在 FXML 中?

java - 如何修复 'Server sending data faster than client can handle, server freezes'

java - 使用 Dropbox Java api : DropboxSSLException: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

JavaFx Webview HTML5 拖放

css - JavaFx:如何为节点的给定样式类获取相应的样式表?

java - 如何使用 SceneBuilder 查看 fxml?