JavaFX tableView - переопределение поведения клавиш со стрелками

Я пытаюсь переопределить поведение клавиш со стрелками в табличном представлении JavaFX. Мне удалось это сделать, но теперь у меня проблемы с ScrollPane.

Короче говоря, у меня есть TableView с 3 столбцами (0,1,2) и нажатием клавиши со стрелкой вправо из 2 я хочу, чтобы выбор перемещался на 1 (не 0) в следующую строку. Закончено.

Но теперь я не могу найти способ сбросить панель прокрутки, когда доберусь до последней строки. Со Swing, работая над похожим проектом, я смог это сделать.

Вот мой SSCCE -- не такой уж и короткий, я знаю

package application;

import java.util.ArrayList;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

class TVScrollPane extends ScrollPane {

    public int row;
    public int col;

    public TableView<TableViewRecord> tableView;
        public TableColumn<TableViewRecord, String> tableColumnA;
        public TableColumn<TableViewRecord, String> tableColumnB;
        public TableColumn<TableViewRecord, String> tableColumnC;

    public TVScrollPane() throws Exception {

        /* set columns */
        tableColumnA = new TableColumn<TableViewRecord, String>("column A");
        tableColumnA.setCellValueFactory(new PropertyValueFactory<TableViewRecord, String>("columnA"));
        tableColumnB = new TableColumn<TableViewRecord, String>("column B");
        tableColumnB.setCellValueFactory(new PropertyValueFactory<TableViewRecord, String>("columnB"));
        tableColumnC = new TableColumn<TableViewRecord, String>("column C");
        tableColumnC.setCellValueFactory(new PropertyValueFactory<TableViewRecord, String>("columnC"));

        /* set tableView */
        tableView = new TableView<TableViewRecord>();
        tableView.getColumns().add(tableColumnA);
        tableView.getColumns().add(tableColumnB);
        tableView.getColumns().add(tableColumnC);
        tableView.getSelectionModel().setCellSelectionEnabled(true);

        /* add records */
        ArrayList<TableViewRecord> al = new ArrayList<TableViewRecord>();
        for(int i = 0; i <= 20; ++i) {
            al.add(new TableViewRecord());
        }
        tableView.setItems(FXCollections.observableArrayList(al));

        /* row/column registration */
        if (tableView.getSelectionModel().getSelectedCells().size() != 0) {
            row = tableView.getSelectionModel().getSelectedCells().get(0).getRow();
            col = tableView.getSelectionModel().getSelectedCells().get(0).getColumn();
        }

        /* set on actions */
        tableView.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                if (e.isPrimaryButtonDown()) {
                    if (tableView.getSelectionModel().getSelectedCells().size() != 0) {
                        row = tableView.getSelectionModel().getSelectedCells().get(0).getRow();
                        col = tableView.getSelectionModel().getSelectedCells().get(0).getColumn();
                    }
                }
            }
        });
        tableView.setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent e) {
                if (e.getCode() == KeyCode.RIGHT) {
                    switch (e.getCode()) {
                    case RIGHT:
                        if (row < tableView.getItems().size()) {
                            switch (col) {
                            case 0:        col = 1; break;
                            case 1:        col = 2; break;
                            case 2: ++row; col = 1; break;
                            }
                        }
                        break;
                    default:
                        break;
                    }
                    int r = row;
                    TableColumn<TableViewRecord, ?> tc = tableView.getColumns().get(col);
                    tableView.getSelectionModel().select(r, tc);
                    tableView.getSelectionModel().getSelectedIndex();
                }
            }
        });

        /* set content */
        setContent(tableView);

    }

}

public class Main extends Application {

    @Override
    public void init() {}

