Reputation: 71
I'm trying to override the behaviour of arrow keys on a JavaFX tableView. I've managed to do it, but now I'm in trouble with the ScrollPane.
In short, I have a TableView with 3 columns (0,1,2) and pressing the right-arrow key from 2 I want the selection to move on 1 (not 0), on the next row. This is done.
But now I can't find a way to reset the Scrollpane when I get to the last row. With Swing, working on a similar project, I was able to do it.
Here is my SSCCE -- not so short, i know
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);
}
}
And this is the class for the tableView record description: it must be public and in a separate class file:
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;
}
}
Does anyone know if it's possible to fix this?
Thank you very much in advance.
Upvotes: 1
Views: 1426
Reputation: 71
Starting from kleopatra's suggestion I looked for a way to interact with the Skin scroll manager directly from TableView and found this nice scrollTo() method:
https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/TableView.html#scrollTo-int-
Here's a solution, with fixed height and number of visible columns
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);
}
}
Upvotes: 1