JavaFX綁定同步兩個值:當(dāng)因變量更改時,其他變量更改。
要將屬性綁定到另一個屬性,請調(diào)用bind()方法,該方法在一個方向綁定值。例如,當(dāng)屬性A綁定到屬性B時,屬性B的更改將更新屬性A,但不是相反。
JavaFX提供了許多綁定選項,以便在域?qū)ο蠛虶UI控件中的屬性之間進(jìn)行同步。
我們可以在JavaFX的屬性API中使用以下三種綁定策略:
javafx.beans.binding.*
中定義的綁定對象進(jìn)行低級綁定。
雙向綁定綁定相同類型的屬性,并同步兩側(cè)的a值。
當(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("New First Name"); 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); } }
上面的代碼生成以下結(jié)果。
我們還可以使用JavaFX fluent API來綁定屬性。流利的API使用類似英語的方法名稱對屬性執(zhí)行操作。
例如,multiply(),divide(),subtract(),isEqualTo(),isNotEqualTo(),concat()。請注意,方法名稱中沒有g(shù)et或set。當(dāng)鏈接流暢的API在一起,我們可以編寫代碼,如同我們正在寫句子,例如 width().multiply(height()).divide(2)
。
以下代碼顯示如何創(chuàng)建表示計算矩形面積的公式的屬性。
它通過使用 javafx.beans.binding.IntegerExpression
接口中的fluent API來執(zhí)行高級綁定。
該代碼使用 multiply()
方法,該方法返回包含計算值的NumberBinding。
這種綁定是延遲評估的,這意味著乘法不會發(fā)生,除非我們通過 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é)果。
當(dāng)對 NumberBinding
類進(jìn)行子類化時,我們使用低級綁定,例如Double類型的DoubleBinding類。
在DoubleBinding類的子類中,我們重寫其 computeValue()
方法,以便我們可以使用運算符(如*
和 -
)來制定復(fù)雜的數(shù)學(xué)方程。
高級綁定使用諸如multiply(),subtract()等方法低級綁定使用諸如*和 - 之類的運算符。
以下代碼顯示如何為公式創(chuàng)建低級別綁定以計算矩形的面積。
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é)果。
在JavaFX中,UI控件和域模型之間的數(shù)據(jù)綁定很容易。以下代碼顯示如何創(chuàng)建登錄對話框并綁定用戶域?qū)ο蟆?/p>
首先,我們定義域?qū)ο?,它是描述用戶名和密碼的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ū)ο笾械拿艽a字段。
Text userName = new Text(); userName.textProperty().bind(user.userNameProperty()); PasswordField passwordField = new PasswordField(); passwordField.setPromptText("Password"); user.passwordProperty().bind(passwordField.textProperty());
BooleanProperty accessGranted在passwordField的文本值屬性的更改偵聽器中設(shè)置。
passwordField.textProperty().addListener((obs, ov, nv) -> { boolean granted = passwordField.getText().equals(MY_PASS); accessGranted.set(granted); if (granted) { primaryStage.setTitle(""); } });
在enter鍵hit事件中訪問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; public class Main extends Application { private final static String MY_PASS = "asdf"; 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 { 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é)果。
更多建議: