2014-05-07 17 views
16

Ich möchte JavaFX-Eigenschaften für die UI-Bindung verwenden, aber ich möchte sie nicht in meinen Modellklassen (siehe Using javafx.beans properties in model classes). Meine Modellklassen haben Getter und Setter, und ich möchte auf diesen basierende Eigenschaften erstellen. Zum Beispiel, eine Instanz bean mit Methoden String getName() und setName(String name) vorausgesetzt, würde ichJavaBean Wrapping mit JavaFX Eigenschaften

SimpleStringProperty property = new SimpleStringProperty(bean, "name") 

erwarten schreiben, dass property.set("Foobar") einen Aufruf an bean.setName auslösen würde. Aber das scheint nicht zu funktionieren. Was vermisse ich?

+0

ausgeben. Verwerfen Sie nicht die Idee, javafx-Eigenschaften in Ihren Modellklassen zu verwenden. Ich habe eine alternative Antwort auf die Frage hinzugefügt, die Sie verknüpft haben: Es könnte ein Ansatz sein, an den es sich zu denken lohnt. –

Antwort

36

Die Klassen Simple*Property sind vollständige eigenständige Implementierungen der entsprechenden abstrakten Klassen Property und verlassen sich nicht auf andere Objekte. So enthält beispielsweise SimpleStringProperty ein (privates) Feld String, das den aktuellen Wert der Eigenschaft enthält.

Die Parameter an den Konstruktor Sie zeigte:

new SimpleStringProperty(bean, "name") 

sind:

  • bean: die Bohne zu dem die Eigenschaft gehört, wenn jeder
  • name: der Name der Eigenschaft

Die bean kann in einer ChangeListener Methode changed(...) nützlich sein, da Sie die "besitzende Bohne" der Eigenschaft abrufen können, die sich von der Eigenschaft selbst geändert hat. Die name kann ähnlich verwendet werden (wenn Sie den gleichen Listener mit mehreren Eigenschaften registriert haben, können Sie herausfinden, welche Eigenschaft geändert wurde: obwohl ich dieses Muster nie verwende).

So eine typische Verwendung eines SimpleStringProperty als beobachtbare Eigenschaft eines Objekts wie folgt aussieht:

public class Person { 
    private final StringProperty firstName 
     = new SimpleStringProperty(this, "firstName"); 

    public final String getFirstName() { 
     return firstName.get(); 
    } 

    public final void setFirstName(String firstName) { 
     this.firstName.set(firstName); 
    } 

    public StringProperty firstNameProperty() { 
     return firstName ; 
    } 

    // ... other properties, etc 
} 

Die Funktionalität, die Sie suchen: eine vorhandene Java Bean Stil-Eigenschaft in einer JavaFX beobachtbare Eigenschaft wickeln implementiert nach Klassen im javafx.beans.property.adapter Paket. So zum Beispiel, könnten Sie tun

StringProperty nameProperty = new JavaBeanStringPropertyBuilder() 
     .bean(bean) 
     .name("name") 
     .build(); 

Aufruf

nameProperty.set("James"); 

mit diesem Setup wird effektiv um einen Anruf zu

bean.setName("James"); 

verursachen Wenn die Bohne PropertyChangeListener s unterstützt, wird die JavaBeanStringProperty registrieren a PropertyChangeListener mit der Bohne. Alle Änderungen an der name-Eigenschaft der Java-Bean werden durch die JavaBeanStringProperty in JavaFX-Eigenschaftenänderungen übersetzt. Folglich wird, wenn der zugrunde liegende JavaBean PropertyChangeListener s unterstützt, wechselt dann in den Bohnen über

bean.setName(...); 

in beliebigen ChangeListener s führt (oder InvalidationListener s) registriert mit den JavaBeanStringProperty über die Änderung informiert werden.

So zum Beispiel, wenn die Bean-Klasse ist

import java.beans.PropertyChangeListener; 
import java.beans.PropertyChangeSupport; 

public class Bean { 

    private String name ; 
    private final PropertyChangeSupport propertySupport ; 

    public Bean(String name) { 
     this.name = name ; 
     this.propertySupport = new PropertyChangeSupport(this); 
    } 

    public Bean() { 
     this(""); 
    } 

    public String getName() { 
     return name ; 
    } 

    public String setName(String name) { 
     String oldName = this.name ; 
     this.name = name ; 
     propertySupport.firePropertyChange("name", oldName, name); 
    } 

    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     propertySupport.addPropertyChangeListener(listener); 
    } 
} 

dann den folgenden Code:

Bean bean = new Bean(); 
StringProperty nameProperty() = new JavaBeanStringPropertyBuilder() 
     .bean(bean) 
     .name("name") 
     .build(); 
nameProperty().addListener((obs, oldName, newName) -> System.out.println("name changed from "+oldName+" to "+newName)); 
bean.setName("James"); 
System.out.println(nameProperty().get()); 

wird die Ausgabe produzieren:

name changed from to James 
James 

Wenn die JavaBean nicht der Fall ist Unterstützung PropertyChangeListener s, dann Änderungen an der Bohne über bean.setName(...) wird nicht aufpropagierens oder InvalidationListener s mit der JavaBeanStringProperty registriert. So

wenn die Bohne ist einfach

public class Bean { 

    public Bean() { 
     this(""); 
    } 

    public Bean(String name) { 
     this.name = name ; 
    } 

    private String name ; 

    public String getName() { 
     return name ; 
    } 

    public void setName(String name) { 
     this.name = name ; 
    } 
} 

Die JavaBeanStringProperty keine Möglichkeit haben würde, um die Änderung zu beobachten, so dass die Änderung Zuhörer würde nie durch einen Aufruf bean.setName() aufgerufen werden. Der obige Testcode würde einfach

James 
+0

+1 gute Erklärung. Der JavaBeanStringPropertyBuilder fügt die PropertyChangeListener-Unterstützung für die Bean hinzu. Aus der Antwort klingt es für mich so, als ob der Benutzer den Support selbst zur Bean hinzufügen sollte. –

+0

Nicht ganz: Die 'JavaBeanStringProperty' fügt der Bean keine 'PropertyChangeListener'-Unterstützung hinzu. Antwort aktualisiert, um zu klären. –

+0

Hätten Sie etwas dagegen, wenn ich Sie bitten würde, auch ein Beispiel für Java Bean mit und ohne PropertyChangeListener-Unterstützung zu zeigen? –