JavaFX使用应替换文本的节点创建fxml模板

时间:2018-08-18 11:37:08

标签: java templates javafx

我已经使用SceneBuilder设计了布局。布局必须以相同的方式显示不同的信息。例如,我有一个用于用户名的标签,如果我使用用户名登录,则希望它显示出来,以便有我的用户名。但是我有很多这样的标签。有没有一种方法可以给标签提供%username的文本(仅作为示例),最后只需替换它即可。这样我就可以使用SceneBuilder创建布局,然后始终按需要放置内容?我需要在运行时多次加载这些fxml文件,并且几乎总是在加载新信息。

有什么想法吗?我知道我可以通过代码生成布局,然后很容易替换文本,但是我喜欢SceneBuilder,只是想知道是否有一种简便的方法。

1 个答案:

答案 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.usernameuser.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并将usernameemailAddress属性绑定到在其中创建的Label节点FXML。

您现在可以仅重复使用一种FXML布局来显示所需的任何User

如果您想保持场景加载并只更改User,则可以通过在MainController.java上添加一个“ setter”来轻松实现:

public void setUser (User user) {
    this.user = user;
}

每次调用该方法时,User中的MainController对象都会更改,JavaFX会注意到这一点,并且每个Label的绑定都会自动更新,并显示新用户的信息。