JavaFX 11 替换 column.impl_setWidth()?

标签 java javafx java-11 javafx-11

我编写了自定义 TableColumn 宽度调整策略。 Java下可以看到它的代码 8/JavaFX 8 here on github .可以看到,在distributeSpaceRatio()等方法中,执行后依赖于TableColumn.impl_setWidth()将列的宽度设置为想要的值我们的计算。

我正在将我的项目迁移到 Java 11/JavaFX 11,方法 impl_setWidth() 已从公众视野中移除。

是否有另一种方法可以告诉表格列设置其宽度?我对任何解决方案都持开放态度,只要它是可靠的并将 with 设置为(或接近)请求的值即可。

以下是我迄今为止尝试过但没有奏效的两个想法:


尝试 1:

这个给出 NoMethodFoundException:

private void setColumnWidth ( TableColumn column, double targetWidth ) {

    try {
        Method method = column.getClass().getDeclaredMethod( "setWidth" );
        method.setAccessible( true );
        Object r = method.invoke( targetWidth );
    } catch ( Exception e ) {
        e.printStackTrace();
    }
}

尝试 2:

这个没有效果:

private void setColumnWidth ( TableColumn column, double targetWidth ) {

    double oldMax = column.getMaxWidth();
    double oldMin = column.getMinWidth();
    double oldPref = column.getPrefWidth();

    column.setMaxWidth( targetWidth );
    column.setMinWidth( targetWidth );
    column.setPrefWidth( targetWidth );

    column.getTableView().refresh();

    column.setPrefWidth( oldPref );
    column.setMinWidth( oldMin );
    column.setMaxWidth( oldMax );
}

尝试 3:

查看 JavaFX 的 TableView.UNCONSTRAINED_RESIZE_POLICY 的源代码,似乎调用的方法最终是 TableColumnBase.doSetWidth(),但这对我来说也不起作用:

private void setColumnWidth ( TableColumn column, double targetWidth ) {

    try {
        Method method = column.getClass().getDeclaredMethod( "doSetWidth" );
        method.setAccessible( true );
        Object r = method.invoke( targetWidth );
    } catch ( Exception e ) {
        e.printStackTrace();
    }
}

尝试 4:

我还尝试使用 this answer 中提供的解决方案执行私有(private)方法,并得到相同的异常——“没有找到名称为 doSetWidth 和参数 [class java.lang.Double] 的方法”。


尝试 5:

我以为这个会起作用,但没有这样的运气。它抛出了“java.lang.NoSuchFieldException:宽度”。但是,当我转到 TableColumnBase 源代码时,我清楚地看到在第 412 行有一个名为 width 的私有(private)字段。不知道为什么会失败。

private void setColumnWidth ( TableColumnBase column, double targetWidth ) {
    try {
        Field widthField = column.getClass().getDeclaredField( "width" );
        widthField.setAccessible( true );
        ReadOnlyDoubleWrapper width = (ReadOnlyDoubleWrapper)widthField.get( column );
        width.set( targetWidth );
    } catch ( Exception e ) {
        e.printStackTrace();
    }
}

尝试 6:

这让我们更接近了,但仍然失败了:

private void setColumnWidth ( TableColumnBase column, double targetWidth ) {
    try {
        Field widthField = column.getClass().getSuperclass().getDeclaredField( "width" );
        widthField.setAccessible( true );
        ReadOnlyDoubleWrapper width = (ReadOnlyDoubleWrapper)widthField.get( column );
        width.set( targetWidth );
    } catch ( Exception e ) {
        e.printStackTrace();
    }
}

java.lang.reflect.InaccessibleObjectException: Unable to make field private javafx.beans.property.ReadOnlyDoubleWrapper javafx.scene.control.TableColumnBase.width accessible: module javafx.controls does not "opens javafx.scene.control" to unnamed module @649dcffc


尝试 7:

private void setColumnWidth ( TableColumn column, double targetWidth ) {
    try {
        Method method = column.getClass().getSuperclass().getDeclaredMethod( "setWidth", double.class );
        method.setAccessible( true );
        method.invoke ( targetWidth );
        //ReadOnlyDoubleWrapper width = (ReadOnlyDoubleWrapper)widthField.get( column );
        //width.set( targetWidth );
    } catch ( Exception e ) {
        e.printStackTrace();
    }
}

java.lang.reflect.InaccessibleObjectException: Unable to make void javafx.scene.control.TableColumnBase.setWidth(double) accessible: module javafx.controls does not "opens javafx.scene.control" to unnamed module @5063f647

最佳答案

根据测试和其他人的帮助,我找到了这个解决方案:

private void setColumnWidth ( TableColumn column, double targetWidth ) {
    try {
        Method method = TableColumnBase.class.getDeclaredMethod( "doSetWidth", double.class );
        method.setAccessible( true );
        method.invoke( column, targetWidth );
    } catch ( NoSuchMethodException | InvocationTargetException | IllegalAccessException e ) {
        e.printStackTrace();
    }
}

此外,JVM 需要使用以下参数调用:

--add-opens javafx.controls/javafx.scene.control=ALL-UNNAMED

关于JavaFX 11 替换 column.impl_setWidth()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53255467/

相关文章:

java - 在 fxml 中显示整个链表

java - 如何在 JavaFx 中检测 tableview 项目计数调整大小?

javafx - 选中复选框时触发JAVAFX事件

java - openjdk11 : Unsupported CipherSuite Exception

docker - 在docker中安装Java时无法找到包

Java 按状态对 jlist 进行排序

java - 创建具有多个客户端的服务器

java - String.split() --- 如何将连续的分隔符视为一个分隔符?

java - 为什么我的 CompletableFuture 代码在 Java 8 中运行而不在 Java 11 中运行?

java - ZonedDateTime 和 Instant.toEpochMilli 的 MIN/MAX 值是多少?