我有一个JavaFX ListView。当我点击列表中的某个项目时,我想要两个...编辑控件,一个ComboBox和一个TextField,由模型中的相应值填充。
首先,我的模特:
public class Recipient {
private final SimpleStringProperty type = new SimpleStringProperty();
private final SimpleStringProperty address = new SimpleStringProperty();
// property getters
}
在我的控制器中,我有:
public class Controller implements Initializable {
@FXML
private ComboBox type;
@FXML
private TextField address;
@FXML
private ListView<Recipient> recipList;
private final ObservableList<String> types = FXCollections.observableArrayList("SMS", "Email");
private final ObservableList<Recipient> recips = FXCollections.observableArrayList(Recipient.DUMMYDATA);
private final ObjectProperty<Recipient> recipient = new SimpleObjectProperty<>();
@Override
public void initialize(URL url, ResourceBundle rb) {
type.setItems(types);
recipList.setItems(recips);
recipList.setCellFactory((ListView<Recipient> p) -> new ListCell<Recipient>() {
@Override
public void updateItem(Recipient recip, boolean empty) {
super.updateItem(recip, empty);
final int index = p.getItems().indexOf(recip);
if (index > -1) {
setText(String.format("%s - %s", recip.typeProperty().get(), recip.addressProperty().get()));
} else {
setText(null);
}
}
});
recipient.setValue(new Recipient());
recipList.setOnMouseClicked(event -> recipClicked(event));
type.valueProperty().bindBidirectional(recipient.get().typeProperty());
address.textProperty().bindBidirectional(recipient.get().addressProperty());
}
public void recipClicked(MouseEvent event) {
final MultipleSelectionModel<Recipient> get = recipList.selectionModelProperty().get();
final Recipient selectedItem = get.getSelectedItem();
recipient.setValue(selectedItem);
}
}
当我单击列表时,SimpleObjectProperty会按预期更新,但我的控件现在会显示数据。我错过了什么?
答案 0 :(得分:1)
绑定绑定在绑定时绑定到属于当前收件人的属性。如果recipient
的值发生变化,那么,例如address.textProperty
仍会绑定到addressProperty()
之前值的recipient
,而不是新值。
您可以使用收件人上的侦听器绑定和取消绑定控件:
recipient.addListener((obs, oldRecipient, newRecipient) -> {
if (oldRecipient != null) {
type.valueProperty().unbindBidirectional(oldRecipient.typeProperty());
address.textProperty().unbindBidirectional(oldRecipient.addressProperty());
}
if (newRecipient != null) {
type.valueProperty().bindBidirectional(newRecipient.typeProperty());
address.textProperty().bindBidirectional(newRecipient.addressProperty());
}
});
另外,请注意,不应使用鼠标侦听器来响应选择中的更改:例如,如果用户使用键盘更改列表视图中的选择,则不起作用。您可以将recipList.setOnMouseClicked(...)
替换为
recipient.bind(recipList.getSelectionModel().selectedItemProperty());
并完全删除recipClicked(...)
。 (事实上,您可能根本不需要recipient
:您可以将其替换为recipList.getSelectionModel().selectedItemProperty()
。)
public class Controller implements Initializable {
@FXML
private ComboBox type;
@FXML
private TextField address;
@FXML
private ListView<Recipient> recipList;
private final ObservableList<String> types = FXCollections.observableArrayList("SMS", "Email");
private final ObservableList<Recipient> recips = FXCollections.observableArrayList(Recipient.DUMMYDATA);
@Override
public void initialize(URL url, ResourceBundle rb) {
type.setItems(types);
recipList.setItems(recips);
recipList.setCellFactory((ListView<Recipient> p) -> new ListCell<Recipient>() {
@Override
public void updateItem(Recipient recip, boolean empty) {
super.updateItem(recip, empty);
if (empty) {
setText(null);
} else {
setText(String.format("%s - %s", recip.typeProperty().get(), recip.addressProperty().get()));
}
}
});
recipList.getSelectionModel().selectedItemProperty().addListener((obs, oldRecipient, newRecipient) -> {
if (oldRecipient != null) {
type.valueProperty().unbindBidirectional(oldRecipient.typeProperty());
address.textProperty().unbindBidirectional(oldRecipient.addressProperty());
}
if (newRecipient != null) {
type.valueProperty().bindBidirectional(newRecipient.typeProperty());
address.textProperty().bindBidirectional(newRecipient.addressProperty());
}
});
}
}