2013-06-11 12 views
5

Volevo ottenere qualcosa che assomiglia alla programmazione reattiva funzionale in JavaFX e ho pensato che dal momento che JavaFX supporta già listener e binding tra proprietà dovrebbe essere abbastanza facile, quindi ho creato una piccola struttura per i binding con conversione, ad es. Io ora sono in grado di fare qualcosa del genere (ad esempio a Scala, ma dovrebbe essere possibile capire cosa intendo):JavaFX force recompute binding

val property1: Property[String] 
val property2: Property[Path] 

Bindings.Conversions 
    .bindUni(property1).to(property2) 
    .using(p => p.getFileName.toString) 
    .connect() 

Qui mi legano valore property2 (che è un java.nio.file.Path) attraverso una funzione di conversione, che prende l'ultima parte del percorso e la converte in una stringa in property1 (che è una stringa).

L'attuazione di questo è molto semplice (anche per le associazioni bidirezionali; ho semplicemente preso un po 'di codice da openjfx BidirectionalBinding classe, tradotto alla Scala e adattato per le conversioni), e mi chiedo perché non v'è nulla di simile in JavaFX già .

Questo funziona tutto bene e riesco persino a creare catene complesse di tali associazioni. Tutto è OK a meno che la funzione di conversione non dipenda da qualche stato esterno.

Supponiamo, per esempio, che si ha la seguente catena di attacchi:

Text field value -1-> intermediate java.nio.file.Path -2-> another String --> Label 

Quando i cambiamenti del campo di testo, Path e String vengono ricalcolate automaticamente, e il valore della proprietà String viene scritto sull'etichetta. Tutto è meraviglioso. Ma supponiamo che -2-> conversione dovrebbe dipendere stato commutato di qualche casella:

         Checkbox state ---+ 
                  | 
Text field value -1-> intermediate java.nio.file.Path -2-> another String --> Label 

Cioè, quando casella è selezionata, trasformazione dovrebbe essere leggermente differente.

L'implementazione diretta di tale struttura non funzionerà, ovviamente, poiché la modifica dello stato della casella di controllo non attiva il ricalcolo della catena di trasformazione. Tuttavia, ho scoperto che JavaFX non fornisce alcun mezzo per forzare gli eventi di modifica. Ho provato a sovrascrivere SimpleStringProperty, ad esempio, esponendo il suo metodo fireValueChangedEvent(), ma questo non ha aiutato. Attualmente sto facendo qualcosa come textField.setText(""); textField.setText(oldValue); ma questo è molto brutto e non è la strada giusta, ovviamente.

Mi manca qualcosa, ed è davvero possibile fare ciò che voglio fare, o non c'è nulla del genere e sono completamente fottuto qui?

Se la risposta è no, allora penso che ciò danneggi gravemente l'espressività dell'intero framework. Capisco che posso davvero fare quello che voglio con un numero di ascoltatori, ma questo sarà brutto, e voglio rendere il tutto il più generale possibile.

risposta

1

È possibile ascoltare lo CheckBox#selectedProperty() nello stesso modo in cui si ascoltano le proprietà String. Vedere esempio successivo:

public class ConditionalBind extends Application { 

    Label label = new Label(); 
    TextField tf = new TextField("hi"); 
    CheckBox cb = new CheckBox("lowerize"); 

    @Override 
    public void start(Stage primaryStage) { 

     label.textProperty().bind(new StringBinding() { 

      { 
       bind(tf.textProperty(), cb.selectedProperty()); 
      } 

      @Override 
      protected String computeValue() { 
       return cb.isSelected() ? tf.getText().toLowerCase() : tf.getText(); 
      } 
     }); 

     VBox root = new VBox(10); 
     root.getChildren().addAll(label, cb, tf); 
     primaryStage.setScene(new Scene(root, 300, 250)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 
+0

Questo è qualcosa che ho scoperto anch'io, e ora sto usando l'approccio simile (tramite binding di basso livello). Tuttavia, questo approccio sembra non estendersi bene ai binding bidirezionali con la conversione. Questo non è un problema per il mio caso d'uso, ma comunque penso che * sia * un problema per il framework. Accetterò la tua risposta, poiché questo è essenzialmente ciò che sto usando ora. Grazie. –

+0

Il tuo caso è stato risolto. Per quanto riguarda il problema del framework, consiglierei di presentare un problema su javafx-jira.kenai.com e/o scrivere una mail a [email protected] - ti metterai in contatto direttamente con gli sviluppatori in questo modo. –

0

Come soluzione alternativa come "brutto" Ho finito casualmente cambiando i valori senza cambiare il significato. Per esempio. per un valore doppio, aggiungerei una piccola quantità casuale per forzare una modifica o per un valore stringa che selezionerei e lo spazio invisibile. Non è affatto bello, ma avrà l'effetto di innescare il cambiamento di proprietà per cominciare.

Le cose peggiorano in un ambiente con multithreading.In questo caso può accadere che la proprietà limitata non ottenga il trigger del cambiamento se l'associazione si verifica solo leggermente dopo l'impostazione iniziale della proprietà. Se ora si imposta la proprietà sullo stesso valore, il valore verrà considerato come non modificato e la proprietà associata non raccoglierà il valore iniziale ma rimarrà al valore null o predefinito. Molto brutto!