如何禁用 ChoiceBox 中的单个项目?

5 java javafx

如何禁用 JavaFX 中的单个项目ChoiceBox?我不想像ChoiceBox这样禁用完整的:

choiceBox.setDisable(true);
Run Code Online (Sandbox Code Playgroud)

jew*_*sea 4

没有用于禁用 ChoiceBox 中项目的公共 API。正如评论中所建议的,您可以使用 ComboBox 代替。

该解决方案使用模型属性(在本例中为待办任务已完成布尔属性)上的提取器来确定是否应禁用组合框中的项目。

用法示例

未完成任何任务,并从下拉列表中选择“喂猫”任务。

全部启用

已按下“完成”按钮以完成“喂猫”任务,该任务仍保持选中状态,但显示为禁用。

喂猫残疾人

显示下拉列表,并且仍选择已禁用的“喂猫”任务。

喂猫残疾并摔倒

选择“修剪草坪”任务。“喂猫”任务仍处于禁用状态,无法再再次选择。

修剪选定的草坪

实施示例

我手动设置禁用项目的不透明度。通常,这会自动发生,但是 ComboBox 样式的一些怪癖不会保留禁用的不透明度的样式,而无需手动覆盖它(根据我的测试)。

生成单元的工厂是可配置的。我已经使用了禁用项目的标准反馈来设置不透明度以直观地表明它们已被禁用。但是您可以提供不同的实现(例如,对于待办事项列表,您可以为无法再选择的已完成任务提供复选标记或删除线)。

import javafx.application.Application;
import javafx.beans.Observable;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.util.List;

public class TodoComboBoxApp extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        ObservableList<ToDoItem> todoList = FXCollections.observableList(
                List.of(
                        new ToDoItem("Weed the garden"),
                        new ToDoItem("Mow the lawn"),
                        new ToDoItem("Feed the cat"),
                        new ToDoItem("Feed the fish"),
                        new ToDoItem("Feed the fish to the cat")
                ),
                todoItem -> new Observable[] { todoItem.completeProperty() }
        );

        ComboBox<ToDoItem> taskComboBox = new ComboBox<>(todoList);
        taskComboBox.getSelectionModel().select(0);
        taskComboBox.setCellFactory(param -> new ToDoCell());
        taskComboBox.setButtonCell(new ToDoCell());

        Button completeButton = new Button("Complete");
        completeButton.setOnAction(e ->
                taskComboBox
                        .getSelectionModel()
                        .getSelectedItem()
                        .setComplete(true)
        );

        VBox layout = new VBox(20, completeButton, taskComboBox);
        layout.setPadding(new Insets(20));

        stage.setScene(new Scene(layout));
        stage.show();
    }

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

class ToDoItem {
    private final String taskName;
    private final BooleanProperty complete = new SimpleBooleanProperty();

    ToDoItem(String taskName) {
        this.taskName = taskName;
    }

    public String getTaskName() {
        return taskName;
    }

    public boolean isComplete() {
        return complete.get();
    }

    public void setComplete(boolean complete) {
        this.complete.set(complete);
    }

    public BooleanProperty completeProperty() {
        return complete;
    }
}

class ToDoCell extends ListCell<ToDoItem> {
    ToDoCell() {
        disabledProperty().addListener((observable, oldValue, newValue) ->
                setOpacity(newValue != null && newValue ? .6 : 1)
        );
    }

    @Override
    protected void updateItem(ToDoItem item, boolean empty) {
        super.updateItem(item, empty);

        if (item == null || empty) {
            setText(null);
            setDisable(false);
            return;
        }

        setText(item.getTaskName());
        setDisable(item.isComplete());

        System.out.println(item.getTaskName() + ", disabled? " + isDisabled());
    }
}
Run Code Online (Sandbox Code Playgroud)