12

这个想法是:在 N 列的 TableView 上,即使您使用水平滚动条,前 M 列也始终可见。

唯一接近我的要求就是将两个表视图绑定在一起,使它们同步滚动。在我看来,将两张桌子并排放置的想法并不是最好的,因为

1)列的排序在两个表之间部分独立:如果您使用相同的 observableList 行在两个表中排序,但不可能对至少一列不在同一个表上的多列进行排序
2 ) 鼠标滚轮或箭头键没有同步滚动

我知道,我可能可以使用 EventHandlers 和 Listeners 来处理此类问题,但我希望可以只使用一张表。

所以,问题是:TableView 或 TableColumns 上是否有任何可配置的属性来获得我正在寻找的行为?

4

5 回答 5

4

我能够冻结 javafx 表视图中的列。我们需要创建我们的自定义表列类,其中我们将有两个方法setFixedisFixed它们将用于使某些列固定。

除此之外,您需要创建自己的

  1. TableViewskin

  2. TableHeaderRow- 基本上在这个类中你需要重写getRootHeader()方法

  3. NestedTableColumnHeader- 在这个类中覆盖layoutChildren()方法并添加新方法来布局fixedColumns
  4. VirtualFlow
  5. TableView-覆盖createDefaultSkin(),添加新的和booleanProperty showColumnHeader一个ObservableArrayListfixedTableColumn
  6. TableRow- 覆盖createDefaultSkin()
  7. TableRowSkinBase- 处理固定列的覆盖layoutChildren()方法。
于 2016-05-30T06:24:59.720 回答
3

目前没有这样的功能。事实上,即使是操纵滚动条和响应滚动条事件也是有问题的。我能想到的两个选择:

选项 #1 - 多表

创建一个包含两个表格和两个滚动条的新布局,如下面的 FXML 片段所示:

<BorderPane prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
  <bottom>
    <ScrollBar fx:id="hScroll" />
  </bottom>
  <center>
    <HBox fx:id="varTable" prefHeight="100.0" prefWidth="200.0">
      <children>
        <TableView fx:id="fixedTable" prefHeight="200.0" prefWidth="200.0">
          <columns>
            <TableColumn prefWidth="75.0" text="Column X" />
            <TableColumn prefWidth="75.0" text="Column X" />
          </columns>
        </TableView>
        <TableView prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS">
          <columns>
            <TableColumn prefWidth="75.0" text="Column X" />
            <TableColumn prefWidth="75.0" text="Column X" />
          </columns>
        </TableView>
      </children>
    </HBox>
  </center>
  <right>
    <ScrollBar fx:id="vScroll" orientation="VERTICAL" />
  </right>
</BorderPane>

请注意,第二个表设置了 HBox.hgrow="ALWAYS"。

编写一个函数来定位 TableView 中的滚动条:

private static final ScrollBar getScrollBar(final TableView<?> tableView) {
  for (final VirtualFlow virtualFlow: Nodes.filter(Nodes.descendents(tableView, 2), VirtualFlow.class)) {
     for (final Node subNode: virtualFlow.getChildrenUnmodifiable()) {
        if (subNode instanceof ScrollBar && ((ScrollBar)subNode).getOrientation() == Orientation.VERTICAL) {
           return (ScrollBar)subNode;
        }
     }
  }

  return null;

}

使用它来定位两个垂直滚动条并将它们的属性(如最小值、最大值、值等)绑定到您自己的垂直滚动条,然后隐藏原始滚动条。您还需要设置 managed=false 以便它们不会占用布局中的空间。

找到并隐藏水平滚动条并将“移动”表水平滚动条的属性绑定到您自己的水平滚动条。

在等待修复此 Jira时,我们成功地使用此技术将两个表与单个滚动条链接起来。

选项 #2 - 编写您自己的 TableViewSkin 下载 JavaFx 源代码以查看他们对皮肤的作用,然后您可以编写一个完整的自定义皮肤或编写一个包装两个常规皮肤的皮肤,并以与上面的选项 #1 类似的方式实现

于 2013-08-29T12:36:10.843 回答
2

所以,问题是:TableView 或 TableColumns 上是否有任何可配置的属性来获得我正在寻找的行为?

显然不是,但是在 JavaFX Jira 上有一个针对此行为的功能请求(您需要注册才能查看它):

https://javafx-jira.kenai.com/browse/RT-19454

我建议你投票给它。:^)

于 2013-08-28T20:36:43.677 回答
1

JavaFX 没有这个功能。查看ControlsFX的电子表格视图。

于 2015-01-18T05:49:26.867 回答
0

代码使用 javafx 11

import javafx.application.Platform;
import javafx.scene.AccessibleAttribute;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TableCell;
import javafx.scene.layout.Region;

public class LockedTableCell<T, S> extends TableCell<T, S> {
        
    {

        Platform.runLater(() -> {

            try {
                ScrollBar scrollBar = (ScrollBar) getTableView()
                            .queryAccessibleAttribute(AccessibleAttribute.HORIZONTAL_SCROLLBAR);
                // set fx:id of TableColumn and get region of column header by #id
                Region headerNode = (Region) getTableView().lookup("#" + getTableColumn().getId());
                scrollBar.valueProperty().addListener((ob, o, n) -> {
                    double doubleValue = n.doubleValue();
                    
                    // move header and cell with translateX & bring it front
                    headerNode.setTranslateX(doubleValue);
                    headerNode.toFront();

                    this.setTranslateX(doubleValue);
                    this.toFront();

                });
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        });

    }

}

使用它(前 M 列)

tableColumnInstance1.setCellFactory(param -> new LockedTableCell<>() {...});
tableColumnInstance2.setCellFactory(param -> new LockedTableCell<>() {...});
...
tableColumnInstanceM.setCellFactory(param -> new LockedTableCell<>() {...});



于 2021-09-16T15:10:22.340 回答