2013-09-04 16 views
6

Ho una ListView piena di POJO e voglio un'etichetta nella GUI per visualizzare le informazioni dall'elemento selezionato.Come associare un'etichetta JavaFX all'elemento selezionato da un ListView

mio POJO sembra qualcosa di simile:

class Customer { 
    private String name; 
    ... 
    public String getName() { 
    return name; 
    } 

Ora, quando l'utente seleziona un cliente dalla lista Voglio il nome del cliente selezionato visualizzato in un'etichetta.

Ovviamente non posso eseguire il binding allo name direttamente perché non è un Property. (E io non voglio sostituire i miei clienti String s con StringProperty -Oggetti perché il SimpleStringProperty non è serializable e ho bisogno del Customer da trasferire tramite RMI.)

Ho provato il BeanPathAdapter da JFXtras (che sembra davvero bello tra l'altro) in questo modo:

BeanPathAdapter<MultipleSelectionModel> customerBeanPathAdapter; 
    customerBeanPathAdapter = new BeanPathAdapter<>(lstCustomers.getSelectionModel()); 
    customerBeanPathAdapter.bindBidirectional("selectedItem.name", lblCustomerName.textProperty()); 

Ma questa soluzione mi butta solo un'eccezione:

... 
Caused by: java.lang.IllegalArgumentException: Unable to resolve accessor getSelectedItem 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.buildAccessor(BeanPathAdapter.java:3062) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.buildAccessorWithLikelyPrefixes(BeanPathAdapter.java:3022) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.updateMethodHandles(BeanPathAdapter.java:2986) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.<init>(BeanPathAdapter.java:2977) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldBean.performOperation(BeanPathAdapter.java:1348) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldBean.performOperation(BeanPathAdapter.java:1186) 
at jfxtras.labs.scene.control.BeanPathAdapter.bindBidirectional(BeanPathAdapter.java:567) 
at jfxtras.labs.scene.control.BeanPathAdapter.bindBidirectional(BeanPathAdapter.java:369) 
at at.gs1.sync.qm.client.gui.MainWindowController.initialize(MainWindowController.java:61) 
... 22 more 
Caused by: java.lang.IllegalAccessException: symbolic reference class is not public: class javafx.scene.control.ListView$ListViewBitSetSelectionModel, from jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle 
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:512) 
at java.lang.invoke.MethodHandles$Lookup.checkSymbolicClass(MethodHandles.java:1113) 
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1094) 
at java.lang.invoke.MethodHandles$Lookup.findVirtual(MethodHandles.java:626) 
at jfxtras.labs.scene.control.BeanPathAdapter$FieldHandle.buildAccessor(BeanPathAdapter.java:3049) 
... 30 more 

Quindi speravo che ci sarebbe stata una soluzione migliore che usare lstCustomers.getSelectionModel().selectedItemProperty().addListener(...) e gestire manualmente la popolazione delle etichette.

+0

Parte del problema è l'accesso implementazione limitato (sembra la l'adattatore non può gestirlo). Un altro potrebbe essere un errore o un'aspettativa non valida (anche la mia :-) - l'aggiornamento del valore sembra avvenire solo nella direzione dalla proprietà legata alla proprietà adattata (cioè il percorso), non viceversa. Almeno non riusciva a farlo funzionare con i bean più semplici, nessuno dei quali con proprietà fx, né una proprietà java bean core semplice. – kleopatra

risposta

2

Una soluzione migliore, a mio avviso, è quella di utilizzare BeanPathAdapter come si è tentato.
Tuttavia il BeanPathAdapter ha bisogno di avere la seguente proprietà aggiunto ad esso:

private final ObjectProperty<B> beanProp = new SimpleObjectProperty<>(); 
{ 
    beanProp.addListener(new ChangeListener<B>() 
    { 
     @Override 
     public void changed(ObservableValue<? extends B> ob, B oldVal, B newVal) 
     { 
      setBean(newVal); 
     } 
    }); 
} 

public ObjectProperty<B> beanProperty() 
{ 
    return beanProp; 
} 

Poi nel codice sono necessari i seguenti:

BeanPathAdapter<Customer> custBean; 
custBean = new BeanPathAdapter<>(new Customer()); // empty or any customer 
custBean.bindBidirectional("name", label.textProperty()); 
custBean.beanProperty().bind(listview.getSelectionModel().selectedItemProperty()); 
+0

Sembra molto promettente. Ci proverò oggi. Grazie! (mi dispiace per la risposta tardiva!) –

+0

Funziona come un fascino! Grazie!! –

1

Non penso che ci sia un rivestimento semplice che stai cercando.
Si potrebbe fare la seguente:

label.textProperty().bind(Bindings.selectString(listview.getSelectionModel().selectedItemProperty(), "name")); 

ma sarà necessario modificare il tuo POJO clienti in questo modo:

class Customer 
{ 
    private String name; 
    ... 
    public String getName() { return name; } 

    public ReadOnlyStringProperty nameProperty() 
    { 
     return new SimpleStringProperty(name); 
    } 
} 

Io non credo che questo è consigliato, però, perché le proprietà sono attesi per riflettere i cambiamenti nei dati sottostanti e sopra riportato rifletterà solo il nome com'era quando viene chiamato nameProperty. Quindi, se viene chiamato setName, la proprietà non rifletterà la modifica. Se il nome del cliente non cambia mai, puoi farla franca.

Problemi correlati