2016-11-08 4 views
0

Da dies eine Frage zum Design ist, werde ich damit beginnen zu sagen, was ich habe und was ich will.Sind Eigenschaften von Eigenschaften sinnvoll?

Ich habe ein Design, das Zusammensetzung verwendet. Ein Cell Objekt enthält eine Shape und eine Background Objekte (benutzerdefinierte für dieses Beispiel). Jede dieser 2 hat ihre eigenen Daten, die sie definieren. hier ist das Beispiel in Code:

class Cell { 

    Shape shape; 
    Background background; 

    class Shape { 

     int size; 
     Color color; 
     Point location; 
     //... 
    } 

    class Background { 

     Color color; 
     String name; 
     CoverType type; 
     //... 
    } 
} 

ich auch eine GUI, die viele Zellen und ich habe geschrieben, wie man es tun (wie benutzt man Farbe, Größe usw. erstellen, was ich will auf dem Bildschirm darstellen muss). Es enthält Klassen wie CellRepresentation, ShapeRepresentation und BackgroundRepresentation, deren Anzeigeeigenschaften an die Dateneigenschaften gebunden sind (ich denke, das nennt man Model and View).

Ich möchte der Lage sein, Änderungen in der GUI zu repräsentieren, indem die oben genannten Daten zu ändern:

  • kann ein Benutzer (zum Beispiel) auf einer Form der rechten Maustaste und seine Farbe gesetzt. Daher ändern sich die obigen Daten und die Änderung muss in der GUI widergespiegelt werden.
  • ein Benutzer kann auch die gesamte Form ändern (z. B. Kopieren-Einfügen aus einer anderen Zelle). Oder sogar die ganze Zelle. Diese Änderungen müssen sich auch in der GUI widerspiegeln.

Meine Frage ist, welche der Klassenmitglieder JavaFX Eigenschaften sein müssen, die ich zu binden.

Hier ist was ich denke: die "Blatt" Eigenschaften (Größe, Farbe, Ort ...) müssen Eigenschaften sein, damit ich die GUI-Eigenschaft an sie binden kann. Muss ich aber auch die Eigenschaften der Form und der Hintergrundobjekte festlegen? Nur ihre Eigenschaften haben eine "tatsächliche" Darstellung auf dem Bildschirm. Im Idealfall hätte es mir gefallen, wenn Shape sich ändert, dann sagen alle seine Eigenschaften ihren Bindings, dass sie sich geändert haben könnten (vielleicht hat die Farbe nicht, aber Größe getan). Aber es funktioniert nicht auf diese Weise - , obwohl die Farbe einer Form ändern kann, wenn die Form ändert die Farbe Eigenschaft wird nicht sagen, was auch immer daran gebunden ist, dass es geändert.

Das gleiche gilt für Cell eine Eigenschaft im Lagerbild, wo es viele Zellen gibt und so weiter: Eigenschaften von Eigenschaften, die Änderungen delegieren.

Also dachte ich mir, machen die Shape und Hintergrund auch Eigenschaften und Registrierung eines InvalidationListener zu ihnen aktualisiert ihre Eigenschaften. Das scheint einfach nicht richtig zu sein, denn ich würde meinen, dass es mit all der Unterstützung für Immobilien eine Möglichkeit geben würde zu tun, was ich will.

Kann jemand einen Weg vorschlagen, dies zu tun?

+0

Sie sollten über Vererbung lesen. – zyexal

+1

@zyexal ich weiß über Vererbung, Java ist nicht neu für mich. Wie ist das zusammen? – Mark

+1