    @Override
    public void start(Stage s) {
        try {
            s.setScene(new Scene(new TVScrollPane()));
            s.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

}

А это класс для описания записи tableView: он должен быть общедоступным и находиться в отдельном файле класса:

package application;

public class TableViewRecord {

    private static Integer tvRecordsCounter = 0;

    private String columnA;
    private String columnB;
    private String columnC;

    public String getColumnA() { return columnA; }
    public String getColumnB() { return columnB; }
    public String getColumnC() { return columnC; }

    public TableViewRecord() {
        ++tvRecordsCounter;
        columnA = "a_" + tvRecordsCounter;
        columnB = "b_" + tvRecordsCounter;
        columnC = "c_" + tvRecordsCounter;
    }

}

Кто-нибудь знает, можно ли это исправить?

Заранее большое спасибо.


person dakat    schedule 15.03.2018    source источник
comment
зачем расширять полосу прокрутки? Прокруткой управляет TableViewSkin (точнее, его поток). Что касается реакции по умолчанию (и переопределенной) на нажатие клавиш: это задача поведения - которое скрыто API (даже в fx9 или fx10) и требует некоторой смелости для замены.. без этого поведение, скорее всего, будет мешать чему угодно ты делаешь.   -  person kleopatra    schedule 16.03.2018
comment
вы правы: нет необходимости расширять ScrollPane. Я использовал ScrollPane автоматически, не знал о TableViewSkin. Пока что, даже удалив ScrollPane, мне это не удалось, но я проведу другие тесты и как можно скорее опубликую решение или новый правильный пример без ScrollPane. Спасибо @kleopatra   -  person dakat    schedule 16.03.2018


Ответы (1)


Начиная с предложения kleopatra, я искал способ взаимодействия с менеджером прокрутки Skin непосредственно из TableView и нашел этот хороший метод scrollTo():

https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TableView.html#scrollTo-int-

Вот решение с фиксированной высотой и количеством видимых столбцов

package application3;

import java.util.ArrayList;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

class testTableView extends TableView<TableViewRecord> {

    public static final int TABLE_VIEW_HEIGHT = 350;
    public static final int VISIBLE_ROWS_NUMBER = 13;

    public int row;
    public int col;

    public TableColumn<TableViewRecord, String> tableColumnA;
    public TableColumn<TableViewRecord, String> tableColumnB;
    public TableColumn<TableViewRecord, String> tableColumnC;

    public testTableView() throws Exception {

        /* set columns */
        tableColumnA = new TableColumn<TableViewRecord, String>("column A");
        tableColumnA.setCellValueFactory(new PropertyValueFactory<TableViewRecord, String>("columnA"));
        tableColumnB = new TableColumn<TableViewRecord, String>("column B");
        tableColumnB.setCellValueFactory(new PropertyValueFactory<TableViewRecord, String>("columnB"));
        tableColumnC = new TableColumn<TableViewRecord, String>("column C");
        tableColumnC.setCellValueFactory(new PropertyValueFactory<TableViewRecord, String>("columnC"));

        /* set tableView */
        getColumns().add(tableColumnA);
        getColumns().add(tableColumnB);
        getColumns().add(tableColumnC);
        getSelectionModel().setCellSelectionEnabled(true);

        /* add records */
        ArrayList<TableViewRecord> al = new ArrayList<TableViewRecord>();
        for(int i = 0; i <= 500; ++i) {
            al.add(new TableViewRecord());
        }
        setItems(FXCollections.observableArrayList(al));

        setPrefHeight(TABLE_VIEW_HEIGHT);

        /* row/column registration */
        if (getSelectionModel().getSelectedCells().size() != 0) {
            row = getSelectionModel().getSelectedCells().get(0).getRow();
            col = getSelectionModel().getSelectedCells().get(0).getColumn();
        }

        /* set on actions */
        setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                if (e.isPrimaryButtonDown()) {
                    if (getSelectionModel().getSelectedCells().size() != 0) {
                        row = getSelectionModel().getSelectedCells().get(0).getRow();
                        col = getSelectionModel().getSelectedCells().get(0).getColumn();
                    }
                }
            }
        });
        setOnKeyPressed(new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent e) {
                if (e.getCode() == KeyCode.RIGHT) {
                    switch (e.getCode()) {
                    case RIGHT:
                        if (row < getItems().size()) {
                            switch (col) {
                            case 0:        col = 1; break;
                            case 1:        col = 2; break;
                            case 2: ++row; col = 1; break;
                            }
                        }
                        break;
                    default:
                        break;
                    }
                    int r = row;
                    TableColumn<TableViewRecord, ?> tc = getColumns().get(col);
                    getSelectionModel().select(r, tc);
                    if (r <= VISIBLE_ROWS_NUMBER - 1) {
                        scrollTo(0);
                    } else {
                        scrollTo(r - VISIBLE_ROWS_NUMBER + 1);
                    }
                }
            }
        });

    }

}

public class Main extends Application {

    @Override
    public void init() {}

    @Override
    public void start(Stage s) {
        try {
            s.setScene(new Scene(new testTableView()));
            s.show();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

}
person dakat    schedule 16.03.2018