有没有办法改变 TableView 焦点可遍历行为?
Is there a way for changing TableView focus traversable behavior?
我有一个简单的 TableView,它具有从右到左的节点方向和 setCellSelectionEnabled(true)。现在,当在 table 上按下右箭头键时,可遍历的焦点作用在相反的一侧,因此左侧的单元格将被选中。另一方面也是如此。当按下左箭头键时,将选择右侧的单元格。出于区域目的,TableView 的节点方向 属性 必须保持 RTL。那么我该如何解决这个问题呢?
这是 TableView FXML 代码:
<TableView fx:id="table" editable="true" layoutX="97.0" layoutY="170.0" nodeOrientation="RIGHT_TO_LEFT" prefHeight="400.0" prefWidth="816.0" AnchorPane.bottomAnchor="25.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="121.0">
<placeholder>
<Label text="داده ای یافت نشد :(" />
</placeholder>
<columns>
<TableColumn fx:id="numberColumn" maxWidth="120.0" minWidth="80.0" text="ردیف" />
<TableColumn fx:id="nameColumn" maxWidth="400.0" minWidth="300.0" prefWidth="300.0" text="نام ماده اولیه" />
<TableColumn fx:id="categoryColumn" maxWidth="300.0" minWidth="150.0" prefWidth="150.0" text="دسته بندی" />
<TableColumn fx:id="priceColumn" maxWidth="300.0" minWidth="220.0" prefWidth="220.0" text="قیمت هر کیلوگرم(ریال)" />
<TableColumn fx:id="unitColumn" maxWidth="200.0" minWidth="100.0" prefWidth="100.0" text="واحد" />
<TableColumn fx:id="numberOfUsesColumn" maxWidth="120.0" minWidth="120.0" prefWidth="120.0" text="دفعات استفاده" />
<TableColumn fx:id="deleteRowColumn" maxWidth="90.0" minWidth="90.0" prefWidth="90.0" resizable="false" text="حذف سطر" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
在 table 导航中不遵守 RTL 是 bug that's fixed in openjfx15。
在那之前我们可以四处乱窜(假设我们可以变脏,即使用反射访问 TableViewSkin 中的私有字段,使用内部 api 和实现细节;)
- 获取 table 的皮肤(通常在 table 显示后可用)并访问其内部字段行为
- 从行为的输入映射中获取 left/right 键映射并将其删除
- 使用它们各自的事件处理程序交叉连接密钥到处理程序并添加它们
在代码中,类似(此处仅用于 left/right,需要对带有修饰符的映射执行相同的操作):
protected void hackNavigation(TableView<?> table) {
TableViewSkin<?> skin = (TableViewSkin<?>) table.getSkin();
// access private field reflectively
// use your own favorite utility method :)
TableViewBehavior<?> behavior = (TableViewBehavior<?>)
FXUtils.invokeGetFieldValue(TableViewSkin.class, skin, "behavior");
// access mappings
ObservableList<Mapping<?>> mappings = behavior.getInputMap().getMappings();
// lookup the original mappings for left/right
KeyBinding leftBinding = new KeyBinding(KeyCode.LEFT);
KeyBinding rightBinding = new KeyBinding(KeyCode.RIGHT);
KeyMapping leftMapping = getMapping(mappings, leftBinding);
KeyMapping rightMapping = getMapping(mappings, rightBinding);
// remove the original mappings
mappings.removeAll(leftMapping, rightMapping);
// create new mappings with the opposite event handlers and add them
KeyMapping replaceRight = new KeyMapping(rightBinding, leftMapping.getEventHandler());
KeyMapping replaceLeft = new KeyMapping(leftBinding, rightMapping.getEventHandler());
mappings.addAll(replaceRight, replaceLeft);
}
/**
* Utility method to get hold of a KeyMapping for a binding.
* Note: only use if certain that it is contained, or guard against failure
*/
protected KeyMapping getMapping(ObservableList<Mapping<?>> mappings, KeyBinding keyBinding) {
Optional<KeyMapping> opt = mappings.stream()
.filter(mapping -> mapping instanceof KeyMapping)
.map(mapping -> (KeyMapping) mapping)
.filter(keyMapping -> keyMapping.getMappingKey().equals(keyBinding))
.findAny()
;
return opt.get();
}
// useage
stage.show();
hackNavigation(myTable);
我有一个简单的 TableView,它具有从右到左的节点方向和 setCellSelectionEnabled(true)。现在,当在 table 上按下右箭头键时,可遍历的焦点作用在相反的一侧,因此左侧的单元格将被选中。另一方面也是如此。当按下左箭头键时,将选择右侧的单元格。出于区域目的,TableView 的节点方向 属性 必须保持 RTL。那么我该如何解决这个问题呢?
这是 TableView FXML 代码:
<TableView fx:id="table" editable="true" layoutX="97.0" layoutY="170.0" nodeOrientation="RIGHT_TO_LEFT" prefHeight="400.0" prefWidth="816.0" AnchorPane.bottomAnchor="25.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="121.0">
<placeholder>
<Label text="داده ای یافت نشد :(" />
</placeholder>
<columns>
<TableColumn fx:id="numberColumn" maxWidth="120.0" minWidth="80.0" text="ردیف" />
<TableColumn fx:id="nameColumn" maxWidth="400.0" minWidth="300.0" prefWidth="300.0" text="نام ماده اولیه" />
<TableColumn fx:id="categoryColumn" maxWidth="300.0" minWidth="150.0" prefWidth="150.0" text="دسته بندی" />
<TableColumn fx:id="priceColumn" maxWidth="300.0" minWidth="220.0" prefWidth="220.0" text="قیمت هر کیلوگرم(ریال)" />
<TableColumn fx:id="unitColumn" maxWidth="200.0" minWidth="100.0" prefWidth="100.0" text="واحد" />
<TableColumn fx:id="numberOfUsesColumn" maxWidth="120.0" minWidth="120.0" prefWidth="120.0" text="دفعات استفاده" />
<TableColumn fx:id="deleteRowColumn" maxWidth="90.0" minWidth="90.0" prefWidth="90.0" resizable="false" text="حذف سطر" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
在 table 导航中不遵守 RTL 是 bug that's fixed in openjfx15。
在那之前我们可以四处乱窜(假设我们可以变脏,即使用反射访问 TableViewSkin 中的私有字段,使用内部 api 和实现细节;)
- 获取 table 的皮肤(通常在 table 显示后可用)并访问其内部字段行为
- 从行为的输入映射中获取 left/right 键映射并将其删除
- 使用它们各自的事件处理程序交叉连接密钥到处理程序并添加它们
在代码中,类似(此处仅用于 left/right,需要对带有修饰符的映射执行相同的操作):
protected void hackNavigation(TableView<?> table) {
TableViewSkin<?> skin = (TableViewSkin<?>) table.getSkin();
// access private field reflectively
// use your own favorite utility method :)
TableViewBehavior<?> behavior = (TableViewBehavior<?>)
FXUtils.invokeGetFieldValue(TableViewSkin.class, skin, "behavior");
// access mappings
ObservableList<Mapping<?>> mappings = behavior.getInputMap().getMappings();
// lookup the original mappings for left/right
KeyBinding leftBinding = new KeyBinding(KeyCode.LEFT);
KeyBinding rightBinding = new KeyBinding(KeyCode.RIGHT);
KeyMapping leftMapping = getMapping(mappings, leftBinding);
KeyMapping rightMapping = getMapping(mappings, rightBinding);
// remove the original mappings
mappings.removeAll(leftMapping, rightMapping);
// create new mappings with the opposite event handlers and add them
KeyMapping replaceRight = new KeyMapping(rightBinding, leftMapping.getEventHandler());
KeyMapping replaceLeft = new KeyMapping(leftBinding, rightMapping.getEventHandler());
mappings.addAll(replaceRight, replaceLeft);
}
/**
* Utility method to get hold of a KeyMapping for a binding.
* Note: only use if certain that it is contained, or guard against failure
*/
protected KeyMapping getMapping(ObservableList<Mapping<?>> mappings, KeyBinding keyBinding) {
Optional<KeyMapping> opt = mappings.stream()
.filter(mapping -> mapping instanceof KeyMapping)
.map(mapping -> (KeyMapping) mapping)
.filter(keyMapping -> keyMapping.getMappingKey().equals(keyBinding))
.findAny()
;
return opt.get();
}
// useage
stage.show();
hackNavigation(myTable);