绑定本质上就是建立一个双向监听。
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()。
/*
*GridPaneSampleBinding.java(测试例子)
* 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);
}
}
JavaFX可通过Property监听,做出自己的操作,在图形的Property监听中应用较多。
// Double监听
方式一(可知详细变化):
DoubleProperty doubleProperty = new SimpleDoubleProperty(初始化的double值);
doubleProperty.addListener(this::doublePropertyChange);
private void doublePropertyChange(ObservableValue<? extends Number> observable, Number oldValue, Number newValue){
double value = (double)newValue;
}
// 坑 最小值变化不触发改变的监听事件
doubleProperty.set(doubleProperty.get() + Double.MIN_VALUE);
方式二(可知详细变化):
doubleProperty.addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
//操作
}
});
可简化为
doubleProperty.addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
double value = (double)newValue;
});
方式三(可知变化了):
ReadOnlyDoubleWrapper doubleProperty = new ReadOnlyDoubleWrapper(初始化的double值);
doubleProperty.getReadOnlyProperty().addListener(o -> doSomething());
private void doSomething(){
}
图形的属性可绑定一个Property,在Property变化时,属性也跟着变化,可广泛应用于动画。
Button myButton = new Button();
myButton.setText("Test");
SimpleDoubleProperty simpleDoubleProperty = new SimpleDoubleProperty(100);
myButton.translateXProperty().bind(simpleDoubleProperty);
simpleDoubleProperty.set(0);
// 想通过setTranslateX方式改变translateX属性,必须解绑
myButton.unbind();
myButton.setTranslateX(50);
JavaFX重点案例
1、接口类
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application implements EventHandler{
Button button;
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("set the title");
button=new Button();
button.setText("Click me");
//button.setOnAction(this);
StackPane layout=new StackPane();
layout.getChildren().add(button);
Scene scene=new Scene(layout,300,300);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
/*@Override
public void handle(ActionEvent event) {
System.out.println("Wow ! I am clicked !");
}*/
}
2.anonymous 匿名类
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application{
Button button;
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("set the title");
button=new Button();
button.setText("Click me");
/*button.setOnAction(new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent event) {
System.out.println("Today is traditional lovers day in China !");
System.out.println("I am a single dog !");
}
});*/
StackPane layout=new StackPane();
layout.getChildren().add(button);
Scene scene=new Scene(layout,300,300);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
3.lambda表达式
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application{
Button button;
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("set the title");
button=new Button();
button.setText("Click me");
/*button.setOnAction(e -> {
System.out.println("I love u !");
System.out.println("Do u love me ?");
});*/
StackPane layout=new StackPane();
layout.getChildren().add(button);
Scene scene=new Scene(layout,300,300);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
友情链接:
code.makery——JavaFX 教程 (中文)
https://code.makery.ch/zh-cn/library/javafx-tutorial/