Select first/last clears anchor information - MultipleSelectionModel

95 Views Asked by At

I have table with table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);. I need to implement go last/first row of a TableView. I used table.scrollTo(ind); table.getSelectionModel().clearAndSelect(ind). This would scroll to first row and select it. But If I try to select numerous rows (using mouse right button with + SHIFT) It doesn't select range of rows between first row and the one pressed but it simply set anchor at the selected row.

What I've observed so far:

  1. From pseudoclass css information. First row is selected,focused - which is exprected.
  2. table.getSelectionModel().selectedIndexProperty() table.getSelectionModel().getSelectedIndices() shows 0 and [0] respective - which is expected
  3. Row is not really selected - table is no longer focused so I got grey not blue row. But even if I call table.requestFocus() at any time and use PlatformUtil.runLater() It doesn't change anything. So I assume this has nothing to do with table focus.

Any Ideas howto (from code) select first row and make such situation that after pressing mouse button on other row with SHIFT I got multiple selection?

Sample application. See createSelectionControl() -> Button("|<")

import javafx.application.Application;
import javafx.beans.binding.StringBinding;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;

/**
 * table with standard cell editor
 */
public class SelectionTableApp extends Application {
    private static String ID_DESC_LABEL = "descLabel";
    private TableView<Person> table;
    private static final Person PERSON_STASZEK = new Person("Stanislaw",
            "Czerkawski", "[email protected]");
    private final ObservableList<Person> data = FXCollections
            .observableArrayList(
                    new Person("Jacob", "Smith", "[email protected]"),
                    new Person("Isabella", "Johnson",
                            "[email protected]"),
                    new Person("Ethan", "Williams",
                            "[email protected]"),
                    new Person("Emma", "Jones", "[email protected]"),
                    new Person("Michael", "Brown", "[email protected]"),
                    PERSON_STASZEK);
    private TableColumn firstNameCol;
    private TableColumn lastNameCol;
    private TableColumn emailCol;

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

