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());
contact.firstNameProperty().set("new value");fname.set("新绑定名称值");System.out.println("firstNameProperty = " + contact.firstNameProperty().get());System.out.println("fname = " + fname.get());}
}
class User {
private SimpleStringProperty firstName = new SimpleStringProperty();private SimpleStringProperty lastName = new SimpleStringProperty();public User(String fn, String ln) {firstName.setValue(fn);lastName.setValue(ln);}public final String getFirstName() {return firstName.getValue();}public StringProperty firstNameProperty() {return firstName;}public final void setFirstName(String firstName) {this.firstName.setValue(firstName);}public final String getLastName() {return lastName.getValue();}public StringProperty lastNameProperty() {return lastName;}public final void setLastName(String lastName) {this.lastName.setValue(lastName);}
}
<a name="O7uov"></a>## 高级别绑定我们也可以使用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()方法调用属性的值。```javaimport javafx.beans.binding.NumberBinding;import javafx.beans.property.IntegerProperty;import javafx.beans.property.SimpleIntegerProperty;public class Main {public static void main(String[] args) {// Area = width * heightIntegerProperty width = new SimpleIntegerProperty(10);IntegerProperty height = new SimpleIntegerProperty(10);NumberBinding area = width.multiply(height);System.out.println(area.getValue());}}
低级别绑定
当对NumberBinding类进行子类化时,使用低级别绑定,例如Double类型的DoubleBinding类。
在DoubleBinding类的子类中,我们覆盖它的computeValue()方法,以便可以使用运算符(例如和 - )来制定复杂的数学方程计算。
高级绑定使用如multiply(),subtract()等方法,而低级绑定使用诸如和 - 等运算符。
以下代码显示如何为公式创建低级别绑定,来计算矩形的面积。
import javafx.beans.binding.DoubleBinding;import javafx.beans.property.DoubleProperty;import javafx.beans.property.SimpleDoubleProperty;public class Main {public static void main(String[] args) {DoubleProperty width = new SimpleDoubleProperty(2);DoubleProperty height = new SimpleDoubleProperty(2);DoubleBinding area = new DoubleBinding() {{super.bind(width, height); // initial bind}@Overrideprotected double computeValue() {return width.get() * height.get();}};System.out.println(area.get());}}
UI控件和域模型之间的绑定
在JavaFX中,UI控件和域模型之间的数据绑定很容易。以下代码显示如何创建登录对话框并绑定用户域对象。
首先,我们定义域对象,它是描述用户名和密码的JavaFX JavaBean。
class User {private final ReadOnlyStringWrapper userName;private StringProperty password;public User() {userName = new ReadOnlyStringWrapper(this, "userName", "ABC");password = new SimpleStringProperty(this, "password", "");}public final String getUserName() {return userName.get();}public ReadOnlyStringProperty userNameProperty() {return userName.getReadOnlyProperty();}public final String getPassword() {return password.get();}public StringProperty passwordProperty() {return password;}}
我们创建了两个UI控件,一个用于使用Text控件显示用户名,另一个是 PasswordField 字段控件,它将输入值绑定到域对象(User)中的 password 字段。
Text userName = new Text();userName.textProperty().bind(user.userNameProperty());PasswordField passwordField = new PasswordField();passwordField.setPromptText("Password");user.passwordProperty().bind(passwordField.textProperty());
在更改侦听器中为passwordField字段文本值属性设置BooleanProperty访问权限。
passwordField.textProperty().addListener((obs, ov, nv) -> {boolean granted = passwordField.getText().equals(MY_PASS);accessGranted.set(granted);if (granted) {primaryStage.setTitle("");}});
在enter键点击事件中访问BooleanProperty accessGranted。
// user hits the enter keypasswordField.setOnAction(actionEvent -> {if (accessGranted.get()) {System.out.println("granted access:"+ user.getUserName());System.out.println("password:"+ user.getPassword());Platform.exit();} else {primaryStage.setTitle("no access");}});
完整的源代码如下所示。
import javafx.application.Application;import javafx.application.Platform;import javafx.beans.property.BooleanProperty;import javafx.beans.property.ReadOnlyStringProperty;import javafx.beans.property.ReadOnlyStringWrapper;import javafx.beans.property.SimpleBooleanProperty;import javafx.beans.property.SimpleStringProperty;import javafx.beans.property.StringProperty;import javafx.scene.Group;import javafx.scene.Scene;import javafx.scene.control.PasswordField;import javafx.scene.layout.VBox;import javafx.scene.text.Text;import javafx.stage.Stage;public class Main extends Application {private final static String MY_PASS = "passwd";// 初始密码private final static BooleanProperty accessGranted = new SimpleBooleanProperty(false);@Overridepublic void start(Stage primaryStage) {User user = new User();Group root = new Group();Scene scene = new Scene(root, 320, 100);primaryStage.setScene(scene);Text userName = new Text();userName.textProperty().bind(user.userNameProperty());PasswordField passwordField = new PasswordField();passwordField.setPromptText("Password");user.passwordProperty().bind(passwordField.textProperty());// user hits the enter keypasswordField.setOnAction(actionEvent -> {if (accessGranted.get()) {System.out.println("granted access:" + user.getUserName());System.out.println("password:" + user.getPassword());Platform.exit();} else {// @ WW w .yIIB A i.c OMprimaryStage.setTitle("no access");}});passwordField.textProperty().addListener((obs, ov, nv) -> {boolean granted = passwordField.getText().equals(MY_PASS);accessGranted.set(granted);if (granted) {primaryStage.setTitle("");}});VBox formLayout = new VBox(4);formLayout.getChildren().addAll(userName, passwordField);formLayout.setLayoutX(12);formLayout.setLayoutY(12);root.getChildren().addAll(formLayout);primaryStage.show();}public static void main(String[] args) {launch(args);}}class User {private final ReadOnlyStringWrapper userName;private StringProperty password;public User() {userName = new ReadOnlyStringWrapper(this, "userName", "ABC");password = new SimpleStringProperty(this, "password", "");}public final String getUserName() {return userName.get();}public ReadOnlyStringProperty userNameProperty() {return userName.getReadOnlyProperty();}public final String getPassword() {return password.get();}public StringProperty passwordProperty() {return password;}}
