Multiple scene nodes in PropertySheet Editor JavaFX - java

I want to add checkbox and textfield to one property of PropertySheet (ControlsFX library). Is it possible or no? So, i just need to add some GUI elements together to one PropertyEditor, for example checkbox + button, checkbox + label, checkbox + textfield and etc. Is it possible to override PropertyEditor to do it?

you could also wrap multiples nodes inside a single parent .[See Here

Solved by myself. I tried to add checkbox + combobox to HBox. Code below, it works.
public static final <T> PropertyEditor<?> createCheckBoxLinkEditor(PropertySheet.Item property,
final Collection<T> choices) {
ComboBox<T> comboBox = new ComboBox<T>();
comboBox.setCellFactory((ListView<T> p) -> new ListCell<T>() {
#Override
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
} else if (item instanceof Class) {
setText(((Class) item).getSimpleName());
} else {
setText(item.toString());
}
}
});
HBox hbox = new HBox(5);
CheckBox checkBox = new CheckBox();
hbox.getChildren().add(checkBox);
hbox.getChildren().add(comboBox);
//hbox.getA
//comboBox.setConverter(value);
return new AbstractPropertyEditor<T, HBox>(property, hbox) {
{
comboBox.setItems(FXCollections.observableArrayList(choices));
//new AutoCompleteComboBoxListener(comboBox);
new SelectKeyComboBoxListener(comboBox);
}
#Override
protected ObservableValue<T> getObservableValue() {
return comboBox.getSelectionModel().selectedItemProperty();
}
#Override
public void setValue(T value) {
comboBox.getSelectionModel().select(value);
}
};
}

Related

Create a listener logic for a custom combobox

I am trying to create a listener logic for a custom combo box that I have created that contains items with check boxes.
I was not able to proceed as I am not getting an idea on how to do it.
MainApplication.java
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", "12-Aug-1994")),
new ComboBoxItemWrap<>(new Person("B", "13-Aug-1994")),
new ComboBoxItemWrap<>(new Person("C", "14-Aug-1994"))
);
cb.setCellFactory( c -> {
ListCell<ComboBoxItemWrap<Person>> cell = new ListCell<ComboBoxItemWrap<Person>>(){
#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);
}
}
ComboBoxItemWrap.java
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();
}
}
Person.java
public class Person {
private StringProperty name = new SimpleStringProperty();
private StringProperty birthday = new SimpleStringProperty();
public Person() {
}
public Person(String name, String 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 StringProperty getBirthdayProperty() {
return birthday;
}
public String getBirthdayValue() {
return birthday.getValue();
}
public void setBirthdayValue(String value) {
birthday.setValue(value);
}
#Override
public String toString() {
return getNameValue()+" ("+getBirthdayValue()+")";
}
}
In the output application, a list of items with check boxes will get populated. On selection of any number of entries in the list, the entry name gets populated on the combo box itself separated by a ';'. Now I want my back end code to listen and identify the entries that have been selected in order to perform further operations.
You may not need to reinvent the wheel. Consider using ControlsFX CheckComboBox.
That being said there are several problems in the code:
You never update the property on a selection of the CheckBox. This can be easily fixed by using bidirectional bindings.
Since the ComboBox popup is closed, the CheckBox is no longer armed at the time the MOUSE_RELEASED event is triggered. this is a prerequesite for the selected state of the CheckBox changing though. Modifying the skin allows you to change this behaviour.
You use ObservableList.filtered to create FilteredLists that you throw away immediately afterwards. You also create a filtered list of a filtered list in the MOUSE_RELEASED event filter. This is not wrong per se, but you're creating an expensive object there without the need to do so: simply get a stream there. This is a much more lightweight way to filter a list, if the result is only needed once. Use filtered/FilteredList only if you need an ObservableList that contains elements from another ObservableList and that is automatically updated.
Also note that there is a way to make an ObservableList trigger update changes on a change of a property: Use the observableArrayList method taking an extractor as parameter.
This is how you could rewrite your code to make it work:
VBox root = new VBox();
Scene scene = new Scene(root, 450, 250);
ComboBox<ComboBoxItemWrap<Person>> cb = new ComboBox<>();
ObservableList<ComboBoxItemWrap<Person>> options = FXCollections.observableArrayList(item -> new Observable[] {item.checkProperty()});
options.addAll(
new ComboBoxItemWrap<>(new Person("A", "12-Aug-1994")),
new ComboBoxItemWrap<>(new Person("B", "13-Aug-1994")),
new ComboBoxItemWrap<>(new Person("C", "14-Aug-1994")));
cb.setCellFactory(c -> new ListCell<ComboBoxItemWrap<Person>>() {
private final CheckBox cb = new CheckBox();
#Override
protected void updateItem(ComboBoxItemWrap<Person> item, boolean empty) {
ComboBoxItemWrap<Person> oldItem = getItem();
if (oldItem != null) {
// remove old binding
cb.selectedProperty().unbindBidirectional(oldItem.checkProperty());
}
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
cb.selectedProperty().bindBidirectional(item.checkProperty());
cb.setText(item.toString());
setGraphic(cb);
}
}
});
// make sure popup remains open
ComboBoxListViewSkin<ComboBoxItemWrap<Person>> skin = new ComboBoxListViewSkin<>(cb);
skin.setHideOnClick(false);
cb.setSkin(skin);
cb.setItems(options);
cb.promptTextProperty().bind(Bindings.createStringBinding(() ->
options.stream().filter(ComboBoxItemWrap::getCheck).map(Object::toString).collect(Collectors.joining("; ")), options));
Note that if you want the popup to be closed after (de)selecting a checkbox, you could simply add a event filter for MOUSE_RELEASED for the checkbox that calls cb.arm() instead of modifying the skin.

