EventFilter for ComboBox选择了Item

时间:2017-03-27 13:44:51

标签: javafx combobox eventfilter

如何为ComboBox的SelectedItem属性编写EventFilter? This文章仅描述了像MouseEvent这样的用户事件,我似乎无法找出selectedItem属性发生变化的EventType。

我问,因为我在对话框中有一个3D应用程序,用于显示插槽上的材料。可以使用我的Combobox切换该插槽,但我希望能够在选择发生实际更改之前进行过滤,看看我是否有任何未保存的更改并显示用户想要保存更改或中止的对话框。由于我在组合框中有各种各样的监听器,当ComboBox中的选择发生变化时切换3D中的材料,因此不容易实现该对话框上的中止功能。

我也对“你想保存变化吗?”的其他方法持开放态度。实施可能更适合。

2 个答案:

答案 0 :(得分:2)

考虑创建另一个属性来表示组合框中的值,并且只有在用户确认时才更新它。然后你的应用程序的其余部分就可以观察到该属性。

所以,例如。

private ComboBox<MyData> combo = ... ;

private boolean needsConfirmation = true ;

private final ReadOnlyObjectWrapper<MyData> selectedValue = new ReadOnlyObjectWrapper<>();

public ReadOnlyObjectProperty<MyData> selectedValueProperty() {
    return selectedValue.getReadOnlyProperty() ;
}

public final MyData getSelectedValue() {
    return selectedValueProperty().get();
}

// ...

combo.valueProperty().addListener((obs, oldValue, newValue) -> {

    if (needsConfirmation) {
        // save changes dialog:
        Dialog<ButtonType> dialog = ... ;
        Optional<ButtonType> response = dialog.showAndWait();
        if (response.isPresent()) {
            if (response.get() == ButtonType.YES) {
                // save changes, then:
                selectedValue.set(newValue);
            } else if (response.get() == ButtonType.NO) {
                // make change without saving:
                selectedValue.set(newValue);
            } else if (response.get() == ButtonType.CANCEL) {
                // revert to old value, make sure we don't display dialog again:
                // Platform.runLater() is annoying workaround required to avoid
                // changing contents of list (combo's selected items) while list is processing change:
                Platform.runLater(() -> {
                    needsConfirmation = false ;
                    combo.setValue(oldValue);
                    needsConfirmation = true ;
                });
            }
        } else {
            needsConfirmation = false ;
            combo.setValue(oldValue);
            needsConfirmation = true ;
        }
    }
});

现在,您的应用程序可以观察selectedValueProperty()并在其发生变化时做出响应:

selectionController.selectedValueProperty().addListener((obs, oldValue, newValue) -> {
    // respond to change...
});

这是一个(非常简单的)SSCCE:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Dialog;
import javafx.scene.control.DialogPane;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class InterceptComboBox extends Application {

    private ComboBox<String> combo ;
    private boolean needsConfirmation = true ;
    private Label view ;
    private final ReadOnlyObjectWrapper<String> selectedValue = new ReadOnlyObjectWrapper<String>();

    public ReadOnlyObjectProperty<String> selectedValueProperty() {
        return selectedValue.getReadOnlyProperty();
    }

    public final String getSelectedValue() {
        return selectedValueProperty().get();
    }

    @Override
    public void start(Stage primaryStage) {
        combo = new ComboBox<>();
        combo.getItems().addAll("One", "Two", "Three");
        combo.setValue("One");
        selectedValue.set("One");
        view = new Label();
        view.textProperty().bind(Bindings.concat("This is view ", selectedValue));

        combo.valueProperty().addListener((obs, oldValue, newValue) -> {
            if (needsConfirmation) {
                SaveChangesResult saveChanges = showSaveChangesDialog();
                if (saveChanges.save) {
                    saveChanges();
                }
                if (saveChanges.proceed) {
                    selectedValue.set(newValue);
                } else { 
                    Platform.runLater(() -> {
                        needsConfirmation = false ;
                        combo.setValue(oldValue);
                        needsConfirmation = true ;
                    });
                }
            }
        });

        BorderPane root = new BorderPane(view);
        BorderPane.setAlignment(combo, Pos.CENTER);
        BorderPane.setMargin(combo, new Insets(5));
        root.setTop(combo);

        primaryStage.setScene(new Scene(root, 400, 400));
        primaryStage.show();
    }

    private void saveChanges() {
        System.out.println("Save changes");
    }

    private SaveChangesResult showSaveChangesDialog() {
        DialogPane dialogPane = new DialogPane();
        dialogPane.setContentText("Save changes?");
        dialogPane.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
        Dialog<SaveChangesResult> dialog = new Dialog<>();
        dialog.setDialogPane(dialogPane);
        dialog.setResultConverter(button -> {
            if (button == ButtonType.YES) return SaveChangesResult.SAVE_CHANGES ;
            else if (button == ButtonType.NO) return SaveChangesResult.PROCEED_WITHOUT_SAVING ;
            else return SaveChangesResult.CANCEL ;
        });
        return dialog.showAndWait().orElse(SaveChangesResult.CANCEL);
    }

    enum SaveChangesResult {
        SAVE_CHANGES(true, true), PROCEED_WITHOUT_SAVING(true, false), CANCEL(false, false) ;

        private boolean proceed ;
        private boolean save ;

        SaveChangesResult(boolean proceed, boolean save) {
            this.proceed = proceed ;
            this.save = save ;
        }

    }

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

答案 1 :(得分:0)

要执行此操作,您需要将ChangeListener添加到valueProperty()的{​​{1}}

以下是一个例子:

ComboBox