JavaFX绑定同步两个值:当依赖变量更改时,其他变量更改。
要将属性绑定到另一个属性,请调用bind()方法,该方法在一个方向绑定值。 例如,当属性A绑定到属性B时,属性B的更改将更新属性A,但不可以反过来。

绑定选项

JavaFX提供了许多绑定选项,以便在域对象和GUI控件中的属性之间进行同步。
我们可以在JavaFX的Properties API中使用以下三种绑定策略:

  • Java Bean上的双向绑定
  • Fluent API的高级绑定
  • 使用javafx.beans.binding定义绑定对象进行低级绑定。

    双向绑定

    双向绑定绑定相同类型的属性,并同步两侧的值。当使用bindBidirectional()方法双向绑定时,需要两个属性都必须是可读/写的。
    以下代码显示如何在firstName属性和字符串属性变量之间进行双向绑定 ```java import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty;

public class Main { public static void main(String[] args) { User contact = new User(“Jame”, “Bind”); StringProperty fname = new SimpleStringProperty(); fname.bindBidirectional(contact.firstNameProperty());

  1. contact.firstNameProperty().set("new value");
  2. fname.set("新绑定名称值");
  3. System.out.println("firstNameProperty = " + contact.firstNameProperty().get());
  4. System.out.println("fname = " + fname.get());
  5. }

}

class User {

  1. private SimpleStringProperty firstName = new SimpleStringProperty();
  2. private SimpleStringProperty lastName = new SimpleStringProperty();
  3. public User(String fn, String ln) {
  4. firstName.setValue(fn);
  5. lastName.setValue(ln);
  6. }
  7. public final String getFirstName() {
  8. return firstName.getValue();
  9. }
  10. public StringProperty firstNameProperty() {
  11. return firstName;
  12. }
  13. public final void setFirstName(String firstName) {
  14. this.firstName.setValue(firstName);
  15. }
  16. public final String getLastName() {
  17. return lastName.getValue();
  18. }
  19. public StringProperty lastNameProperty() {
  20. return lastName;
  21. }
  22. public final void setLastName(String lastName) {
  23. this.lastName.setValue(lastName);
  24. }

}

  1. <a name="O7uov"></a>
  2. ## 高级别绑定
  3. 我们也可以使用JavaFX流利的API来绑定属性。**API**使用类似英语的方法名称对属性执行操作。 例如,multiply(),divide(),subtract(),isEqualTo(),isNotEqualTo(),concat()。 请注意,方法名称中没有get或set。当链接**API**在一起时可以写代码,就像类似于写英文句子,例如,width().multiply(height()).divide(2)。<br />以下代码显示如何创建表示计算矩形面积的公式的属性。<br />它通过使用javafx.beans.binding.IntegerExpression接口中的**fluent API**来执行高级绑定。<br />该代码使用multiply()方法,该方法返回包含计算值 - NumberBinding。<br />这个绑定是延迟评估求值的,这意味着乘法不会执行计算,除非通过get()或getValue()方法调用属性的值。
  4. ```java
  5. import javafx.beans.binding.NumberBinding;
  6. import javafx.beans.property.IntegerProperty;
  7. import javafx.beans.property.SimpleIntegerProperty;
  8. public class Main {
  9. public static void main(String[] args) {
  10. // Area = width * height
  11. IntegerProperty width = new SimpleIntegerProperty(10);
  12. IntegerProperty height = new SimpleIntegerProperty(10);
  13. NumberBinding area = width.multiply(height);
  14. System.out.println(area.getValue());
  15. }
  16. }

低级别绑定

当对NumberBinding类进行子类化时,使用低级别绑定,例如Double类型的DoubleBinding类。
在DoubleBinding类的子类中,我们覆盖它的computeValue()方法,以便可以使用运算符(例如和 - )来制定复杂的数学方程计算。
高级绑定使用如multiply(),subtract()等方法,而低级绑定使用诸如
和 - 等运算符。
以下代码显示如何为公式创建低级别绑定,来计算矩形的面积。

  1. import javafx.beans.binding.DoubleBinding;
  2. import javafx.beans.property.DoubleProperty;
  3. import javafx.beans.property.SimpleDoubleProperty;
  4. public class Main {
  5. public static void main(String[] args) {
  6. DoubleProperty width = new SimpleDoubleProperty(2);
  7. DoubleProperty height = new SimpleDoubleProperty(2);
  8. DoubleBinding area = new DoubleBinding() {
  9. {
  10. super.bind(width, height); // initial bind
  11. }
  12. @Override
  13. protected double computeValue() {
  14. return width.get() * height.get();
  15. }
  16. };
  17. System.out.println(area.get());
  18. }
  19. }

UI控件和域模型之间的绑定

