如何使用 Javafx 和 Scene builder 制作合适的 MVC 模式
How to make a proper MVC Pattern with Javafx and Scene builder
您好,我是 Java 和 Javafx 的新手,希望您能帮我解决问题。我正在尝试使用 Scene Builder 执行正确的 MVC 模式,但我的代码不起作用,我不知道为什么。
我明白模型 class 必须获取数据,而控制器 class 应该使用和处理数据,但我有一个很大的问题,即场景构建器确实接受一个控制器 class 对于一个 FXML 文件。这就是为什么我尝试使用 getter 和 setter 来建立模型和控制器之间的连接。
但我也觉得我做的不对。
主要class:
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);
}
}
控制器class:
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");
}
}
}
型号class:
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>
文件夹
我很乐意提供一些反馈。谢谢!!
所有 UI 元素都应该在视图中。
模型应该只有视图和控制器使用的信息和逻辑。
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);
}
}
控制器 "wires" 视图和模型:它处理凭据验证和
场景的变化。
请注意,它被修改为接受 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);
}
}
您好,我是 Java 和 Javafx 的新手,希望您能帮我解决问题。我正在尝试使用 Scene Builder 执行正确的 MVC 模式,但我的代码不起作用,我不知道为什么。
我明白模型 class 必须获取数据,而控制器 class 应该使用和处理数据,但我有一个很大的问题,即场景构建器确实接受一个控制器 class 对于一个 FXML 文件。这就是为什么我尝试使用 getter 和 setter 来建立模型和控制器之间的连接。
但我也觉得我做的不对。
主要class:
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);
}
}
控制器class:
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");
}
}
}
型号class:
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>
文件夹
我很乐意提供一些反馈。谢谢!!
所有 UI 元素都应该在视图中。 模型应该只有视图和控制器使用的信息和逻辑。
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);
}
}
控制器 "wires" 视图和模型:它处理凭据验证和
场景的变化。
请注意,它被修改为接受 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);
}
}