带有复选框的 JavaFX 组合框

Posted

技术标签:

【中文标题】带有复选框的 JavaFX 组合框【英文标题】:JavaFX ComboBox with CheckBoxes 【发布时间】:2014-12-25 04:45:17 【问题描述】:

问题描述

我尝试创建一个JavaFXComboBox,它在下拉菜单中保存CheckBoxesComboBox 应该是可编辑的,并由一个简单的Class 提供,我们称之为CheckItemCheckItems 的列表应该是可检查的 - 并且在做出选择后不应关闭下拉菜单。

最后,ComboBox 中的文本应该可用并且选择(所有选中项)

这是我已经解决的问题

(1) ComboBoxCheckItem 渲染为 CheckedBox 并正确选择

(2) 从ComboBox获取文本

出现的问题

(1) 点击一个项目后,下拉菜单关闭并且项目的选择状态不会改变。

(2) 据我所知,一次只能选择 一个 项?

这是我测试这些东西的代码:

测试程序

public class ComboButtonSample extends Application 

    @Override
    public void start(Stage stage) 
            final ObservableList<CheckItem> items = fetchItems();
            ComboBox<CheckItem> combo = createComboBox(items);
            combo.setPromptText("enter searchstring here");
            combo.setEditable(true);


            // order the components vertically
            VBox vBox = new VBox();
            vBox.getChildren().add(combo);

            // Button to write out the text and the items of the combobox
            Button btn = new Button();
            btn.setText("combo text to console");
            btn.setOnAction((event) -> 
                    System.out.println("Text is: "+combo.getEditor().getText());
                    System.out.println("Content is: ");
                    for (Iterator<CheckItem> iterator = combo.getItems().iterator(); iterator.hasNext();) 
                            CheckItem ci = (CheckItem) iterator.next();
                            System.out.println(String.format("[%s] %s -> %s", ci.selected ? "X" : " ",ci.getDisplayName(), ci.getInternalName()));

                    
            );

            vBox.getChildren().add(btn);

            // show you do not need any code to change the selection of the box.
            CheckBox checkBox = new CheckBox();
            checkBox.setText("test box");
            vBox.getChildren().add(checkBox);

            stage.setScene(new Scene(vBox));
            stage.show();
    

    private ComboBox<CheckItem> createComboBox(ObservableList<CheckItem> data) 
            ComboBox<CheckItem> combo = new ComboBox<>();
            combo.getItems().addAll(data);
            combo.setCellFactory(listView -> new CheckItemListCell());
            return combo;
    

    class CheckItemListCell extends ListCell<CheckItem> 
            private final CheckBox btn;

            CheckItemListCell() 
                    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                    btn = new CheckBox();
            

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

                    if (item == null || empty) 
                            setGraphic(null);
                     else 
                            btn.setText(item.getDisplayName());
                            btn.selectedProperty().setValue(item.selected);
                            setGraphic(btn);
                    
            
    

    private ObservableList<CheckItem> fetchItems() 
            final ObservableList<CheckItem> data = FXCollections
                            .observableArrayList();
            for (int i = 1; i < 15; i++) 
                    CheckItem chkItem = new CheckItem();
                    chkItem.selected = i%3==0;
                    chkItem.setDisplayName("DisplayName" + i);
                    chkItem.setInternalName("InternalName" + i);
                    data.add(chkItem);
            
            return data;
    

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

检查项目

public class CheckItem 
    boolean selected;
    String displayName;
    String internalName;    

    public boolean isChecked() 
        return selected;
    

    public void setChecked(boolean checked) 
        this.selected = checked;
    

    public String getDisplayName() 
        return displayName;
    

    public void setDisplayName(String displayName) 
        this.displayName = displayName;
    

    public String getInternalName() 
        return internalName;
    

    public void setInternalName(String internalName) 
        this.internalName = internalName;
    

【问题讨论】:

ComboBoxes 专门用于从项目列表中选择一个项目。我认为对于您想要的功能,我将从由CheckMenuItems 填充的MenuButton 开始。 ControlsFX 项目中还有一个CheckComboBox,您可能想看看。 感谢 José Pereda 不知何故我错过了这个!您可以将此添加为接受它的答案吗?谢谢! 【参考方案1】:

我的示例代码:

CheckedComboBox

类人

