How to set text and color of multiple ListView items when clicked

Viewed 50

I know there are many related questions about this but maybe I'm missing something because I can't get the behavior I'm expecting, to work.

@FXML
private ListView<String> guiList;

void performAction(Actions action) {
    try {
        Task<String> task = new Task<>() {
            @Override
            public String call() {
                String mySelection = Context.getInstance().getSelected();
                ArrayList<String> selectedList = Context.getInstance().getItemsClicked();
                if (selectedList == null) {
                    selectedList = new ArrayList<>();
                }
                selectedList.add(mySelection);
                Context.getInstance().setItemsClicked(selectedList);
                guiList.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
                    @Override
                    public ListCell<String> call(ListView<String> param) {
                        ListCell<String> cell = new ListCell<String>() {
                            @Override
                            protected void updateItem(String item, boolean empty) {
                                super.updateItem(item, empty);
                                if(item != null && item.matches(mySelection)) {
                                    setText(mySelection + " [" + action + "]");
                                    setFont(Font.font(Font.getDefault().getFamily(), FontWeight.BOLD, Font.getDefault().getSize()));
                                    setStyle("-fx-text-fill: green;");
                                } else {
                                    setText(item);
                                }
                            }
                        };
                        return cell;
                    }
                });
                return "";
            }
        };
    } catch (Exception e) {

    }
}

When I click in an item of guiList, the text is changed, gets bold and shows in green color but I don't understand why I need the else statement. If I don't use it, all the other items of the list disappear.

I ask this because I want to change ALL of the items I click and in the current behavior, the changes are only made in the last one clicked.

1 Answers

Here is on approach. Use an object that has a Boolean variable to keeps up with if the item has been selected.


KeyCode 1

lvMain.getSelectionModel().selectedItemProperty().addListener(((ov, t, t1) - > {
    if (t1 != null) {
        t1.setSelected(true);
    }
}));   

Key Code 2

lvMain.setCellFactory(lv - > new ListCell < MyItem > () {
    @Override
    public void updateItem(MyItem item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
            setText(item.getText());
            if (item.isSelected()) {
                setTextFill(Color.RED);
            }
        }
    }
});

Main

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/**
 *
 * @author blj0011
 */
public class App extends Application {
    @Override
    public void start(Stage primaryStage) {
        ListView<MyItem> lvMain = new ListView();//Create ListView  
        lvMain.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);//Change ListView selection mode to multiple
        ObservableList<MyItem> items = FXCollections.observableArrayList(new MyItem("Julia"), new MyItem("Ian"), new MyItem("Sue"), new MyItem("Matthew"), new MyItem("Hannah"));//ObseravableList that will be used to set the ListView
        lvMain.setItems(items);//Set the ListView's items
        lvMain.setCellFactory(lv -> new ListCell<MyItem>()
        {
            @Override
            public void updateItem(MyItem item, boolean empty)
            {
                super.updateItem(item, empty);
                if (empty) {
                    setText(null);
                    setGraphic(null);
                }
                else {
                    setText(item.getText());
                    if(item.isSelected())
                    {
                        setTextFill(Color.RED);
                    }                    
                }
            }
        });
        lvMain.getSelectionModel().selectedItemProperty().addListener(((ov, t, t1) -> {
            if(t1 != null)
            {
                t1.setSelected(true);
            }
        }));        


        VBox vbox = new VBox();
        vbox.getChildren().addAll(lvMain);


        StackPane root = new StackPane();
        root.getChildren().add(vbox);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

MyItem

/**
 *
 * @author Sed
 */
public class MyItem {
    private String text;
    private boolean selected;

    public MyItem(String text) {
        this.text = text;
        this.selected = false;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean isSelected) {
        this.selected = isSelected;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }    
}

Output

enter image description here


I think a better solution would be to use the ListView's built in multiple selection or have your cells have a ToggleButton. When the ToggleButton is on, change the color of the text. When it is off, change the color back to it's original state.

Related