鼠标中键单击 TableView 行选择
TableView row selection on Mouse Middle Button click
目前在TableView中,当我们点击鼠标中键时不会发生行选择。如果我们右击或左击,该行被选中。我正在尝试具有在单击中间按钮时选择行的功能。
我已经知道在 table 行工厂中包含一个事件处理程序可以解决这个问题。但是我有一个自定义 table 视图,其中包含我的应用程序的许多自定义功能。这个自定义 TableView 在我的应用程序中广泛使用。我的主要问题是,我不能要求每个 table 行工厂都包含此修复程序。
我正在寻找一种在更高级别(可能在 TableView 级别)执行此操作的方法,以便行工厂不需要关心它。
非常感谢ideas/help。
下面是我正在努力实现的一个简单示例。
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableRowSelectionOnMiddleButtonDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
for (int i = 0; i < 4; i++) {
persons.add(new Person("First name" + i, "Last Name" + i));
}
CustomTableView<Person> tableView = new CustomTableView<>();
TableColumn<Person, String> fnCol = new TableColumn<>("First Name");
fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
TableColumn<Person, String> lnCol = new TableColumn<>("Last Name");
lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty());
tableView.getColumns().addAll(fnCol, lnCol);
tableView.getItems().addAll(persons);
tableView.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() {
@Override
public TableRow<Person> call(TableView<Person> param) {
return new TableRow<Person>(){
{
/* This will fix my issue, but I dont want each tableView rowfactory to set this behavior.*/
// addEventHandler(MouseEvent.MOUSE_PRESSED,e->{
// getTableView().getSelectionModel().select(getItem());
// });
}
@Override
protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
}
};
}
});
VBox sp = new VBox();
sp.setAlignment(Pos.TOP_LEFT);
sp.getChildren().addAll(tableView);
Scene sc = new Scene(sp);
primaryStage.setScene(sc);
primaryStage.show();
}
public static void main(String... a) {
Application.launch(a);
}
/**
* My custom tableView.
* @param <S>
*/
class CustomTableView<S> extends TableView<S> {
public CustomTableView() {
// A lot of custom behavior is included to this TableView.
}
}
class Person {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
public Person(String fn, String ln) {
setFirstName(fn);
setLastName(ln);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
}
}
任何全局自定义(每个控件)的入口点 functionality/behavior 是控件的外观。更具体地说:用户交互由皮肤的行为控制——不幸的是,它没有进入 public 范围,因此它的 access/modification 需要变脏(如访问内部 classes/methods,部分通过反射)。
假设允许这样的访问,将鼠标交互调整为对中间的反应方式与对 TableCell 的主按钮的反应方式相同的步骤是
- 实施自定义 TableCellSkin
- 反思性地访问它的行为
- 在行为的 inputMap 中找到 mousePressed 处理程序
- 用自定义处理程序替换原始处理程序,用来自主按钮的 mouseEvent 替换来自中间按钮的 mouseEvent
- 通过 css
将自定义 TableCellSkin 设置为默认值
注意:table右边空闲的space中负责处理mouseEvents的TableRowSkin没有把中键分开,所以目前无事可做。如果将来发生变化,简单地应用与 table 单元格相同的技巧。
示例:
public class TableRowCustomMouse extends Application {
public static class CustomMouseTableCellSkin<T, S> extends TableCellSkin<T, S> {
EventHandler<MouseEvent> original;
public CustomMouseTableCellSkin(TableCell<T, S> control) {
super(control);
adjustMouseBehavior();
}
private void adjustMouseBehavior() {
// dirty: reflective access to behavior, use your custom reflective accessor
TableCellBehavior<T, S> behavior =
(TableCellBehavior<T, S>) FXUtils.invokeGetFieldValue(TableCellSkin.class, this, "behavior");
InputMap<TableCell<T, S>> inputMap = behavior.getInputMap();
ObservableList<Mapping<?>> mappings = inputMap.getMappings();
List<Mapping<?>> pressedMapping = mappings.stream()
.filter(mapping -> mapping.getEventType() == MouseEvent.MOUSE_PRESSED)
.collect(Collectors.toList());
if (pressedMapping.size() == 1) {
Mapping<?> originalMapping = pressedMapping.get(0);
original = (EventHandler<MouseEvent>) pressedMapping.get(0).getEventHandler();
if (original != null) {
EventHandler<MouseEvent> replaced = this::replaceMouseEvent;
mappings.remove(originalMapping);
mappings.add(new MouseMapping(MouseEvent.MOUSE_PRESSED, replaced));
}
}
}
private void replaceMouseEvent(MouseEvent e) {
MouseEvent replaced = e;
if (e.isMiddleButtonDown()) {
replaced = new MouseEvent(e.getSource(), e.getTarget(), e.getEventType(),
e.getX(), e.getY(),
e.getScreenX(), e.getScreenY(),
MouseButton.PRIMARY,
e.getClickCount(),
e.isShiftDown(), e.isControlDown(), e.isAltDown(), e.isMetaDown(),
true, false, false,
e.isSynthesized(), e.isPopupTrigger(), e.isStillSincePress(),
null
);
}
original.handle(replaced);
}
}
private Parent createContent() {
TableView<Person> table = new TableView<>(Person.persons());
TableColumn<Person, String> first = new TableColumn("First Name");
first.setCellValueFactory(cc -> cc.getValue().firstNameProperty());
TableColumn<Person, String> last = new TableColumn<>("Last Name");
last.setCellValueFactory(cc -> cc.getValue().lastNameProperty());
table.getColumns().addAll(first, last);
BorderPane content = new BorderPane(table);
return content;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
// load the default css
stage.getScene().getStylesheets()
.add(getClass().getResource("customtablecellskin.css").toExternalForm());
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TableRowCustomMouse.class.getName());
}
具有 TableCell 自定义外观的 css:
.table-cell {
-fx-skin: "<yourpackage>.TableRowCustomMouse$CustomMouseTableCellSkin";
}
接受@kleopatra 的方法作为答案。但是,我的问题的解决方案与@kleopatra 的回答有点不同。但是核心思想还是一样的。
我使用了覆盖 TableCellBehavior 的 doSelect 方法的方法
@Override
protected void doSelect(double x, double y, MouseButton button, int clickCount, boolean shiftDown, boolean shortcutDown) {
MouseButton btn = button;
if (button == MouseButton.MIDDLE) {
btn = MouseButton.PRIMARY;
}
super.doSelect(x, y, btn, clickCount, shiftDown, shortcutDown);
}
下面是解决我的问题的工作演示:
演示类:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableRowSelectionOnMiddleButtonDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
for (int i = 0; i < 4; i++) {
persons.add(new Person("First name" + i, "Last Name" + i));
}
CustomTableView<Person> tableView = new CustomTableView<>();
TableColumn<Person, String> fnCol = new TableColumn<>("First Name");
fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
TableColumn<Person, String> lnCol = new TableColumn<>("Last Name");
lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty());
tableView.getColumns().addAll(fnCol, lnCol);
tableView.getItems().addAll(persons);
tableView.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() {
@Override
public TableRow<Person> call(TableView<Person> param) {
return new TableRow<Person>() {
{
/* This will fix my issue, but I dont want each tableView rowfactory to set this behavior.*/
// addEventHandler(MouseEvent.MOUSE_PRESSED,e->{
// getTableView().getSelectionModel().select(getItem());
// });
}
@Override
protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
}
};
}
});
VBox sp = new VBox();
sp.setAlignment(Pos.TOP_LEFT);
sp.getChildren().addAll(tableView);
Scene sc = new Scene(sp);
sc.getStylesheets().add(this.getClass().getResource("tableRowSelectionOnMiddleButton.css").toExternalForm());
primaryStage.setScene(sc);
primaryStage.show();
}
public static void main(String... a) {
Application.launch(a);
}
/**
* My custom tableView.
*
* @param <S>
*/
class CustomTableView<S> extends TableView<S> {
public CustomTableView() {
// A lot of custom behavior is included to this TableView.
}
}
class Person {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
public Person(String fn, String ln) {
setFirstName(fn);
setLastName(ln);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
}
}
CustomTableCellSkin class:
import com.sun.javafx.scene.control.behavior.TableCellBehavior;
import com.sun.javafx.scene.control.skin.TableCellSkinBase;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.input.MouseButton;
public class CustomTableCellSkin<S, T> extends TableCellSkinBase<TableCell<S, T>, TableCellBehavior<S, T>> {
private final TableColumn<S, T> tableColumn;
public CustomTableCellSkin(TableCell<S, T> tableCell) {
super(tableCell, new CustomTableCellBehavior<S, T>(tableCell));
this.tableColumn = tableCell.getTableColumn();
super.init(tableCell);
}
@Override
protected BooleanProperty columnVisibleProperty() {
return tableColumn.visibleProperty();
}
@Override
protected ReadOnlyDoubleProperty columnWidthProperty() {
return tableColumn.widthProperty();
}
}
class CustomTableCellBehavior<S, T> extends TableCellBehavior<S, T> {
public CustomTableCellBehavior(TableCell<S, T> control) {
super(control);
}
@Override
protected void doSelect(double x, double y, MouseButton button, int clickCount, boolean shiftDown, boolean shortcutDown) {
MouseButton btn = button;
if (button == MouseButton.MIDDLE) {
btn = MouseButton.PRIMARY;
}
super.doSelect(x, y, btn, clickCount, shiftDown, shortcutDown);
}
}
tableRowSelectionOnMiddleButton.css
.table-cell {
-fx-skin: "<package>.CustomTableCellSkin";
}
目前在TableView中,当我们点击鼠标中键时不会发生行选择。如果我们右击或左击,该行被选中。我正在尝试具有在单击中间按钮时选择行的功能。
我已经知道在 table 行工厂中包含一个事件处理程序可以解决这个问题。但是我有一个自定义 table 视图,其中包含我的应用程序的许多自定义功能。这个自定义 TableView 在我的应用程序中广泛使用。我的主要问题是,我不能要求每个 table 行工厂都包含此修复程序。
我正在寻找一种在更高级别(可能在 TableView 级别)执行此操作的方法,以便行工厂不需要关心它。
非常感谢ideas/help。
下面是我正在努力实现的一个简单示例。
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableRowSelectionOnMiddleButtonDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
for (int i = 0; i < 4; i++) {
persons.add(new Person("First name" + i, "Last Name" + i));
}
CustomTableView<Person> tableView = new CustomTableView<>();
TableColumn<Person, String> fnCol = new TableColumn<>("First Name");
fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
TableColumn<Person, String> lnCol = new TableColumn<>("Last Name");
lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty());
tableView.getColumns().addAll(fnCol, lnCol);
tableView.getItems().addAll(persons);
tableView.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() {
@Override
public TableRow<Person> call(TableView<Person> param) {
return new TableRow<Person>(){
{
/* This will fix my issue, but I dont want each tableView rowfactory to set this behavior.*/
// addEventHandler(MouseEvent.MOUSE_PRESSED,e->{
// getTableView().getSelectionModel().select(getItem());
// });
}
@Override
protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
}
};
}
});
VBox sp = new VBox();
sp.setAlignment(Pos.TOP_LEFT);
sp.getChildren().addAll(tableView);
Scene sc = new Scene(sp);
primaryStage.setScene(sc);
primaryStage.show();
}
public static void main(String... a) {
Application.launch(a);
}
/**
* My custom tableView.
* @param <S>
*/
class CustomTableView<S> extends TableView<S> {
public CustomTableView() {
// A lot of custom behavior is included to this TableView.
}
}
class Person {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
public Person(String fn, String ln) {
setFirstName(fn);
setLastName(ln);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
}
}
任何全局自定义(每个控件)的入口点 functionality/behavior 是控件的外观。更具体地说:用户交互由皮肤的行为控制——不幸的是,它没有进入 public 范围,因此它的 access/modification 需要变脏(如访问内部 classes/methods,部分通过反射)。
假设允许这样的访问,将鼠标交互调整为对中间的反应方式与对 TableCell 的主按钮的反应方式相同的步骤是
- 实施自定义 TableCellSkin
- 反思性地访问它的行为
- 在行为的 inputMap 中找到 mousePressed 处理程序
- 用自定义处理程序替换原始处理程序,用来自主按钮的 mouseEvent 替换来自中间按钮的 mouseEvent
- 通过 css 将自定义 TableCellSkin 设置为默认值
注意:table右边空闲的space中负责处理mouseEvents的TableRowSkin没有把中键分开,所以目前无事可做。如果将来发生变化,简单地应用与 table 单元格相同的技巧。
示例:
public class TableRowCustomMouse extends Application {
public static class CustomMouseTableCellSkin<T, S> extends TableCellSkin<T, S> {
EventHandler<MouseEvent> original;
public CustomMouseTableCellSkin(TableCell<T, S> control) {
super(control);
adjustMouseBehavior();
}
private void adjustMouseBehavior() {
// dirty: reflective access to behavior, use your custom reflective accessor
TableCellBehavior<T, S> behavior =
(TableCellBehavior<T, S>) FXUtils.invokeGetFieldValue(TableCellSkin.class, this, "behavior");
InputMap<TableCell<T, S>> inputMap = behavior.getInputMap();
ObservableList<Mapping<?>> mappings = inputMap.getMappings();
List<Mapping<?>> pressedMapping = mappings.stream()
.filter(mapping -> mapping.getEventType() == MouseEvent.MOUSE_PRESSED)
.collect(Collectors.toList());
if (pressedMapping.size() == 1) {
Mapping<?> originalMapping = pressedMapping.get(0);
original = (EventHandler<MouseEvent>) pressedMapping.get(0).getEventHandler();
if (original != null) {
EventHandler<MouseEvent> replaced = this::replaceMouseEvent;
mappings.remove(originalMapping);
mappings.add(new MouseMapping(MouseEvent.MOUSE_PRESSED, replaced));
}
}
}
private void replaceMouseEvent(MouseEvent e) {
MouseEvent replaced = e;
if (e.isMiddleButtonDown()) {
replaced = new MouseEvent(e.getSource(), e.getTarget(), e.getEventType(),
e.getX(), e.getY(),
e.getScreenX(), e.getScreenY(),
MouseButton.PRIMARY,
e.getClickCount(),
e.isShiftDown(), e.isControlDown(), e.isAltDown(), e.isMetaDown(),
true, false, false,
e.isSynthesized(), e.isPopupTrigger(), e.isStillSincePress(),
null
);
}
original.handle(replaced);
}
}
private Parent createContent() {
TableView<Person> table = new TableView<>(Person.persons());
TableColumn<Person, String> first = new TableColumn("First Name");
first.setCellValueFactory(cc -> cc.getValue().firstNameProperty());
TableColumn<Person, String> last = new TableColumn<>("Last Name");
last.setCellValueFactory(cc -> cc.getValue().lastNameProperty());
table.getColumns().addAll(first, last);
BorderPane content = new BorderPane(table);
return content;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
// load the default css
stage.getScene().getStylesheets()
.add(getClass().getResource("customtablecellskin.css").toExternalForm());
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TableRowCustomMouse.class.getName());
}
具有 TableCell 自定义外观的 css:
.table-cell {
-fx-skin: "<yourpackage>.TableRowCustomMouse$CustomMouseTableCellSkin";
}
接受@kleopatra 的方法作为答案。但是,我的问题的解决方案与@kleopatra 的回答有点不同。但是核心思想还是一样的。
我使用了覆盖 TableCellBehavior 的 doSelect 方法的方法
@Override
protected void doSelect(double x, double y, MouseButton button, int clickCount, boolean shiftDown, boolean shortcutDown) {
MouseButton btn = button;
if (button == MouseButton.MIDDLE) {
btn = MouseButton.PRIMARY;
}
super.doSelect(x, y, btn, clickCount, shiftDown, shortcutDown);
}
下面是解决我的问题的工作演示:
演示类:
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableRowSelectionOnMiddleButtonDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
for (int i = 0; i < 4; i++) {
persons.add(new Person("First name" + i, "Last Name" + i));
}
CustomTableView<Person> tableView = new CustomTableView<>();
TableColumn<Person, String> fnCol = new TableColumn<>("First Name");
fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
TableColumn<Person, String> lnCol = new TableColumn<>("Last Name");
lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty());
tableView.getColumns().addAll(fnCol, lnCol);
tableView.getItems().addAll(persons);
tableView.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() {
@Override
public TableRow<Person> call(TableView<Person> param) {
return new TableRow<Person>() {
{
/* This will fix my issue, but I dont want each tableView rowfactory to set this behavior.*/
// addEventHandler(MouseEvent.MOUSE_PRESSED,e->{
// getTableView().getSelectionModel().select(getItem());
// });
}
@Override
protected void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
}
};
}
});
VBox sp = new VBox();
sp.setAlignment(Pos.TOP_LEFT);
sp.getChildren().addAll(tableView);
Scene sc = new Scene(sp);
sc.getStylesheets().add(this.getClass().getResource("tableRowSelectionOnMiddleButton.css").toExternalForm());
primaryStage.setScene(sc);
primaryStage.show();
}
public static void main(String... a) {
Application.launch(a);
}
/**
* My custom tableView.
*
* @param <S>
*/
class CustomTableView<S> extends TableView<S> {
public CustomTableView() {
// A lot of custom behavior is included to this TableView.
}
}
class Person {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
public Person(String fn, String ln) {
setFirstName(fn);
setLastName(ln);
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
}
}
CustomTableCellSkin class:
import com.sun.javafx.scene.control.behavior.TableCellBehavior;
import com.sun.javafx.scene.control.skin.TableCellSkinBase;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.input.MouseButton;
public class CustomTableCellSkin<S, T> extends TableCellSkinBase<TableCell<S, T>, TableCellBehavior<S, T>> {
private final TableColumn<S, T> tableColumn;
public CustomTableCellSkin(TableCell<S, T> tableCell) {
super(tableCell, new CustomTableCellBehavior<S, T>(tableCell));
this.tableColumn = tableCell.getTableColumn();
super.init(tableCell);
}
@Override
protected BooleanProperty columnVisibleProperty() {
return tableColumn.visibleProperty();
}
@Override
protected ReadOnlyDoubleProperty columnWidthProperty() {
return tableColumn.widthProperty();
}
}
class CustomTableCellBehavior<S, T> extends TableCellBehavior<S, T> {
public CustomTableCellBehavior(TableCell<S, T> control) {
super(control);
}
@Override
protected void doSelect(double x, double y, MouseButton button, int clickCount, boolean shiftDown, boolean shortcutDown) {
MouseButton btn = button;
if (button == MouseButton.MIDDLE) {
btn = MouseButton.PRIMARY;
}
super.doSelect(x, y, btn, clickCount, shiftDown, shortcutDown);
}
}
tableRowSelectionOnMiddleButton.css
.table-cell {
-fx-skin: "<package>.CustomTableCellSkin";
}