javafx binding combobox itemsProperty

872 views Asked by At

I have customized a combobox in order to add and remove an item in a combobox. Now I would bind my customized combobox, but it is not working and I don't understand what happen.

Here my sample example :

public class CbbxEditSuppr extends ComboBox<BoxItem> {

private TextField editor = null;
private ObservableList<BoxItem> items = null;



/**
 * Constructeur.
 * 
 * @param addedItems ObservableList<String>
 * @param prefWidth double largeur préférée
 */
public CbbxEditSuppr(ObservableList<String> addedItems, final double prefWidth) {
    // initialisation des attributs
    editor = this.getEditor();
    items = this.getItems();
    this.setPrefWidth(prefWidth);
    // initialisation du contenu de la cellule
    this.setCellFactory(new Callback<ListView<BoxItem>, ListCell<BoxItem>>() {
        @Override
        public ListCell<BoxItem> call(ListView<BoxItem> p) {
            final ListCell<BoxItem> cell = new ListCell<BoxItem>() {
                @Override
                protected void updateItem(BoxItem t, boolean bln) {
                    super.updateItem(t, bln);
                    if (t != null) {
                        setGraphic(t.getBtn());
                        setText(t.getItem());
                    } else {
                        setGraphic(null);
                    }
                }
            };
            return cell;
        }
    });
    // déininition du converter
    this.setConverter(new StringConverter<BoxItem>() {
        @Override
        public String toString(BoxItem cbbx) {
            if (cbbx == null) {
                return null;
            } else {
                return cbbx.getItem();
            }
        }
        @Override
        public BoxItem fromString(String id) {
            if (id != null) {
                final BoxItem box = new BoxItem(id, items);
                return box;
            } else {
                return null;
            }

        }
    });
    // permet de prendre en compte la touche ENTER, et ajouter des valeurs a la liste
    this.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
        public void handle(final KeyEvent event) {
            if (event != null && event.getCode().equals(KeyCode.ENTER)) {
                if (editor.getText().trim().length() > 0) {
                    addItem(editor.getText());
                    editor.clear();
                }
            } else if  (event != null && event.getCode().equals(KeyCode.DOWN)) {
                showPopUpMenu();
            }
        }
    });
    // propriétés editable et selection du premier element
    this.setEditable(true);
    /* ajout des valeurs a la liste d'items */
    if (addedItems != null && addedItems.size() > 0) {
        for (String stg : addedItems) {
            if (stg != null) {
                final BoxItem hbox = new BoxItem(stg, items);
                items.add(hbox);
            }
        }
    }
    this.getSelectionModel().selectFirst();
}

private void showPopUpMenu(){
    if (!this.isShowing()) {
        this.show();
    }
}

/**
 * Ajoute un item à la liste
 * 
 * @param stg String nom de l'item
 */
public void addItem(String stg) {
    if (stg != null) {
        items.add(new BoxItem(stg, items));
    }
}


/**
 * Retourne la description du contenu de la liste
 */
public String toString() {
    final StringBuilder stgBuilder = new StringBuilder("[ ");
    if (items != null && items.size() > 0) {
        final BoxItem lastItem = items.get(items.size() - 1);
        for (BoxItem item : items) {
            if (item != null) {
                stgBuilder.append(item.getItem());
                if (!item.equals(lastItem)) {
                    stgBuilder.append(", ");
                }
            }
        }
    }
    stgBuilder.append(" ]");
    return stgBuilder.toString();

}
}

and

public class ComboboxSample extends Application {

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


@Override
public void start(Stage stage) {
    stage.setTitle("ComboBoxSample");
    Scene scene = new Scene(new Group(), 450, 250);

    CbbxEditSuppr cbboxLeft = new CbbxEditSuppr(FXCollections.observableArrayList(new ArrayList()), 200);
    CbbxEditSuppr cbboxRight = new CbbxEditSuppr(FXCollections.observableArrayList(new ArrayList()), 200);

    cbboxLeft.itemsProperty().bindBidirectional(cbboxRight.itemsProperty());
    GridPane grid = new GridPane();
    grid.setVgap(4);
    grid.setHgap(10);
    grid.setPadding(new Insets(5, 5, 5, 5));
    grid.add(new Label("To: "), 0, 0);
    grid.add(cbboxLeft, 1, 0);
    grid.add(cbboxRight, 2, 0);

    Group root = (Group) scene.getRoot();
    root.getChildren().add(grid);
    stage.setScene(scene);
    stage.show();

}
}

When I add a value in the right combobox it is working but not in the left combobox. Do you have any advice please ?

1

There are 1 answers

0
James_D On

The issue is that you "shadow" the items field. There are basically two properties called items in your combo box subclass: one that you define and one you inherit. When you call itemsProperty() you are getting the property wrapping the inherited items, and you are binding to that. In your class implementation, you then refer to the shadow items field, which is not bound.

You should remove the items field entirely from your class, and just refer to the inherited one by calling getItems().

For example, do

if (addedItems != null && addedItems.size() > 0) {
    for (String stg : addedItems) {
        if (stg != null) {
            final BoxItem hbox = new BoxItem(stg, items);
            getItems().add(hbox);
        }
    }
}