盡管java開發者偶爾用“property”來指java 類中的attributes 。Javafx “properties ” 實際上遠遠不止“attributes” 。 JAVAfX定義了一個接口 javafx.beans.property.Property,它有一個非常有用的功能:綁定GUI組件(視圖層)到java類(MODULE)的“properties”中。當綁定建立后,如果module層的值發生改變,GUI自動會自動接到通知,反之亦然。
說明:綁定本質上就是建立一個雙向監聽。
假定我們正在發開一個金融軟件,它能從服務端接收股票價格化的通知。當java對象接收到新的價格后,我們需要更新對應的UI組件的內容。 但有了javafx之后, 我們可以綁定java類的價格“PROPERTY”到ui組件上(比如說是一個Label),如此便不再需要其他編碼工作了。 只要價格發生了變更。Label組件會自動更新。 JAVAFX “property” 極大的簡化了數據層和UI層數據同步的問題。
Property 接口當前實現所扮演的角色是對java “attributes”的包裹,並為其添加了改變通知功能。Property interface 里包含了bind(), unbind(), bindBidirectional() , unbindBidirctional(), and isBound()。 說明的是:只有Observable類型的對象才可以綁定到JAVAFX “property”上。
JavaFx property 相關的類位於javafx.beans.property包中。每一種Property類型都有兩個類。 read-only 和 read-write ones 。舉例來說:我們需要一個String property。 可以用 SimpleStringProperty 或者 ReadOnlyStringWrapper。他們兩個都實現了StringProperty 接口。其他數據類型和容器也是如此。
綁定是非直接的,當UI組件發生變化,它能夠更新地下module層的值(MVC).當module層的值發生變化,UI層也會被更新。如果想解除綁定,可以使用unbind()。方法
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package mybinding;
import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.event.ActionEvent; import javafx.event.Event; import javafx.event.EventHandler; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.geometry.VPos; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; import javafx.stage.Stage;
public class GridPaneSampleBinding extends Application {
//Declaring a JavaFX property private StringProperty message = new SimpleStringProperty();
public void start(Stage primaryStage) {
Label userIdLbl = new Label("User ID:"); TextField userIdTxt = new TextField(); Label userPwdLbl = new Label("Password:"); PasswordField userPwdTxt = new PasswordField(); Button signInBtn = new Button("Sign In"); Button cancelBtn = new Button("Cancel"); Hyperlink forgotPwdLink = new Hyperlink("Forgot password");
// A label to display messages using binding Label messageLbl = new Label(); // binding the StringProperty to a GUI component messageLbl.textProperty().bind(message);
GridPane root = new GridPane(); root.setVgap(20); root.setPadding(new Insets(10)); root.setAlignment(Pos.CENTER);
// Using static methods for setting node constraints GridPane.setConstraints(userIdLbl, 0, 0); GridPane.setConstraints(userIdTxt, 1, 0); GridPane.setConstraints(userPwdLbl, 0, 1); GridPane.setConstraints(userPwdTxt, 1, 1); GridPane.setConstraints(signInBtn, 0, 2);
//Cancel button: span 1, right aligned GridPane.setConstraints(cancelBtn, 1, 2, 1, 1, HPos.RIGHT, VPos.CENTER); GridPane.setConstraints(forgotPwdLink, 0, 3, 2, 1);
// Message label: span 2 GridPane.setConstraints(messageLbl, 0, 4, 2, 1);
root.getChildren().addAll(userIdLbl, userIdTxt, userPwdLbl, userPwdTxt, signInBtn, cancelBtn, forgotPwdLink, messageLbl);
// event handlers //1. Anonymous class signInBtn.setOnAction(new EventHandler() {
@Override public void handle(Event event) { message.set("Sign in clicked."); } });
// lambda expression cancelBtn.setOnAction(evt -> message.set("Cancel clicked.") );
// method reference forgotPwdLink.setOnAction(this::forgotPwdHandler);
// Show the window Scene scene = new Scene(root, 250, 220); primaryStage.setScene(scene); primaryStage.show(); }
private void forgotPwdHandler(ActionEvent evt) { message.set("Forgot password clicked"); }
public static void main(String[] args) { launch(args); } }
|