首页 文章

tableview中的javafx列自动调整大小

提问于
浏览
32

afaik javafx中的TableView有两个列调整大小策略:CONSTRAINED_RESIZE_POLICY和UNCONSTRAINED_RESIZE_POLICY,但是我想要调整列的大小以适应他们的单元格内容我认为这是其他平台中的一个简单问题(如C#中的datagridview)但无法解析

10 回答

  • 5

    3年后我再次回到这个问题,一些建议正在计算每个单元格中数据文本的大小(根据字体大小,字体系列,填充......这很复杂)

    但我意识到当我点击表头上的 divider 时,它的大小适合我想要的内容 . 所以我深入研究JavaFX源代码我终于在 TableViewSkin 找到了 resizeColumnToFitContent 方法,但它是 protected 方法,我们可以通过反思来解决:

    import com.sun.javafx.scene.control.skin.TableViewSkin;
    import javafx.scene.control.Skin;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class GUIUtils {
        private static Method columnToFitMethod;
    
        static {
            try {
                columnToFitMethod = TableViewSkin.class.getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
                columnToFitMethod.setAccessible(true);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    
        public static void autoFitTable(TableView tableView) {
            tableView.getItems().addListener(new ListChangeListener<Object>() {
                @Override
                public void onChanged(Change<?> c) {
                    for (Object column : tableView.getColumns()) {
                        try {
                            columnToFitMethod.invoke(tableView.getSkin(), column, -1);
                        } catch (IllegalAccessException | InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    }
    

    请注意,我们称之为“ tableView.getItems() ”,因此我们必须在 setItems() 之后调用此函数

  • 24

    我认为只要通过覆盖一个返回true的回调函数来解决你的问题,它将禁用列的重新调整大小,并且所有列都将重新调整大小以适合其单元格的内容 .

    例:

    TableView<String[]> table = new TableView<>();
    table.setColumnResizePolicy(new Callback<TableView.ResizeFeatures, Boolean>() {
      @Override
      public Boolean call(ResizeFeatures p) {
         return true;
      }
    });
    
  • 2

    在测试了以前的解决方案后,我终于找到了一个适合我的解决方所以这是我的(在将数据插入表后调用方法):

    public static void autoResizeColumns( TableView<?> table )
    {
        //Set the right policy
        table.setColumnResizePolicy( TableView.UNCONSTRAINED_RESIZE_POLICY);
        table.getColumns().stream().forEach( (column) ->
        {
            //Minimal width = columnheader
            Text t = new Text( column.getText() );
            double max = t.getLayoutBounds().getWidth();
            for ( int i = 0; i < table.getItems().size(); i++ )
            {
                //cell must not be empty
                if ( column.getCellData( i ) != null )
                {
                    t = new Text( column.getCellData( i ).toString() );
                    double calcwidth = t.getLayoutBounds().getWidth();
                    //remember new max-width
                    if ( calcwidth > max )
                    {
                        max = calcwidth;
                    }
                }
            }
            //set the new max-widht with some extra space
            column.setPrefWidth( max + 10.0d );
        } );
    }
    
  • 0

    或者简而言之:

    // automatically adjust width of columns depending on their content
    configAttributeTreeTable.setColumnResizePolicy((param) -> true );
    
  • 5

    我在这个问题上使用了其他解决方案,它的效果非常好 . 但是,这方面的缺点是TableView的宽度大于TableColumns的所需宽度 . 我已经创建了一个hack来解决这个问题,它运行正常:

    orderOverview.setColumnResizePolicy((param) -> true );
    Platform.runLater(() -> FXUtils.customResize(orderOverview));
    

    其中FXUtils.customResize()的创建方式如下:

    public static void customResize(TableView<?> view) {
    
        AtomicDouble width = new AtomicDouble();
        view.getColumns().forEach(col -> {
            width.addAndGet(col.getWidth());
        });
        double tableWidth = view.getWidth();
    
        if (tableWidth > width.get()) {
            TableColumn<?, ?> col = view.getColumns().get(view.getColumns().size()-1);
            col.setPrefWidth(col.getWidth()+(tableWidth-width.get()));
        }
    
    }
    

    我希望这对其他人也有帮助!

  • 2

    如果你想只有一列填充表的剩余宽度,我找到了一个非常直接的解决方案,这个解决方案很简短,不需要上面描述的hacky反射解决方案:

    DoubleBinding usedWidth = columnA.widthProperty().add(columnB.widthProperty()).add(columnC.widthProperty());
    
    fillingColumn.prefWidthProperty().bind(tableView.widthProperty().subtract(usedWidth));
    
  • -1

    此代码以与表宽度相关的比例自动调整所有列宽,
    当表宽度低于x 时,它可以将第一列宽度固定为给定值

    // To generalize the columns width proportions in relation to the table width,
            // you do not need to put pixel related values, you can use small float numbers if you wish,
            // because it's the relative proportion of each columns width what matters here:
    
            final float[] widths = { 1.2f, 2f, 0.8f };// define the relational width of each column 
    
            // whether the first column should be fixed
            final boolean fixFirstColumm = true; 
    
            // fix the first column width when table width is lower than:
            final float fixOnTableWidth = 360; //pixels 
    
            // calulates sum of widths
            float sum = 0;
            for (double i : widths) {
                sum += i;
            }
    
            // calculates the fraction of the first column proportion in relation to the sum of all column proportions
            float firstColumnProportion = widths[0] / sum;
    
            // calculate the fitting fix width for the first column, you can change it by your needs, but it jumps to this width
            final float firstColumnFixSize = fixOnTableWidth * firstColumnProportion;
    
            // set the width to the columns
            for (int i = 0; i < widths.length; i++) {
                table.getColumns().get(i).prefWidthProperty().bind(table.widthProperty().multiply((widths[i] / sum)));
                // ---------The exact width-------------^-------------^
        if (fixFirstColumm)
                if (i == 0) {
                    table.widthProperty().addListener(new ChangeListener<Number>() {
                        @Override
                        public void changed(ObservableValue<? extends Number> arg0, Number oldTableWidth, Number newTableWidth) {
    
                            if (newTableWidth.intValue() <= fixOnTableWidth) {
    
                                // before you can set new value to column width property, need to unbind the autoresize binding
                                table.getColumns().get(0).prefWidthProperty().unbind();
                                table.getColumns().get(0).prefWidthProperty().setValue(firstColumnFixSize);
    
                            } else if (!table.getColumns().get(0).prefWidthProperty().isBound()) {
    
                                // than readd the autoresize binding if condition table.width > x
                                table.getColumns().get(0).prefWidthProperty()
                                        .bind(table.widthProperty().multiply(firstColumnProportion));
                            }
    
                        }
                    });
                }
            }
    

    建议将代码放在一个单独的TableAutoresizeModel类中,在那里你可以处理进一步的计算,例如在隐藏列上添加监听器...

  • 2
    public static void autoFillColumn(TableView<?> table, int col) {
        double width = 0;
        for (int i = 0; i < table.getColumns().size(); i++) {
            if (i != col) {
                width += table.getColumns().get(i).getWidth();
            }
        }
        table.getColumns().get(col).setPrefWidth(table.getWidth() - width);
    }
    
  • 0
    myTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
    for(TableColumn column: myTable.getColumns())
    {           
        column.setMinWidth(200);                                        
    }
    
  • 0

    经过长时间的研究最佳解决方案是......

    tblPlan.setColumnResizePolicy((param) -> true );
    Platform.runLater(() -> customResize(tblPlan));
    

    “自定义调整大小”

    public void customResize(TableView<?> view) {
    
            AtomicLong width = new AtomicLong();
            view.getColumns().forEach(col -> {
                width.addAndGet((long) col.getWidth());
            });
            double tableWidth = view.getWidth();
    
            if (tableWidth > width.get()) {
                view.getColumns().forEach(col -> {
                    col.setPrefWidth(col.getWidth()+((tableWidth-width.get())/view.getColumns().size()));
                });
            }
        }
    

相关问题