TreeTableView : setting a row not editable

I want to have control over the styling of some rows of a TreeTableView based on the level in the tree. I used setRowFactory and apply a styling if this row is part of the first level children of the root of the Table. The styling works fine, but I also want to disable clicking on the checkbox for those rows. I am able to setDisable(true) but that also disables the expanding of the TreeItem and SetEditable(false) does not seem to have any effect.
EDIT: What I understand is that the Table must be set editable, then the columns are by default editable. But if I set TreeTableRow.setEditable(true); or TreeTableRow.setEditable(false); I never see any effect. The description seems of setEditable seems exactly what I want but I am unable to use it that way.
void javafx.scene.control.Cell.setEditable(boolean arg0)
setEditable
public final void setEditable(boolean value)
Allows for certain cells to not be able to be edited. This is useful incases >where, say, a List has 'header rows' - it does not make sense forthe header rows >to be editable, so they should have editable set tofalse.
Parameters:value - A boolean representing whether the cell is editable or not.If >true, the cell is editable, and if it is false, the cell can notbe edited.
Main:
public class TreeTableViewRowStyle extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
// create the treeTableView and colums
TreeTableView<Person> ttv = new TreeTableView<Person>();
TreeTableColumn<Person, String> colName = new TreeTableColumn<>("Name");
TreeTableColumn<Person, Boolean> colSelected = new TreeTableColumn<>("Selected");
colName.setPrefWidth(100);
ttv.getColumns().add(colName);
ttv.getColumns().add(colSelected);
ttv.setShowRoot(false);
ttv.setEditable(true);
// set the columns
colName.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
colSelected.setCellFactory(CheckBoxTreeTableCell.forTreeTableColumn(colSelected));
colSelected.setCellValueFactory(new TreeItemPropertyValueFactory<>("selected"));
ttv.setRowFactory(table-> {
return new TreeTableRow<Person>(){
#Override
public void updateItem(Person pers, boolean empty) {
super.updateItem(pers, empty);
boolean isTopLevel = table.getRoot().getChildren().contains(treeItemProperty().get());
if (!isEmpty()) {
if(isTopLevel){
setStyle("-fx-background-color:lightgrey;");
setEditable(false); //THIS DOES NOT SEEM TO WORK AS I WANT
//setDisable(true); //this would disable the checkbox but also the expanding of the tree
}else{
setStyle("-fx-background-color:white;");
}
}
}
};
});
// creating treeItems to populate the treetableview
TreeItem<Person> rootTreeItem = new TreeItem<Person>();
TreeItem<Person> parent1 = new TreeItem<Person>(new Person("Parent 1"));
TreeItem<Person> parent2 = new TreeItem<Person>(new Person("Parent 1"));
parent1.getChildren().add(new TreeItem<Person>(new Person("Child 1")));
parent2.getChildren().add(new TreeItem<Person>(new Person("Child 2")));
rootTreeItem.getChildren().addAll(parent1,parent2);
ttv.setRoot(rootTreeItem);
// build and show the window
Group root = new Group();
root.getChildren().add(ttv);
stage.setScene(new Scene(root, 300, 300));
stage.show();
}
}
Model Person :
public class Person {
private StringProperty name;
private BooleanProperty selected;
public Person(String name) {
this.name = new SimpleStringProperty(name);
selected = new SimpleBooleanProperty(false);
}
public StringProperty nameProperty() {
return name;
}
public BooleanProperty selectedProperty() {
return selected;
}
public void setName(String name){
this.name.set(name);
}
public void setSelected(boolean selected){
this.selected.set(selected);
}
}
The base problem is that none of the editable (nor the pseudo-editable like CheckBoxXX) Tree/Table cells respect the editability of the row they are contained in. Which I consider a bug.
To overcome, you have to extend the (pseudo) editable cells and make them respect the row's editable. The exact implementation is different for pseudo- vs. real editing cells. Below are in-line examples, for frequent usage you would make them top-level and re-use.
CheckBoxTreeTableCell: subclass and override updateItem to re-bind its disabled property like
colSelected.setCellFactory(c -> {
TreeTableCell cell = new CheckBoxTreeTableCell() {
#Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (getGraphic() != null) {
getGraphic().disableProperty().bind(Bindings
.not(
getTreeTableView().editableProperty()
.and(getTableColumn().editableProperty())
.and(editableProperty())
.and(getTreeTableRow().editableProperty())
));
}
}
};
return cell;
});
For a real editing cell, f.i. TextFieldTreeTableCell: override startEdit and return without calling super if the row isn't editable
colName.setCellFactory(c -> {
TreeTableCell cell = new TextFieldTreeTableCell() {
#Override
public void startEdit() {
if (getTreeTableRow() != null && !getTreeTableRow().isEditable()) return;
super.startEdit();
}
};
return cell;
});
Now you can toggle the row's editability as you do, changed the logic a bit to guarantee full cleanup in all cases:
ttv.setRowFactory(table-> {
return new TreeTableRow<Person>(){
#Override
public void updateItem(Person pers, boolean empty) {
super.updateItem(pers, empty);
// tbd: check for nulls!
boolean isTopLevel = table.getRoot().getChildren().contains(treeItemProperty().get());
if (!isEmpty() && isTopLevel) {
// if(isTopLevel){
setStyle("-fx-background-color:lightgrey;");
setEditable(false);
}else{
setEditable(true);
setStyle("-fx-background-color:white;");
}
}
};
});
Instead of creating a custom TreeTableCell subclass you can use the following utility method that basically installs a new cell-factory on a column that delegates to the original cell-factory but adds the row-editability binding whenever a cell is created.
public <S, T> void bindCellToRowEditability(TreeTableColumn<S, T> treeTableColumn) {
// Keep a handle on the original cell-factory.
Callback<TreeTableColumn<S, T>, TreeTableCell<S, T>> callback = treeTableColumn.getCellFactory();
// Install a new cell-factory that performs the delegation.
treeTableColumn.setCellFactory(column -> {
TreeTableCell<S, T> cell = callback.call(column);
// Add a listener so that we pick up when a new row is set for the cell.
cell.tableRowProperty().addListener((observable, oldRow, newRow) -> {
// If the new row is non-null, we proceed.
if (newRow != null) {
// We get the cell and row editable-properties.
BooleanProperty cellEditableProperty = cell.editableProperty();
BooleanProperty rowEditableProperty = newRow.editableProperty();
// Bind the cell's editable-property with its row's property.
cellEditableProperty.bind(rowEditableProperty);
}
});
return cell;
});
}
You can then set this for all columns of your TreeTableView as:
List<TreeTableColumn<S, ?>> columns = treeTableView.getColumns();
columns.forEach(this::bindCellToRowEditability);
You still need the custom TreeTableRow that checks whether it is top-level or not so that the editable value is correctly set for the row itself. However, setting the editable value on the row will now ensure that all cells in that row correctly reflects the row's editable-property.
If you want disable a specific Cell then handle the disable logic in the CellFactory rather than in RowFactory. The static method forTreeTableColumn(..) is a convinient method for quick use. But that is not the only way. You can still create your own factory for CheckBoxTreeTableCell.
So instead of
colSelected.setCellFactory(CheckBoxTreeTableCell.forTreeTableColumn(colSelected));
set the cellfactory as below, and this should work for you.
colSelected.setCellFactory(new Callback<TreeTableColumn<Person, Boolean>, TreeTableCell<Person, Boolean>>() {
#Override
public TreeTableCell<Person, Boolean> call(TreeTableColumn<Person, Boolean> column) {
return new CheckBoxTreeTableCell<Person, Boolean>() {
#Override
public void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
boolean isTopLevel = column.getTreeTableView().getRoot().getChildren().contains(getTreeTableRow().getTreeItem());
setEditable(!isTopLevel);
}
};
}
});

