Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListView - removeAll doesn't work?

Tags:

java

javafx-2

(This is code from the book "JavaFX 2.0 by example" by Carl Dea - the code example is freely available at Apress so I'm sure they don't mind me using it here)

I have example code which works perfectly

package javafx2introbyexample.chapter1.recipe1_11;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/**
 *
 * @author cdea
 */
public class CreatingAndWorkingWithObservableLists extends Application {

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

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Chapter 1-11 Creating and Working with ObservableLists");
        Group root = new Group();
        Scene scene = new Scene(root, 400, 250, Color.WHITE);

        // create a grid pane
        GridPane gridpane = new GridPane();
        gridpane.setPadding(new Insets(5));
        gridpane.setHgap(10);
        gridpane.setVgap(10);

        // candidates label
        Label candidatesLbl = new Label("Candidates");
        GridPane.setHalignment(candidatesLbl, HPos.CENTER);
        gridpane.add(candidatesLbl, 0, 0);

        Label heroesLbl = new Label("Heroes");
        gridpane.add(heroesLbl, 2, 0);
        GridPane.setHalignment(heroesLbl, HPos.CENTER);

        // candidates
        final ObservableList<String> candidates = FXCollections.observableArrayList("Superman",
                "Spiderman",
                "Wolverine",
                "Police", 
                "Fire Rescue", 
                "Soldiers", 
                "Dad & Mom", 
                "Doctor", 
                "Politician", 
                "Pastor", 
                "Teacher");
        final ListView<String> candidatesListView = new ListView<String>(candidates);
        candidatesListView.setPrefWidth(150);
        candidatesListView.setPrefHeight(150);

        gridpane.add(candidatesListView, 0, 1);

        // heros
        final ObservableList<String> heroes = FXCollections.observableArrayList();
        final ListView<String> heroListView = new ListView<String>(heroes);
        heroListView.setPrefWidth(150);
        heroListView.setPrefHeight(150);

        gridpane.add(heroListView, 2, 1);


        // select heroes
        Button sendRightButton = new Button(">");
        sendRightButton.setOnAction(new EventHandler<ActionEvent>() {

            public void handle(ActionEvent event) {
                String potential = candidatesListView.getSelectionModel().getSelectedItem();
                if (potential != null) {
                    candidatesListView.getSelectionModel().clearSelection();
                    candidates.remove(potential);
                    heroes.add(potential);
                }
            }
        });

        // deselect heroes
        Button sendLeftButton = new Button("<");
        sendLeftButton.setOnAction(new EventHandler<ActionEvent>() {

            public void handle(ActionEvent event) {
                String notHero = heroListView.getSelectionModel().getSelectedItem();
                if (notHero != null) {
                    heroListView.getSelectionModel().clearSelection();
                    heroes.remove(notHero);
                    candidates.add(notHero);
                }
            }
        });

        VBox vbox = new VBox(5);
        vbox.getChildren().addAll(sendRightButton,sendLeftButton);

        gridpane.add(vbox, 1, 1);
        GridPane.setConstraints(vbox, 1, 1, 1, 2,HPos.CENTER, VPos.CENTER);

        root.getChildren().add(gridpane);        
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

It is code for moving persons back and forth between two listviews, one at a time. What I want to do is make it possible to select and move several persons in one click.

The relevant excerpts I want to change are:

final ListView<String> candidatesListView = new ListView<String>(candidates);
    candidatesListView.setPrefWidth(150);
    candidatesListView.setPrefHeight(150);

    gridpane.add(candidatesListView, 0, 1);

    // heros
    final ObservableList<String> heroes = FXCollections.observableArrayList();
    final ListView<String> heroListView = new ListView<String>(heroes);

...

// select heroes
    Button sendRightButton = new Button(">");
    sendRightButton.setOnAction(new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            String potential = candidatesListView.getSelectionModel().getSelectedItem();
            if (potential != null) {
                candidatesListView.getSelectionModel().clearSelection();
                candidates.remove(potential);
                heroes.add(potential);
            }
        }
    });

    // deselect heroes
    Button sendLeftButton = new Button("<");
    sendLeftButton.setOnAction(new EventHandler<ActionEvent>() {

        public void handle(ActionEvent event) {
            String notHero = heroListView.getSelectionModel().getSelectedItem();
            if (notHero != null) {
                heroListView.getSelectionModel().clearSelection();
                heroes.remove(notHero);
                candidates.add(notHero);
            }
        }
    });

What I have tried changing:

First I add the following import:

import javafx.scene.control.SelectionMode;

Then I add the lines

candidatesListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
heroListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

beneath the respective declarations of the two lists.

Lastly I change the code of the handling of the eventbutton to

public void handle(ActionEvent event) {
            ObservableList<String> potential = candidatesListView.getSelectionModel().getSelectedItems();
            if (potential != null) {

                System.out.println(potential);
                candidates.removeAll(potential);
                heroes.addAll(potential);
                candidatesListView.getSelectionModel().clearSelection();
            }
        }

That is- I change it to getSelectedItem_s_, then I addAll and removeAll instead of merely adding/removing one person. This just leaves the listView blank when I try to move several people over. What gives?

Ps. I also tried just adding/removing several people one at a time by iterating over the list "potential", but that also gave the wrong result.

like image 826
The Unfun Cat Avatar asked Aug 26 '12 18:08

The Unfun Cat


1 Answers

Unfortunately you've met a bug: http://javafx-jira.kenai.com/browse/RT-24367

The original problem is next: ListView.getSelectionMode() returns part of it's observable list but not the copy. So removing from that list leads to various issues.

Use next code which copies list before removing items from it:

    sendRightButton.setOnAction(new EventHandler<ActionEvent>() {
        public void handle(ActionEvent event) {
            ObservableList<String> potential = 
                FXCollections.observableArrayList( //copy
                    candidatesListView.getSelectionModel().getSelectedItems());
            if (potential != null) {
                heroes.addAll(potential);
                candidates.removeAll(potential);
                candidatesListView.getSelectionModel().clearSelection();
            }
        }
    });
like image 115
Sergey Grinev Avatar answered Oct 12 '22 13:10

Sergey Grinev