JavaFX 綁定

2018-03-04 14:34 更新

JavaFX教程 - JavaFX綁定


JavaFX綁定同步兩個值:當(dāng)因變量更改時,其他變量更改。

要將屬性綁定到另一個屬性,請調(diào)用bind()方法,該方法在一個方向綁定值。例如,當(dāng)屬性A綁定到屬性B時,屬性B的更改將更新屬性A,但不是相反。

綁定選項

JavaFX提供了許多綁定選項,以便在域?qū)ο蠛虶UI控件中的屬性之間進(jìn)行同步。

我們可以在JavaFX的屬性API中使用以下三種綁定策略:

  • Java Bean上的雙向綁定
  • 與Fluent 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é)果。

UI控件和域模型之間的綁定

在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é)果。

null
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號