在JavaFX中,UI控件和域模型之间的数据绑定很容易。以下代码显示如何创建登录对话框并绑定用户域对象。
首先,我们定义域对象,它是描述用户名和密码的JavaFX JavaBean

  1. class User {
  2. private final ReadOnlyStringWrapper userName;
  3. private StringProperty password;
  4. public User() {
  5. userName = new ReadOnlyStringWrapper(this, "userName", "ABC");
  6. password = new SimpleStringProperty(this, "password", "");
  7. }
  8. public final String getUserName() {
  9. return userName.get();
  10. }
  11. public ReadOnlyStringProperty userNameProperty() {
  12. return userName.getReadOnlyProperty();
  13. }
  14. public final String getPassword() {
  15. return password.get();
  16. }
  17. public StringProperty passwordProperty() {
  18. return password;
  19. }
  20. }

我们创建了两个UI控件,一个用于使用Text控件显示用户名,另一个是 PasswordField 字段控件,它将输入值绑定到域对象(User)中的 password 字段。

  1. Text userName = new Text();
  2. userName.textProperty().bind(user.userNameProperty());
  3. PasswordField passwordField = new PasswordField();
  4. passwordField.setPromptText("Password");
  5. user.passwordProperty().bind(passwordField.textProperty());

在更改侦听器中为passwordField字段文本值属性设置BooleanProperty访问权限。

  1. passwordField.textProperty().addListener((obs, ov, nv) -> {
  2. boolean granted = passwordField.getText().equals(MY_PASS);
  3. accessGranted.set(granted);
  4. if (granted) {
  5. primaryStage.setTitle("");
  6. }
  7. });

enter键点击事件中访问BooleanProperty accessGranted。

  1. // user hits the enter key
  2. passwordField.setOnAction(actionEvent -> {
  3. if (accessGranted.get()) {
  4. System.out.println("granted access:"+ user.getUserName());
  5. System.out.println("password:"+ user.getPassword());
  6. Platform.exit();
  7. } else {
  8. primaryStage.setTitle("no access");
  9. }
  10. });

完整的源代码如下所示。

  1. import javafx.application.Application;
  2. import javafx.application.Platform;
  3. import javafx.beans.property.BooleanProperty;
  4. import javafx.beans.property.ReadOnlyStringProperty;
  5. import javafx.beans.property.ReadOnlyStringWrapper;
  6. import javafx.beans.property.SimpleBooleanProperty;
  7. import javafx.beans.property.SimpleStringProperty;
  8. import javafx.beans.property.StringProperty;
  9. import javafx.scene.Group;
  10. import javafx.scene.Scene;
  11. import javafx.scene.control.PasswordField;
  12. import javafx.scene.layout.VBox;
  13. import javafx.scene.text.Text;
  14. import javafx.stage.Stage;
  15. public class Main extends Application {
  16. private final static String MY_PASS = "passwd";// 初始密码
  17. private final static BooleanProperty accessGranted = new SimpleBooleanProperty(false);
  18. @Override
  19. public void start(Stage primaryStage) {
  20. User user = new User();
  21. Group root = new Group();
  22. Scene scene = new Scene(root, 320, 100);
  23. primaryStage.setScene(scene);
  24. Text userName = new Text();
  25. userName.textProperty().bind(user.userNameProperty());
  26. PasswordField passwordField = new PasswordField();
  27. passwordField.setPromptText("Password");
  28. user.passwordProperty().bind(passwordField.textProperty());
  29. // user hits the enter key
  30. passwordField.setOnAction(actionEvent -> {
  31. if (accessGranted.get()) {
  32. System.out.println("granted access:" + user.getUserName());
  33. System.out.println("password:" + user.getPassword());
  34. Platform.exit();
  35. } else {// @ WW w .yIIB A i.c OM
  36. primaryStage.setTitle("no access");
  37. }
  38. });
  39. passwordField.textProperty().addListener((obs, ov, nv) -> {
  40. boolean granted = passwordField.getText().equals(MY_PASS);
  41. accessGranted.set(granted);
  42. if (granted) {
  43. primaryStage.setTitle("");
  44. }
  45. });
  46. VBox formLayout = new VBox(4);
  47. formLayout.getChildren().addAll(userName, passwordField);
  48. formLayout.setLayoutX(12);
  49. formLayout.setLayoutY(12);
  50. root.getChildren().addAll(formLayout);
  51. primaryStage.show();
  52. }
  53. public static void main(String[] args) {
  54. launch(args);
  55. }
  56. }
  57. class User {
  58. private final ReadOnlyStringWrapper userName;
  59. private StringProperty password;
  60. public User() {
  61. userName = new ReadOnlyStringWrapper(this, "userName", "ABC");
  62. password = new SimpleStringProperty(this, "password", "");
  63. }
  64. public final String getUserName() {
  65. return userName.get();
  66. }
  67. public ReadOnlyStringProperty userNameProperty() {
  68. return userName.getReadOnlyProperty();
  69. }
  70. public final String getPassword() {
  71. return password.get();
  72. }
  73. public StringProperty passwordProperty() {
  74. return password;
  75. }
  76. }