javajavafxjfoenix

JavaFX: Make Chips Editable in JFXChipView


I want to ask if it is possible to make a chip in JFXChipView editable once it has been set.

enter image description here


Solution

  • You can create your own JFXChip and implement a behavior to enable editing. First, you need to have an editable label. I looked up online and I found this post: JavaFX custom control - editable label. Then, you can extend JFXChip to use that EditableLabel:

    import com.jfoenix.controls.JFXButton;
    import com.jfoenix.controls.JFXChip;
    import com.jfoenix.controls.JFXChipView;
    import com.jfoenix.svg.SVGGlyph;
    import javafx.beans.binding.Bindings;
    import javafx.beans.property.Property;
    import javafx.scene.layout.HBox;
    
    public class EditableChip<T> extends JFXChip<Property<T>> {
        protected final HBox root;
    
        public EditableChip(JFXChipView<Property<T>> view, Property<T> item) {
            super(view, item);
            JFXButton closeButton = new JFXButton(null, new SVGGlyph());
            closeButton.getStyleClass().add("close-button");
            closeButton.setOnAction(event -> {
                view.getChips().remove(item);
                event.consume();
            });
    
            // Create the label with an initial value from the item
            String initialValue = view.getConverter().toString(item);
            EditableLabel label = new EditableLabel(initialValue);
            label.setMaxWidth(100);
    
            // Bind the item to the text in the label
            item.bind(Bindings.createObjectBinding(() -> view.getConverter().fromString(label.getText()).getValue(), label.textProperty()));
    
            root = new HBox(label, closeButton);
            getChildren().setAll(root);
        }
    }
    

    Note: I am using Property<T> instead of using the desired class T because JFXChipView stores the item the first time you add it. And in that case, you're going to get the values as you entered them the first time when calling JFXChipView#getChips().

    Sample application:

    import com.jfoenix.controls.JFXChipView;
    import javafx.application.Application;
    import javafx.beans.property.Property;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.scene.Scene;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    import javafx.util.StringConverter;
    
    public class EditableChipViewApp extends Application {
        @Override
        public void start(Stage primaryStage) {
            JFXChipView<Property<String>> chipView = new JFXChipView<>();
            chipView.setChipFactory(EditableChip::new);
    
            chipView.setConverter(new StringConverter<Property<String>>() {
                @Override
                public String toString(Property<String> object) {
                    return object == null ? null : object.getValue();
                }
    
                @Override
                public Property<String> fromString(String string) {
                    return new SimpleStringProperty(string);
                }
            });
    
            VBox container = new VBox(chipView);
            Scene scene = new Scene(container, 800, 600);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    Result:

    sample application

    This is how you get the actual values of the chips:

    List<String> chipsValues = chipView.getChips().stream().map(Property::getValue).collect(Collectors.toList());