无法将JavaFX TextField绑定到ListView值

时间:2017-06-18 01:56:50

标签: javafx

我有一个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会按预期更新,但我的控件现在会显示数据。我错过了什么?

1 个答案:

答案 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());
            }
        });
    }
}