    @Override
    public void start(Stage stage) {
        addData();
        BorderPane root = new BorderPane();
        Scene scene = new Scene(root);
        scene.getStylesheets().add("ks/javafx/table/def/1.css");
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(550);

        final Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));
        createTable();
        configureTable(table);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(createAddPersonControl(),
                createInfoControl(), createSelectionControl());

        root.setTop(label);
        root.setCenter(table);
        root.setBottom(vbox);

        stage.setScene(scene);
        stage.show();

        scene.focusOwnerProperty().addListener((obs, o, n) -> {
            System.out.println("SelectionTableApp.start()=" + n);
        });
    }

    private void addData() {
        for (int i = 0; i < 100; i++) {
            data.add(new Person("first-" + i, "name-" + i, "mail-" + i));
        }
    }

    private void configureTable(TableView<Person> table) {
        table.setEditable(false);
        table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    }

    private void createTable() {
        table = new TableView<Person>();

        firstNameCol = new TableColumn("First Name");
        firstNameCol.setMinWidth(100);
        firstNameCol
                .setCellValueFactory(new PropertyValueFactory<Person, String>(
                        "firstName"));
        firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
        firstNameCol
                .setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {
                    @Override
                    public void handle(CellEditEvent<Person, String> t) {
                        System.out.println("onEditCommit");
                        t.getTableView().getItems()
                                .get(t.getTablePosition().getRow())
                                .setFirstName(t.getNewValue());
                    }
                });

        lastNameCol = new TableColumn("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol
                .setCellValueFactory(new PropertyValueFactory<Person, String>(
                        "lastName"));
        lastNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
        lastNameCol
                .setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {
                    @Override
                    public void handle(CellEditEvent<Person, String> t) {
                        System.out.println("onEditCommit");
                        t.getTableView().getItems()
                                .get(t.getTablePosition().getRow())
                                .setLastName(t.getNewValue());
                    }
                });

        emailCol = new TableColumn("Email");
        emailCol.setMinWidth(200);
        emailCol.setCellValueFactory(new PropertyValueFactory<Person, String>(
                "email"));
        emailCol.setCellFactory(TextFieldTableCell.forTableColumn());
        emailCol.setOnEditCommit(new EventHandler<CellEditEvent<Person, String>>() {
            @Override
            public void handle(CellEditEvent<Person, String> t) {
                System.out.println("onEditCommit");
                t.getTableView().getItems().get(t.getTablePosition().getRow())
                        .setEmail(t.getNewValue());
            }
        });

        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
    }

    private Node createAddPersonControl() {
        final TextField addFirstName = new TextField();
        addFirstName.setPromptText("First Name");
        addFirstName.setMaxWidth(firstNameCol.getPrefWidth());
        final TextField addLastName = new TextField();
        addLastName.setMaxWidth(lastNameCol.getPrefWidth());
        addLastName.setPromptText("Last Name");
        final TextField addEmail = new TextField();
        addEmail.setMaxWidth(emailCol.getPrefWidth());
        addEmail.setPromptText("Email");

        final Button addButton = new Button("Add");
        addButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent e) {
                data.add(new Person(addFirstName.getText(), addLastName
                        .getText(), addEmail.getText()));
                addFirstName.clear();
                addLastName.clear();
                addEmail.clear();
            }
        });
        final HBox hb = new HBox();
        hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton);
        hb.setSpacing(3);
        return hb;
    }

    private Node createSelectionControl() {
        Button goFist = new Button("|<");
        goFist.setOnAction(e -> {
            int ind = 0;
            table.scrollTo(ind);
            table.getSelectionModel().clearAndSelect(ind);

            // Bounds local = table.getBoundsInLocal();
            // Bounds sceneBounds = table.localToScene(local);
            // Bounds screenBounds = table.localToScreen(local);
            // System.out.println("SelectionTableApp.createSelectionControl()="
            // +
            // local);
            // System.out.println("SelectionTableApp.createSelectionControl()="
            // +
            // sceneBounds);
            // System.out.println("SelectionTableApp.createSelectionControl()="
            // +
            // screenBounds);
            //
            // double sceneX = sceneBounds.getMinX() + 10;
            // double sceneY = sceneBounds.getMinY() + 10;
            // double screenX = screenBounds.getMinX() + 10;
            // double screenY = screenBounds.getMinX() + 10;
            //
            // sceneX = 21;
            // sceneY = 59;
            // screenX = 760;
            // screenY = 287;
            //
            // MouseEvent me = new MouseEvent(MouseEvent.MOUSE_PRESSED, sceneX,
            // sceneY, screenX, screenY,
            // MouseButton.PRIMARY, 1, false, false, false, false, true, false,
            // false, true, false, false,
            // null);
            // MouseEvent.fireEvent(table, me);
            // me = new MouseEvent(MouseEvent.MOUSE_RELEASED, sceneX, sceneY,
            // screenX, screenY,
            // MouseButton.PRIMARY, 1, false, false, false, false, true, false,
            // false, true, false, false,
            // null);
            // MouseEvent.fireEvent(table, me);
            // me = new MouseEvent(MouseEvent.MOUSE_CLICKED, sceneX, sceneY,
            // screenX, screenY, MouseButton.PRIMARY,
            // 1, false, false, false, false, true, false, false, true, false,
            // false, null);
            // MouseEvent.fireEvent(table, me);
            // Event.fireEvent(YOUR NODE, new
            // MouseEvent(MouseEvent.MOUSE_CLICKED,
            // 0, 0, 0, 0, MouseButton.PRIMARY, 1, true, true, true, true, true,
            // true, true, true, true, true, null));
            // table.fireEvent(event);
        });
        Button goLast = new Button(">|");
        goLast.setOnAction(e -> {
            int ind = table.getItems().size() - 1;
            table.getSelectionModel().clearAndSelect(ind);
            table.scrollTo(ind);
        });
        HBox hbox = new HBox(goFist, goLast);
        return hbox;
    }

    private Node createInfoControl() {
        GridPane grid = new GridPane();
        grid.setHgap(10);
        grid.setVgap(5);

        StringBinding binding = new StringBinding() {
            {
                bind(table.editingCellProperty());
            }

            @Override
            protected String computeValue() {
                TablePosition<Person, ?> pos = table.getEditingCell();
                String ret = (pos != null) ? (pos.getRow() + "." + pos
                        .getColumn()) : "";
                return ret;
            }
        };
        addLabelAndVal("editingCell:", binding, grid, 0, 0);

        addLabelAndVal("table.focused:", table.focusedProperty().asString(),
                grid, 0, 2);
        addLabelAndVal("selM.selected:", table.getSelectionModel()
                .selectedIndexProperty().asString(), grid, 1, 0);
        addLabelAndVal("needsLayout:", table.needsLayoutProperty().asString(),
                grid, 1, 2);

        addLabelAndVal("selected", table.getSelectionModel()
                .getSelectedIndices(), grid, 2, 0);
        return grid;
    }

    private void addLabelAndVal(String labelTxt, ObservableValue<String> val,
            GridPane grid, int rowInd, int colInd) {
        Label lab = new Label(labelTxt);
        lab.setId(ID_DESC_LABEL);
        Label valLab = new Label();
        valLab.textProperty().bind(val);
        grid.add(lab, colInd, rowInd);
        grid.add(valLab, colInd + 1, rowInd);
    }

    private void addLabelAndVal(String labelTxt,
            final ObservableList<Integer> val, GridPane grid, int rowInd,
            int colInd) {
        Label lab = new Label(labelTxt);
        lab.setId(ID_DESC_LABEL);
        Label valLab = new Label();

        val.addListener(new ListChangeListener<Integer>() {
            @Override
            public void onChanged(
                    javafx.collections.ListChangeListener.Change<? extends Integer> c) {
                valLab.setText(val.toString());
            }
        });

        valLab.setText(val.toString());
        grid.add(lab, colInd, rowInd);
        grid.add(valLab, colInd + 1, rowInd);
    }

}

and my model:

import javafx.beans.property.SimpleStringProperty;

public class Person {

    private final SimpleStringProperty firstName;
    private final SimpleStringProperty lastName;
    private final SimpleStringProperty email;

    public Person(String fName, String lName, String email) {
        this.firstName = new SimpleStringProperty(fName);
        this.lastName = new SimpleStringProperty(lName);
        this.email = new SimpleStringProperty(email);
    }

    public String getFirstName() {
        return firstName.get();
    }

    public void setFirstName(String fName) {
        firstName.set(fName);
    }

    public String getLastName() {
        return lastName.get();
    }

    public void setLastName(String fName) {
        lastName.set(fName);
    }

    public String getEmail() {
        return email.get();
    }

    public void setEmail(String fName) {
        email.set(fName);
    }
}
0

There are 0 best solutions below