Sie können sich die ['Bindings.selectXXX'] (http://docs.oracle.com/javase/8/javafx/api/javafx/beans/binding/Bindings.html#select-java) ansehen. lang.Object-java.lang.String ...-) Methoden, die Ihnen eine Möglichkeit geben, an "Eigenschaften von Eigenschaften" zu binden. Diese API hat etwas von einem "Legacy" -Gefühl, da sie weder typsicher noch kompilierfähig ist. Tomas Mikula hat eine [Bibliothek] (https://github.com/TomasMikula/ReactFX), die eine modernere Implementierung derselben Idee hat, siehe [this post] (http://tomasmikula.github.io/blog/2015) /02/10/val-a-better-observablevalue.html). –

Antwort

3

Mit der Standard-JavaFX-API können Sie die Methoden Bindings.selectXXX nutzen, um eine "Eigenschaft einer Eigenschaft" zu beobachten.

So zum Beispiel:

import javafx.beans.binding.Bindings; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.scene.paint.Color; 

public class Cell { 

    private final ObjectProperty<Shape> shape = new SimpleObjectProperty<>(new Shape()); 


    public final ObjectProperty<Shape> shapeProperty() { 
     return this.shape; 
    } 




    public final Cell.Shape getShape() { 
     return this.shapeProperty().get(); 
    } 




    public final void setShape(final Cell.Shape shape) { 
     this.shapeProperty().set(shape); 
    } 


    public static class Shape { 

     private final IntegerProperty size = new SimpleIntegerProperty(0); 
     private final ObjectProperty<Color> color = new SimpleObjectProperty<>(Color.BLACK); 
     public final IntegerProperty sizeProperty() { 
      return this.size; 
     } 

     public final int getSize() { 
      return this.sizeProperty().get(); 
     } 

     public final void setSize(final int size) { 
      this.sizeProperty().set(size); 
     } 

     public final ObjectProperty<Color> colorProperty() { 
      return this.color; 
     } 

     public final javafx.scene.paint.Color getColor() { 
      return this.colorProperty().get(); 
     } 

     public final void setColor(final javafx.scene.paint.Color color) { 
      this.colorProperty().set(color); 
     } 

    } 


    public static void main(String[] args) { 
     Cell cell = new Cell(); 
     Bindings.selectInteger(cell.shapeProperty(), "size").addListener(
       (obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize)); 
     cell.getShape().setSize(10); 
     cell.setShape(new Shape()); 
     Shape s = new Shape(); 
     s.setSize(20); 
     cell.setShape(s); 
    } 

} 

Wird die (gewünschte) -Ausgang

Size changed from 0 to 10 
Size changed from 10 to 0 
Size changed from 0 to 20 

produzieren Diese API ein bisschen ein Vermächtnis spüren ist, dass es die Eigenschaft beim Passieren Name beruht als String und folglich nicht typsicher und kann zur Kompilierzeit nicht überprüft werden. Wenn eine der Zwischeneigenschaften null ist (z. B. wenn in diesem Beispiel cel.getShape() null zurückgibt), generieren die Bindungen störende und ausführliche Warnmeldungen (obwohl dies ein unterstützter Anwendungsfall sein sollte).

Tomas Mikula hat eine modernere Implementierung in seiner ReactFX library, siehe this post für eine Beschreibung. Mit ReactFX, würden Sie tun:

public static void main(String[] args) { 
    Cell cell = new Cell(); 
    Var<Number> size = Val.selectVar(cell.shapeProperty(), Shape::sizeProperty); 
    size.addListener(
      (obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize)); 

    cell.getShape().setSize(10); 
    cell.setShape(new Shape()); 
    Shape s = new Shape(); 
    s.setSize(20); 
    cell.setShape(s); 
} 

Schließlich, wenn Sie eine Liste der Zellen erstellen, können Sie eine ObservableList eine extractor Angabe erstellen. Der Extraktor ist eine Funktion, die jedes Element in der Liste (jeweils Cell) auf ein Array von Observable s abbildet. Wenn sich eine dieser Observable s ändert, löst die Liste ein Update-Ereignis aus. So könnten Sie tun

ObservableList<Cell> cellList = 
    FXCollections.observableArrayList(cell -> new Observable[] {Bindings.selectInteger(cell.shapeProperty(), "size")}); 

die Standard-API oder

ObservableList<Cell> cellList = 
    FXCollections.observableArrayList(cell -> new Observable[] {Val.selectVar(cell.shapeProperty(), Shape::sizeProperty)}); 

mit ReactFX. Fügen Sie dann einfach einen ListChangeListener der Liste hinzu, und es wird benachrichtigt, wenn sich die Größe ändert (oder wenn sich die Form zu einer neuen Form mit einer anderen Größe ändert). Sie können beliebig viele Observables, die Eigenschaften (oder Eigenschaften von Eigenschaften) der Zelle im zurückgegebenen Array sind, hinzufügen.

+0

ReactFX scheint eine viel bessere Option zu sein. Auf keinen Fall werde ich String-Namen für meine Reflection-Stil-Eigenschaften verwenden - es ist rundherum problematisch. Vielen Dank! – Mark

+0

@Mark Ich habe das ReactFX-Tag zu Ihrer Frage hinzugefügt, falls jemand, der mehr darüber weiß, etwas hinzufügen wollte. –

+0

gute Idee! Danke – Mark

Verwandte Themen