How can I add a checkbox to a table that reads and writes the object property that it represents in JavaFX

I have a table that lists objects of type Bot which have a name and isOn properties that I want to list:
private SimpleStringProperty name;
private boolean isOn;
The boolean isOn, I want to be read from a checkbox and also editable from that checkbox
So far, I have been able to add a checkbox to a column in my table for each row but it is purely visual (i.e. it is not tied to the Bot's isOn member).
How can I make the checkbox read and write from and to this member of Bot?
Here is my code dealing with the Table altogether:
ObservableList<Bot> bots = FXCollections.observableArrayList();
#FXML
private TableView<Bot> botTable;
#FXML
private TableColumn<Bot, String> nameColumn;
#FXML
private TableColumn<Bot, Boolean> statusColumn;
public void initialize(URL location, ResourceBundle resources){
nameColumn.setCellValueFactory(new PropertyValueFactory<Bot, String>("name"));
statusColumn.setCellValueFactory(new PropertyValueFactory<Bot, Boolean>("on"));
statusColumn.setSortable(false);
statusColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Bot, Boolean>, ObservableValue<Boolean>>(){
#Override public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Bot, Boolean> features) {
return new SimpleBooleanProperty(features.getValue() != null);
}
});
// create a cell value factory with an add button for each row in the table.
statusColumn.setCellFactory(new Callback<TableColumn<Bot, Boolean>, TableCell<Bot, Boolean>>() {
#Override public TableCell<Bot, Boolean> call(TableColumn<Bot, Boolean> personBooleanTableColumn) {
return new AddBotCell(/*stage, botTable*/);
}
});
botTable.setItems(bots);
}
/** A table cell containing a button for adding a new person. */
private class AddBotCell extends TableCell<Bot, Boolean> {
// a checkbox for adding a new bot.
final CheckBox checkbox = new CheckBox();
// pads and centers the add button in the cell.
final StackPane paddedCheckBox = new StackPane();
AddBotCell(/*final Stage stage, final TableView table*/) {
paddedCheckBox.setPadding(new Insets(3));
paddedCheckBox.getChildren().add(checkbox);
checkbox.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
}
});
}
/** places an add checkbox in the row only if the row is not empty. */
#Override protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(checkbox);
}
}
}
You need to remove the checkbox, if the cell becomes empty. Furthermore you need to update the value when the user interacts with the CheckBox. This is better done from a listener to the selected property:
private class AddBotCell extends TableCell<Bot, Boolean> {
// a button for adding a new person.
final CheckBox checkbox = new CheckBox();
// pads and centers the add button in the cell.
final StackPane paddedCheckBox = new StackPane();
// records the y pos of the last button press so that the add person dialog can be shown next to the cell.
final DoubleProperty buttonY = new SimpleDoubleProperty();
private boolean updating = false;
AddBotCell(/*final Stage stage, final TableView table*/) {
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
paddedCheckBox.setPadding(new Insets(3));
paddedCheckBox.getChildren().add(checkbox);
checkbox.selectedProperty().addListener((o, oldValue, newValue) -> {
if (!updating) {
updating = true;
((Bot)getTableRow().getItem()).setIsOn(newValue);
updating = false;
}
});
}
/** places an add button in the row only if the row is not empty. */
#Override protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
setGraphic(paddedCheckBox);
updating = true;
checkbox.setSelected(item);
updating = false;
}
}
}
Also your cellValueFactory should use the value of the property.
statusColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Bot, Boolean>, ObservableValue<Boolean>>(){
#Override public ObservableValue<Boolean> call(TableColumn.CellDataFeatures<Bot, Boolean> features) {
return new SimpleBooleanProperty(features.getValue().isIsOn());
}
});

