JavaFX ComboBox with CheckBoxes

15,640

Solution 1

If you have problems in your implementation, you should have a look to the CheckComboBox control in the ControlsFX project.

CheckComboBox Sample

Source code can be found here.

Solution 2

My sample code:

CheckedComboBox

class Person

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()+")";
    }

}

simple wrapper

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

sample code

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);
    }
}
Share:
15,640

Related videos on Youtube

lumo
Author by

lumo

Updated on June 04, 2022

Comments

  • lumo
    lumo almost 2 years

    Description of the Question

    I try to create a JavaFX ComboBox which holds CheckBoxes in the dropdown menu. The ComboBox shall be editable and gets fed by a simple Class lets call it CheckItem. the list of CheckItems shall be checkable - and shall not close the dropdown menu after a selection is made.

    finally the Text in the ComboBox should be available and a Selection (all checked Items)

    this is what i already worked out

    (1) a ComboBox rendering the CheckItem as CheckedBox with correct selection

    (2) gaining the Text from the ComboBox

    problems coming up

    (1) After clicking on one item the dropdown closes & selection state of the item does not change.

    (2) As far as i noticed its only possible to have one item selected at a time?

    here is my code for testing the stuff:

    Test Program

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

    CheckItem

    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;
        }
    }
    
    • James_D
      James_D over 9 years
      ComboBoxes are specifically for selecting one item from a list of items. I think for the functionality you want I would start with a MenuButton populated by CheckMenuItems.
    • José Pereda
      José Pereda over 9 years
      There's also a CheckComboBox in the ControlsFX project you may want to have a look.
    • lumo
      lumo over 9 years
      thanks José Pereda somehow i missed this one! can you add this as an answer to accept it? thanks!
  • user691197
    user691197 about 9 years
    Hi ! How to add this CheckComboBox into an FXML file ?
  • José Pereda
    José Pereda about 9 years
    Please, create a new question.