防止 TableColumn 仅由用户调整大小
Prevent TableColumn from being resized by user only
有没有办法阻止 TableView
中的任何或至少所有 JavaFX TableColumn
被用户调整大小,同时仍然允许调整大小策略起作用?
存在 TableColumn::setResizable
,但在阻止用户调整 TableColumn
大小的同时,它还会阻止调整大小策略调整 TableColumn
的大小。
一个快速的解决方案可能是在 table header 行上为鼠标拖动添加事件过滤器。创建自定义 tableView 并在 header 行上添加事件过滤器,如下所示:
class CustomTableView<S> extends TableView<S>{
private Node headerRow;
@Override
protected void layoutChildren() {
super.layoutChildren();
if(headerRow ==null){
headerRow = (Region) lookup("TableHeaderRow");
headerRow.addEventFilter(MouseEvent.MOUSE_DRAGGED, MouseEvent::consume);
}
}
}
显然副作用是您现在无法重新对齐列。如果您非常特定于仅调整大小,则查找负责调整大小的节点并在其上而不是在整个 header 行上添加过滤器。
下面是一个快速运行的演示,它禁用列大小调整和重新对齐,同时仍然允许调整大小策略。
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
public class TableResizeRestrictionDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
persons.add(new Person("Harry","John","LS"));
persons.add(new Person("Mary","King","MS"));
persons.add(new Person("Don","Bon","CAT"));
persons.add(new Person("Pink","Wink","IND"));
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());
TableColumn<Person, String> cityCol = new TableColumn<>("City");
cityCol.setCellValueFactory(param -> param.getValue().cityProperty());
tableView.getColumns().addAll(fnCol, lnCol, cityCol);
tableView.setItems(persons);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
Scene sc = new Scene(tableView);
primaryStage.setScene(sc);
primaryStage.show();
}
class Person{
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
private StringProperty city = new SimpleStringProperty();
public Person(String fn, String ln, String cty){
setFirstName(fn);
setLastName(ln);
setCity(cty);
}
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);
}
public String getCity() {
return city.get();
}
public StringProperty cityProperty() {
return city;
}
public void setCity(String city) {
this.city.set(city);
}
}
class CustomTableView<S> extends TableView<S>{
private Node headerRow;
@Override
protected void layoutChildren() {
super.layoutChildren();
if(headerRow ==null){
headerRow = (Region) lookup("TableHeaderRow");
headerRow.addEventFilter(MouseEvent.MOUSE_DRAGGED, MouseEvent::consume);
}
}
}
}
Update :: 查看NestedTableColumnHeader class中的源代码后,负责调整大小的节点确实是Rectangle(s)。不幸的是,没有为该矩形设置样式 class。因此假设 HeaderRow 中的所有矩形都是为了调整大小,我们查找所有 Rectangle 节点并设置事件过滤器。
内部 PRESSED-DRAGGED-RELEASED 个处理程序用于调整大小,ENTER-EXIT 个处理程序用于更改光标。因此,与其为 5 种类型的事件设置过滤器,不如为一个超级事件设置过滤器 MouseEvent.ANY。这也将解决更改光标的问题。
class CustomTableView<S> extends TableView<S> {
private final EventHandler<MouseEvent> consumeEvent = MouseEvent::consume;
@Override
protected void layoutChildren() {
super.layoutChildren();
final Set<Node> dragRects = lookup("TableHeaderRow").lookupAll("Rectangle");
for (Node dragRect : dragRects) {
dragRect.removeEventFilter(MouseEvent.ANY, consumeEvent);
dragRect.addEventFilter(MouseEvent.ANY, consumeEvent);
}
}
}
不保留矩形引用(如演示中的 HeaderRow)的原因是,每次重新对齐列时,都会生成一组新的矩形。所以你不能依赖任何 Rectangle 参考。为了避免重复的过滤器,我们创建了一个处理程序引用,首先我们删除然后添加处理程序。
有没有办法阻止 TableView
中的任何或至少所有 JavaFX TableColumn
被用户调整大小,同时仍然允许调整大小策略起作用?
存在 TableColumn::setResizable
,但在阻止用户调整 TableColumn
大小的同时,它还会阻止调整大小策略调整 TableColumn
的大小。
一个快速的解决方案可能是在 table header 行上为鼠标拖动添加事件过滤器。创建自定义 tableView 并在 header 行上添加事件过滤器,如下所示:
class CustomTableView<S> extends TableView<S>{
private Node headerRow;
@Override
protected void layoutChildren() {
super.layoutChildren();
if(headerRow ==null){
headerRow = (Region) lookup("TableHeaderRow");
headerRow.addEventFilter(MouseEvent.MOUSE_DRAGGED, MouseEvent::consume);
}
}
}
显然副作用是您现在无法重新对齐列。如果您非常特定于仅调整大小,则查找负责调整大小的节点并在其上而不是在整个 header 行上添加过滤器。
下面是一个快速运行的演示,它禁用列大小调整和重新对齐,同时仍然允许调整大小策略。
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
public class TableResizeRestrictionDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
ObservableList<Person> persons = FXCollections.observableArrayList();
persons.add(new Person("Harry","John","LS"));
persons.add(new Person("Mary","King","MS"));
persons.add(new Person("Don","Bon","CAT"));
persons.add(new Person("Pink","Wink","IND"));
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());
TableColumn<Person, String> cityCol = new TableColumn<>("City");
cityCol.setCellValueFactory(param -> param.getValue().cityProperty());
tableView.getColumns().addAll(fnCol, lnCol, cityCol);
tableView.setItems(persons);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
Scene sc = new Scene(tableView);
primaryStage.setScene(sc);
primaryStage.show();
}
class Person{
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
private StringProperty city = new SimpleStringProperty();
public Person(String fn, String ln, String cty){
setFirstName(fn);
setLastName(ln);
setCity(cty);
}
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);
}
public String getCity() {
return city.get();
}
public StringProperty cityProperty() {
return city;
}
public void setCity(String city) {
this.city.set(city);
}
}
class CustomTableView<S> extends TableView<S>{
private Node headerRow;
@Override
protected void layoutChildren() {
super.layoutChildren();
if(headerRow ==null){
headerRow = (Region) lookup("TableHeaderRow");
headerRow.addEventFilter(MouseEvent.MOUSE_DRAGGED, MouseEvent::consume);
}
}
}
}
Update :: 查看NestedTableColumnHeader class中的源代码后,负责调整大小的节点确实是Rectangle(s)。不幸的是,没有为该矩形设置样式 class。因此假设 HeaderRow 中的所有矩形都是为了调整大小,我们查找所有 Rectangle 节点并设置事件过滤器。
内部 PRESSED-DRAGGED-RELEASED 个处理程序用于调整大小,ENTER-EXIT 个处理程序用于更改光标。因此,与其为 5 种类型的事件设置过滤器,不如为一个超级事件设置过滤器 MouseEvent.ANY。这也将解决更改光标的问题。
class CustomTableView<S> extends TableView<S> {
private final EventHandler<MouseEvent> consumeEvent = MouseEvent::consume;
@Override
protected void layoutChildren() {
super.layoutChildren();
final Set<Node> dragRects = lookup("TableHeaderRow").lookupAll("Rectangle");
for (Node dragRect : dragRects) {
dragRect.removeEventFilter(MouseEvent.ANY, consumeEvent);
dragRect.addEventFilter(MouseEvent.ANY, consumeEvent);
}
}
}
不保留矩形引用(如演示中的 HeaderRow)的原因是,每次重新对齐列时,都会生成一组新的矩形。所以你不能依赖任何 Rectangle 参考。为了避免重复的过滤器,我们创建了一个处理程序引用,首先我们删除然后添加处理程序。