How can I to force JavaFX ComboBox dropdown list cells to be re-rendered?

I have a Java 8 editable ComboBox where the default item is bolded and the non-default items are unbolded by a CellFactory.
When the default is changed to another item, the only way I have found to get the new default bolded and the old default unbolded by the CellFactory is to delete and re-add both the old and new default items. This necessitates a fair bit of code to deal with a new item becoming current because the previous current item was removed and then setting the current item to the item we were modifying.
Is there a nice way to flag a cell as dirty and needing re-rendering so I don't have to remove and re-add 2 cells?
I have spent half a day googling but maybe I'm not asking the right questions.
I suppose the controlling code would be simpler if I just cleared all the combobox items and re-added them all, but that's not very efficient.
Edit: As requested, here is CellFactory:
bookComboBox.setCellFactory(
new Callback<ListView<String>, ListCell<String>>() {
#Override public ListCell<String> call(ListView<String> param) {
final ListCell<String> cell = new ListCell<String>() {
{
super.setPrefWidth(100);
}
#Override public void updateItem(String item,
boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item);
if (item.equals(Book.getDefaultBook())) {
setFont(Font.font("System", FontWeight.BOLD, 14));
System.out.println("bookComboBox.setCellFactory: set BOLD item=" + item);
}
else {
setFont(Font.font("System", FontWeight.NORMAL, 14));
System.out.println("bookComboBox.setCellFactory: set NORMAL item=" + item);
}
}
else {
setText(null);
}
}
};
return cell;
}
});
I'm not changing the values of the cells, just the font used when rendering.
I'm not using onEditCommit().
I use bookComboBox.setOnAction listener to react to combobox selection changes.
The setOnAction event also occurs when text is entered in the combobox and Action key (ENTER) is pressed or Combobox loses focus.
By using a ObservableValue<Boolean> that tells you whether the item should be bold or not for each cell, you can create a binding that updates the font.
Example:
This uses each item as default for 1 sec before using the next as default.
#Override
public void start(Stage primaryStage) {
ComboBox<String> comboBox = new ComboBox<>(FXCollections.observableArrayList(
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
));
final Font BOLD_FONT = Font.font("System", FontWeight.BOLD, 14);
final Font NORMAL_FONT = Font.font("System", FontWeight.NORMAL, 14);
final StringProperty defaultValue = new SimpleStringProperty();
comboBox.setCellFactory(lv -> new ListCell<String>() {
{
// use bold font if the item property contains the
// same value as the defaultValue property
fontProperty().bind(Bindings.when(itemProperty().isEqualTo(defaultValue))
.then(BOLD_FONT)
.otherwise(NORMAL_FONT));
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else {
setText(item);
}
}
});
// change default every second
PauseTransition animation = new PauseTransition(Duration.seconds(1));
EventHandler<ActionEvent> eventHandler = new EventHandler<ActionEvent>() {
private Iterator<String> iterator = comboBox.getItems().iterator();
#Override
public void handle(ActionEvent event) {
if (!iterator.hasNext()) {
iterator = comboBox.getItems().iterator();
}
defaultValue.set(iterator.next());
animation.play();
}
};
animation.setOnFinished(eventHandler);
eventHandler.handle(null);
Scene scene = new Scene(comboBox);
primaryStage.setScene(scene);
primaryStage.show();
}

