在 JavaFX 应用程序中的用户模型之间切换

Changing between User models in a JavaFX App

在我当前的 JavaFX 应用程序中,可能有不同的用户拥有不同的相关数据。在应用程序的不同部分,标签、表格、图形等都绑定到用​​户的可观察属性 class。

问题出现在更换用户的时候。绑定仍然绑定到以前的用户。除了在用户更改时重新绑定 UI 的所有部分之外,是否有更好的更新方法?

用户数据存储在传递给所有控制器的 DataManager class 中,因此它们可以访问相同的数据。

DataManager 示例:

public class DataManager {

    private ObservableList<User> userList = FXCollections.observableArrayList();
    private User currentUser;

   public void addUser(String name, int age, double height, double weight) {
        User newUser = new User(name, age, height, weight);
        try {
            DatabaseWriter.createDatabase();
            newUser.setId(UserDBOperations.insertNewUser(newUser));
        } catch (SQLException e) {
            e.printStackTrace();
        }
        userList.add(newUser);
    }

    public void deleteUser(User user) {
        try {
            DatabaseWriter.createDatabase();
            UserDBOperations.deleteExistingUser(user.getId());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        userList.remove(user);
    }

    public updateCurrentUser();

    public changeUser();
}

示例用户 class:

public class User {

    private int id;
    private StringProperty name;
    private IntegerProperty age;
    private DoubleProperty height;
    private DoubleProperty weight;
    private DoubleProperty bmi;
    private DoubleProperty totalDistance;

    private ObservableList<Event> eventList = FXCollections.observableArrayList();

有没有更好的方法来使用在这种情况下效果更好的模型数据?如果有助于回答,我可以提供更多 code/app 上下文。

谢谢

编辑 1:

public class ParentController {

    private DataManager dataManager = new DataManager();
    private ChildController childController1;
    private ChildController childController2;


    public void initializeChild() {
        childController1.setDataManager(dataManager);
        childController2.setDataManager(dataManager);
        // Controllers for different FXML Files
        //
    }
}

public class ChildController {

    /*  Child controller has elements which need data 
        from the DataManager
    */

    private DataManager dataManager;

    public void setDataManager(DataManager dataManager) {
        this.dataManager = dataManager;
    }
}

我试图克服的主要问题是如何使数据库、存储在内存中的模型以及所有不同的页面与同一数据模型保持同步。任何可以为我指明正确方向的建议或资源都会很棒。

编辑 2:添加了更多关于数据库连接的上下文

简单地说,您必须重新绑定控件才能显示新数据。

例如,当您将 TextProperty 绑定到 user.NameProperty 时,该绑定特定于那个 user 对象。即使您更改用户,绑定仍指向原始用户。

一种可能且简单的解决方案是使用 Singleton class 来存储您选择的 User。这将允许所选用户对您的整个应用程序可见:

User.java

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class User {

    private StringProperty username = new SimpleStringProperty();

    public User(String username) {
        this.username.set(username);
    }

    public String getUsername() {
        return username.get();
    }

    public StringProperty usernameProperty() {
        return username;
    }
}

GlobalData.java

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;

public class GlobalData {

    // Global property to hold the currently-selected user
    private ObjectProperty<User> selectedUser = new SimpleObjectProperty<>();

    private static GlobalData ourInstance = new GlobalData();

    public static GlobalData getInstance() {
        return ourInstance;
    }

    private GlobalData() {
    }

    public User getSelectedUser() {
        return selectedUser.get();
    }

    public ObjectProperty<User> selectedUserProperty() {
        return selectedUser;
    }

    public void setSelectedUser(User selectedUser) {
        this.selectedUser.set(selectedUser);
    }
}

现在,在您的 UI 控制器中,您只需要创建一个侦听器来监视 selectedUser 的变化。当用户改变时,只需重新绑定每个控制器中的 UI 个元素。

这是一个简单的 MCVE 演示:

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.Random;

public class Main extends Application {

    // The Label which holds the username value
    private Label lblUsername = new Label();

    // Grab a reference to the GlobalData singleton
    private GlobalData globalData = GlobalData.getInstance();

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

    @Override
    public void start(Stage primaryStage) {

        // Create the initial sample User
        globalData.setSelectedUser(new User("User #1"));

        // Simple interface
        VBox root = new VBox(10);
        root.setPadding(new Insets(10));
        root.setAlignment(Pos.CENTER);

        // HBox to hold the username display
        HBox hBox = new HBox(5);
        hBox.setAlignment(Pos.CENTER);

        // Add the username labels to the HBox
        hBox.getChildren().addAll(
                new Label("Username:"),
                lblUsername
        );

        // Bind the Label to display the current selected user's username
        lblUsername.textProperty().bind(globalData.getSelectedUser().usernameProperty());

        // Here we use a listener on the the selectedUser property. When it changes, we
        // call the rebindUser() method to update the UI
        globalData.selectedUserProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue != null) {
                rebindUser(newValue);
            }
        });

        // Add a button that just changes the selectedUser
        Button button = new Button("Change User");

        // Set the action for the button to change users
        button.setOnAction(this::changeUser);

        // Add the HBox and button to the root layout
        root.getChildren().addAll(hBox, button);

        // Show the Stage
        primaryStage.setWidth(400);
        primaryStage.setHeight(200);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    private void changeUser(ActionEvent event) {

        // Create a new user with a random # at the end
        Random rnd = new Random();
        int num = rnd.nextInt(50 + 2);

        globalData.setSelectedUser(new User("User #" + num));
    }

    // This method accepts a new User object and updates all the displayed bindings
    private void rebindUser(User newUser) {
        lblUsername.textProperty().unbind();
        lblUsername.textProperty().bind(newUser.usernameProperty());
    }
}

这会产生以下输出:

单击该按钮将创建一个随机新用户,更新 GlobalData 单例的 selectedUser 属性,并通过 [=21] 更新 Label =]方法。