JavaFX ComboBox with CheckBoxes
Solution 1
If you have problems in your implementation, you should have a look to the CheckComboBox control in the ControlsFX project.
Source code can be found here.
Solution 2
My sample code:
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);
}
}
Related videos on Youtube
lumo
Updated on June 04, 2022Comments
-
lumo almost 2 years
Description of the Question
I try to create a
JavaFX
ComboBox
which holdsCheckBoxes
in the dropdown menu. TheComboBox
shall be editable and gets fed by a simpleClass
lets call itCheckItem
. the list ofCheckItems
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 theCheckItem
asCheckedBox
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 over 9 years
ComboBox
es are specifically for selecting one item from a list of items. I think for the functionality you want I would start with aMenuButton
populated byCheckMenuItem
s. -
José Pereda over 9 yearsThere's also a CheckComboBox in the ControlsFX project you may want to have a look.
-
lumo over 9 yearsthanks José Pereda somehow i missed this one! can you add this as an answer to accept it? thanks!
-
-
user691197 about 9 yearsHi ! How to add this CheckComboBox into an FXML file ?
-
José Pereda about 9 yearsPlease, create a new question.