public class Person 

    private StringProperty name = new SimpleStringProperty();
    private ObjectProperty<LocalDate> birthday = new SimpleObjectProperty<>();

    public Person() 
    

    public Person(String name, LocalDate birthday) 
        setNameValue(name);
        setBirthdayValue(birthday);
    

    public StringProperty getNameProperty() 
        return name;
    

    public String getNameValue() 
        return name.getValue();
    

    public void setNameValue(String value) 
        name.setValue(value);
    

    public ObjectProperty<LocalDate> getBirthdayProperty() 
        return birthday;
    

    public LocalDate getBirthdayValue() 
        return birthday.getValue();
    

    public void setBirthdayValue(LocalDate value) 
        birthday.setValue(value);
    

    @Override
    public String toString() 
        return getNameValue()+" ("+getBirthdayValue()+")";
    


简单的包装器

public class ComboBoxItemWrap<T> 

    private BooleanProperty check = new SimpleBooleanProperty(false);
    private ObjectProperty<T> item = new SimpleObjectProperty<>();

    ComboBoxItemWrap() 
    

    ComboBoxItemWrap(T item) 
        this.item.set(item);
    

    ComboBoxItemWrap(T item, Boolean check) 
        this.item.set(item);
        this.check.set(check);
    

    public BooleanProperty checkProperty() 
        return check;
    

    public Boolean getCheck() 
        return check.getValue();
    

    public void setCheck(Boolean value) 
        check.set(value);
    

    public ObjectProperty<T> itemProperty() 
        return item;
    

    public T getItem() 
        return item.getValue();
    

    public void setItem(T value) 
        item.setValue(value);
    

    @Override
    public String toString() 
        return item.getValue().toString();
    

示例代码

public class MainApplication extends Application 

    @Override
    public void start(Stage stage) 
        Scene scene = new Scene(new VBox(), 450, 250);

        ComboBox<ComboBoxItemWrap<Person>> cb = new ComboBox<>();

        @SuppressWarnings("unchecked")
        ObservableList<ComboBoxItemWrap<Person>> options = FXCollections.observableArrayList(
                new ComboBoxItemWrap<>(new Person("A", LocalDate.now().minusDays(12))),
                new ComboBoxItemWrap<>(new Person("B", LocalDate.now().minusDays(34))),
                new ComboBoxItemWrap<>(new Person("C", LocalDate.now().minusDays(48))),
                new ComboBoxItemWrap<>(new Person("D", LocalDate.now().minusDays(56))),
                new ComboBoxItemWrap<>(new Person("E", LocalDate.now().minusDays(72))),
                new ComboBoxItemWrap<>(new Person("F", LocalDate.now().minusDays(96)))
                );

        cb.setCellFactory( c -> 
            ListCell<ComboBoxItemWrap<Person>> cell = new ListCell<>()
                @Override
                protected void updateItem(ComboBoxItemWrap<Person> item, boolean empty) 
                    super.updateItem(item, empty);
                    if (!empty) 
                        final CheckBox cb = new CheckBox(item.toString());
                        cb.selectedProperty().bind(item.checkProperty());
                        setGraphic(cb);
                    
                
            ;

            cell.addEventFilter(MouseEvent.MOUSE_RELEASED, event -> 
                cell.getItem().checkProperty().set(!cell.getItem().checkProperty().get());
                StringBuilder sb = new StringBuilder();
                cb.getItems().filtered( f-> f!=null).filtered( f-> f.getCheck()).forEach( p -> 
                    sb.append("; "+p.getItem());
                );
                final String string = sb.toString();
                cb.setPromptText(string.substring(Integer.min(2, string.length())));
            );

            return cell;
        );

        cb.setItems(options);


        VBox root = (VBox) scene.getRoot();

        Button bt = new Button("test");

        bt.setOnAction(event -> 
            cb.getItems().filtered( f -> f.getCheck()).forEach( item -> System.out.println(item.getItem()));
        );

        root.getChildren().addAll(cb, bt);
        stage.setScene(scene);
        stage.show();
    

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

【讨论】:

【参考方案2】:

如果您在实施中遇到问题,您应该查看ControlsFX 项目中的CheckComboBox 控件。

源码可以在here找到。

【讨论】:

嗨!如何将此 CheckComboBox 添加到 FXML 文件中? 请创建一个新问题。

以上是关于带有复选框的 JavaFX 组合框的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JavaFX 将选择框、复选框和文本字段实现为一个按钮 [关闭]

带有复选框的 QML 组合框

JavaFX 8,带有复选框的 ListView

如何将数据源绑定到 datagridview 组合框和复选框

组合框的访问选择查询并不总是评估复选框值

将可检查组合框的文本显示到 QTableWidget