组合框选定项的事件筛选器



如何为 ComboBox 的 SelectedItem 属性编写事件筛选器?本文仅针对用户事件(如鼠标事件(对其进行描述,我似乎无法找出所选项目属性更改的 EventType 是什么。

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

我也对"是否要保存更改?"实现的其他方法持开放态度,这些方法可能更适合。

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

因此,例如

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);
    }
}

为此,您需要向ComboBoxvalueProperty()添加一个ChangeListener

下面是一个示例:

comboBox.valueProperty().addListener(new ChangeListener<Object>()
{
    @Override
    public void changed(ObservableValue observable, Object oldValue, Object newValue)
    {
        Optional<ButtonType> result = saveAlert.showAndWait();
        if(result.isPresent())
        {
             if(result.get() == ButtonType.YES)
             {
                 //Your Save Functionality
                 comboBox.valueProperty().setValue(newValue);
             }
             else
             {
                 //Whatever
                 comboBox.valueProperty().setValue(oldValue);
             }
        }
    }    
});

最新更新