JavaFX綁定同步兩個值:當(dāng)依賴變量更改時,其他變量更改。
要將屬性綁定到另一個屬性,請調(diào)用bind()方法,該方法在一個方向綁定值。 例如,當(dāng)屬性A綁定到屬性B時,屬性B的更改將更新屬性A,但不可以反過來。
JavaFX提供了許多綁定選項(xiàng),以便在域?qū)ο蠛虶UI控件中的屬性之間進(jìn)行同步。
我們可以在JavaFX的Properties API中使用以下三種綁定策略:
javafx.beans.binding
定義綁定對象進(jìn)行低級綁定。雙向綁定綁定相同類型的屬性,并同步兩側(cè)的值。當(dāng)使用bindBidirectional()
方法雙向綁定時,需要兩個屬性都必須是可讀/寫的。
以下代碼顯示如何在firstName
屬性和字符串屬性變量之間進(jìn)行雙向綁定
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());
}// @ W WW .yI iB AI.c o M
}
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);
}
}
上面的代碼生成以下結(jié)果。
firstNameProperty = 新綁定名稱值
fname = 新綁定名稱值
我們也可以使用JavaFX流利的API來綁定屬性。API使用類似英語的方法名稱對屬性執(zhí)行操作。 例如,multiply()
,divide()
,subtract()
,isEqualTo()
,isNotEqualTo()
,concat()
。 請注意,方法名稱中沒有get
或set
。當(dāng)鏈接API在一起時可以寫代碼,就像類似于寫英文句子,例如,width().multiply(height()).divide(2)
。
以下代碼顯示如何創(chuàng)建表示計(jì)算矩形面積的公式的屬性。
它通過使用javafx.beans.binding.IntegerExpression
接口中的fluent API來執(zhí)行高級綁定。
該代碼使用multiply()
方法,該方法返回包含計(jì)算值 - NumberBinding
。
這個綁定是延遲評估求值的,這意味著乘法不會執(zhí)行計(jì)算,除非通過get()
或getValue()
方法調(diào)用屬性的值。
import 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 * height
IntegerProperty width = new SimpleIntegerProperty(10);
IntegerProperty height = new SimpleIntegerProperty(10);
NumberBinding area = width.multiply(height);
System.out.println(area.getValue());
}
}
上面的代碼生成以下結(jié)果。
100
當(dāng)對NumberBinding
類進(jìn)行子類化時,使用低級別綁定,例如Double
類型的DoubleBinding
類。
在DoubleBinding
類的子類中,我們覆蓋它的computeValue()
方法,以便可以使用運(yùn)算符(例如*
和 -
)來制定復(fù)雜的數(shù)學(xué)方程計(jì)算。
高級綁定使用如multiply()
,subtract()
等方法,而低級綁定使用諸如*
和 -
等運(yùn)算符。
以下代碼顯示如何為公式創(chuàng)建低級別綁定,來計(jì)算矩形的面積。
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
}
@Override
protected double computeValue() {
return width.get() * height.get();
}
};
System.out.println(area.get());
}
}
上面的代碼生成以下結(jié)果。
4.0
在JavaFX中,UI控件和域模型之間的數(shù)據(jù)綁定很容易。以下代碼顯示如何創(chuàng)建登錄對話框并綁定用戶域?qū)ο蟆?br>首先,我們定義域?qū)ο螅敲枋鲇脩裘兔艽a的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;
}
}
我們創(chuàng)建了兩個UI控件,一個用于使用Text
控件顯示用戶名,另一個是 PasswordField
字段控件,它將輸入值綁定到域?qū)ο?User
)中的 password
字段。
Text userName = new Text();
userName.textProperty().bind(user.userNameProperty());
PasswordField passwordField = new PasswordField();
passwordField.setPromptText("Password");
user.passwordProperty().bind(passwordField.textProperty());
在更改偵聽器中為passwordField
字段文本值屬性設(shè)置BooleanProperty
訪問權(quán)限。
passwordField.textProperty().addListener((obs, ov, nv) -> {
boolean granted = passwordField.getText().equals(MY_PASS);
accessGranted.set(granted);
if (granted) {
primaryStage.setTitle("");
}
});
在enter鍵點(diǎn)擊事件中訪問BooleanProperty accessGranted
。
// user hits the enter key
passwordField.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;
// @ w Ww .yi iB A i. C o M
public class Main extends Application {
private final static String MY_PASS = "passwd";// 初始密碼
private final static BooleanProperty accessGranted = new SimpleBooleanProperty(false);
@Override
public 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 key
passwordField.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 OM
primaryStage.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;
}
}
上面的代碼生成以下結(jié)果。
在上面的輸入框中輸入密碼:passwd
完成后,得到以下輸出結(jié)果 -
granted access:ABC
password:passwd