在 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
=]方法。
在我当前的 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
=]方法。