How to put images in ListView javafx

In my ListView myList, I want each item(String) to have a mini photo next to it.
Here is my how my ListView myList is defined:
ListView<String> myList = new ListView<String>();
SearchResultList.setCellFactory(new Callback<ListView<String>,ListCell<String>>() {
#Override
public ListCell<String> call(ListView<String> list) {
return new ColorRectCell();
}
}
);
I read you must specify a cell factory which updates each item in list. However I don't know how this all works, This is the code where I specify my cell factory
static class ColorRectCell extends ListCell<String> {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
Image rect = new Image("huisteken.jpg");
ImageView rec = new ImageView(rect);
if (item != null) {
System.out.println("testing" + item +"######");
setGraphic(rec);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
}
Please, any ideas or tips are welcome.
My solution to accomplish this is to set the Cells text to null and to make Graphic contain a Hbox containing both picture and text. So make your updateItem look like this:
#Override
void updateItem(final String item, final boolean empty) {
super.updateItem(item, empty);
// if null, display nothing
if (empty || item == null) {
setText(null);
setGraphic(null);
return;
}
setText(null);
Label textLabel = new Label(item + " ");
final HBox hbox = new HBox();
hbox.setSpacing(5);
Label iconLabel = new Label();
iconLabel.setGraphic(new ImageView(new Image("huisteken.jpg")));
hbox.getChildren().addAll(iconLabel, textLabel);
setGraphic(hbox);
}
`

Categories