我已经使用SceneBuilder设计了布局。布局必须以相同的方式显示不同的信息。例如,我有一个用于用户名的标签,如果我使用用户名登录,则希望它显示出来,以便有我的用户名。但是我有很多这样的标签。有没有一种方法可以给标签提供%username的文本(仅作为示例),最后只需替换它即可。这样我就可以使用SceneBuilder创建布局,然后始终按需要放置内容?我需要在运行时多次加载这些fxml文件,并且几乎总是在加载新信息。
有什么想法吗?我知道我可以通过代码生成布局,然后很容易替换文本,但是我喜欢SceneBuilder,只是想知道是否有一种简便的方法。
答案 0 :(得分:0)
您正在寻找的是Java,JavaFX和一般的面向对象编程的非常基本的功能。
无需构建多个FXML文档,也无需手动替换文本。您只需使用一个FXML文档并使用适当的MVC( M odel- V iew- C ontroller)方法即可完成此操作。
您将要从所谓的数据模型或模型对象开始。在您的情况下,类似于User
对象:
User.java
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class User {
// These properties are used to display User data in the Scene
private StringProperty username = new SimpleStringProperty();
private StringProperty emailAddress = new SimpleStringProperty();
/**
* A simple constructor to build the User object with a username and email address
*/
public User(String username, String emailAddress) {
// Set the values for each of the User properties
this.username.set(username);
this.emailAddress.set(emailAddress);
}
public String getUsername() {
return username.get();
}
public StringProperty usernameProperty() {
return username;
}
public void setUsername(String username) {
this.username.set(username);
}
public String getEmailAddress() {
return emailAddress.get();
}
public StringProperty emailAddressProperty() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress.set(emailAddress);
}
}
User.java
中要注意的重要事项是StringProperty
声明。当我们加载FXML控制器时,它们将起作用。
MainLayout.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<GridPane hgap="10.0" vgap="5.0">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" minWidth="-Infinity" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="150.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Username:" />
<Label text="Email Address:" GridPane.rowIndex="1" />
<Label fx:id="lblUsername" GridPane.columnIndex="1" />
<Label fx:id="lblEmailAddress" GridPane.columnIndex="1" GridPane.rowIndex="1" />
</children>
</GridPane>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
这只是带有GridPane
的简单FXML布局,用于显示我们的User
信息。
MainController.java
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class MainController {
// Here, we define our FXML elements. This allows us to access those elements directly from our Controller
@FXML
private Label lblUsername;
@FXML
private Label lblEmailAddress;
// This is the User object that holds the data we want to display
private User user;
public MainController(User user) {
this.user = user;
}
/**
* The initialize() method is called when the FXML document is loaded. This is where we will populate our Scene
* with the data from the User object passed to the controller's constructor. Since we already created our
* constructor from the Main class, we have a valid User object to work with
*/
@FXML
private void initialize() {
// There are two basic ways we can setup our Scene to display the User data. This demonstrates the proper Binding
// method of doing so.
// Bind the value of each Label to show the corresponding data from the User object
lblUsername.textProperty().bind(user.usernameProperty());
lblEmailAddress.textProperty().bind(user.emailAddressProperty());
// The other method would be to simply set the text for each label. We will comment this out, however, as
// using the above binding is preferred.
// lblUsername.setText(user.getUsername());
// lblEmailAddress.setText(user.getEmailAddress());
}
}
还记得User
对象如何定义两个Property
字段吗?现在在我们的MainController
中看到每个Label
也都有一个textProperty
吗?当我们在该属性上调用bind()
方法时,基本上是在告诉Java始终将textProperty
保持等于user.username
或user.emailAddress
属性包含的值。
Main.java
现在,让我们创建将创建实际应用程序的类:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// First, let's create a sample User, passing the username and email address to the constructor
User user = new User("zephyr", "zephyr@home.com");
primaryStage.setTitle("Data Object Sample");
try {
// Tell JavaFX where to find the FXML file and create a loader for it
FXMLLoader loader = new FXMLLoader(getClass().getResource("MainLayout.fxml"));
// Create a new MainController and pass our sample User to it
MainController controller = new MainController(user);
// Now that we've initialized our MainController with a User, let's set the controller for this FXML
loader.setController(controller);
// We may now load the FXML document and display the Scene
primaryStage.setScene(new Scene(loader.load()));
// Finally, show the Scene
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
就是这样!
运行应用程序时可以看到,MainController
看到User
并将username
和emailAddress
属性绑定到在其中创建的Label
节点FXML。
您现在可以仅重复使用一种FXML布局来显示所需的任何User
。
如果您想保持场景加载并只更改User
,则可以通过在MainController.java
上添加一个“ setter”来轻松实现:
public void setUser (User user) {
this.user = user;
}
每次调用该方法时,User
中的MainController
对象都会更改,JavaFX会注意到这一点,并且每个Label
的绑定都会自动更新,并显示新用户的信息。