Zephyr
Zephyr

Reputation: 10253

How to reset ComboBox and display PromptText?

Note: I am expanding on duplicate question here because it does not include a MCVE. The few other similar questions I've found also do not include working answers.

I am unable to find a way to have a ComboBox display the PromptText after clearing the selection.

Here is the MCVE:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        final VBox root = new VBox(10);
        root.setAlignment(Pos.TOP_CENTER);
        root.setPadding(new Insets(10));

        final ComboBox<String> cboSelection = new ComboBox<>();
        final Button btnClear = new Button("Clear");

        // Set ComboBox selections
        final ObservableList<String> subjectsList = FXCollections.observableArrayList();
        subjectsList.addAll("Software", "Math", "Physics");

        // Setup the Subject selection
        cboSelection.setPromptText("Select Subject");
        cboSelection.setItems(subjectsList);

        // Set action for "Clear" button
        btnClear.setOnAction(e -> {
            cboSelection.setValue(null);
        });

        root.getChildren().addAll(cboSelection, btnClear);

        primaryStage.setTitle("ComboBox Demo");
        primaryStage.setScene(new Scene(root, 200, 100));
        primaryStage.show();


    }


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

}

Clicking the "Clear" button will set the selected value to null and clear the selection of the ComboBox, but the prompt text does not show again. This does not seem like the normal expected behavior.

I have tried clearSelection() as well as setPromptText() within the button's onAction and nothing seems to work to get the prompt text back.

Upvotes: 4

Views: 5734

Answers (1)

James_D
James_D

Reputation: 209358

According to the documentation, the prompt text should not actually be displayed at all here:

Prompt text is not displayed in all circumstances, it is dependent upon the subclasses of ComboBoxBase to clarify when promptText will be shown. For example, in most cases prompt text will never be shown when a combo box is non-editable (that is, prompt text is only shown when user input is allowed via text input).

If you want to see some prompt text when the selection is null (and you do not have an editable combo box), use a custom buttonCell on the combo box:

    cboSelection.setPromptText("Select Subject");
    cboSelection.setButtonCell(new ListCell<String>() {
        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty) ;
            if (empty || item == null) {
                setText("Select Subject");
            } else {
                setText(item);
            }
        }
    });

Note that it seems you also need to set the prompt text, as in the code in the question, in order to get the text to appear initially. I assume this is because of the same bug (I'm guessing that the library code is incorrectly setting the text of the button cell to the prompt text initially; if the prompt text is not set, the text gets set to null, apparently after the button cell's update method is invoked).

And you can obviously make this reusable by creating a named subclass of ListCell:

public class PromptButtonCell<T> extends ListCell<T> {

    private final StringProperty promptText = new SimpleStringProperty();

    public PromptButtonCell(String promptText) {
        this.promptText.addListener((obs, oldText, newText) -> {
            if (isEmpty() || getItem() == null) {
                setText(newText);
            }
        });
        setPromptText(promptText);
    }

    public StringProperty promptTextProperty() {
        return promptText ;
    }

    public final String getPromptText() {
        return promptTextProperty().get();
    }

    public final void setPromptText(String promptText) {
        promptTextProperty().set(promptText);
    }

    @Override
    protected void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);
        if (empty || item == null) {
            setText(getPromptText());
        } else {
            setText(item);
        }
    }
}

and then just

cboSelection.setButtonCell("Select Subject");
cboSelection.setButtonCell(new PromptButtonCell<>("Select Subject"));

Upvotes: 6

Related Questions