Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX 11 Replacement for column.impl_setWidth()?

I wrote a custom TableColumn width resize policy. You can see its code under Java 8 / JavaFX 8 here on github. As you can see, in the method distributeSpaceRatio() and other places, it depends on TableColumn.impl_setWidth() to set the width of the columns to the desired value after doing our calculations.

I am migrating my project to Java 11 / JavaFX 11 and the method impl_setWidth() has been removed from public view.

Is there another method to tell a table column to set its width? I'm open to any solution as long as it is reliable and sets the with to (or close to) the requested value.

Here are two ideas I've tried so far that didn't work:


Attempt 1:

This one gives 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();
    }
}

Attempt 2:

This one has no effect:

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 );
}

Attempt 3:

Looking at the source for JavaFX's TableView.UNCONSTRAINED_RESIZE_POLICY, it seems the method invoked is ultimately TableColumnBase.doSetWidth(), however that also doesn't work for me here:

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();
    }
}

Attempt 4:

I also tried using the solution provided in this answer to execute a private method, and got the same exception -- "There are no methods found with name doSetWidth and params [class java.lang.Double]".


Attempt 5:

I thought this one was going to work, but no such luck. It threw a "java.lang.NoSuchFieldException: width". However, when I go to the TableColumnBase source code, I clearly see on line 412 a private field called width. Not sure why this fails.

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();
    }
}

Attempt 6:

This got us closer, but still failed:

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


Attempt 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

like image 205
JoshuaD Avatar asked Oct 16 '22 10:10

JoshuaD


1 Answers

Based on testing and the help of others, I found this solution:

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();
    }
}

In addition, the JVM needs to be invoked with the following arguments:

--add-opens javafx.controls/javafx.scene.control=ALL-UNNAMED
like image 99
JoshuaD Avatar answered Oct 21 '22 04:10

JoshuaD