(javafx)tableview列的宽度如何根据内容自动调整

时间:2016-06-29 04:23:30

标签: javafx

当我双击列标题单元格的右边框时,它会自动调整列的宽度。 我如何以编程方式执行相同操作?

4 个答案:

答案 0 :(得分:3)

最后我找到了解决方案:

    TableViewSkin<?> skin = (TableViewSkin<?>) table.getSkin();
    TableHeaderRow headerRow = skin.getTableHeaderRow();
    NestedTableColumnHeader rootHeader = headerRow.getRootHeader();
    for (TableColumnHeader columnHeader : rootHeader.getColumnHeaders()) {
        try {
            TableColumn<?, ?> column = (TableColumn<?, ?>) columnHeader.getTableColumn();
            if (column != null) {
                Method method = skin.getClass().getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
                method.setAccessible(true);
                method.invoke(skin, column, 30);
            }
        } catch (Throwable e) {
            e = e.getCause();
            e.printStackTrace(System.err);
        }
    }

Javafx仍然很粗糙。许多简单的事情需要通过深刻的屁股......

答案 1 :(得分:3)

(不仅是内部)API从fx8更改为fx9:

  • TableViewSkin(以及所有皮肤实现)移动到公共范围:现在可以继承并实现所需的任何其他功能
  • tableViewSkin.getTableHeaderRow()tableHeaderRow.getRootHeader()已从受保护范围更改为包私有范围,合法访问任何内容的唯一方法是通过查找
  • resizeToFitContent的实现从皮肤移动到包私有实用程序类TableSkinUtils,根本无法访问
  • TableColumnHeader获得了一个调用实用程序方法的私有doColumnAutoSize(TableColumnBase, int),前提是列的prefWidth的默认值为80.好的一面是:由于这个次优的api,我们可以抓取一个任意的头和自动-size任何列

在代码中(注意:这会处理由TableView返回的所有可见叶列,嵌套与否 - 如果要包含隐藏列,则还需要收集它们)

/**
 * Resizes all visible columns to fit its content. Note that this does nothing if a column's 
 * prefWidth is != 80.
 * 
 * @param table
 */
public static void doAutoSize(TableView<?> table) {
    // good enough to find an arbitrary column header
    // due to sub-optimal api
    TableColumnHeader header = (TableColumnHeader) table.lookup(".column-header");
    if (header != null) {
        table.getVisibleLeafColumns().stream().forEach(column -> doColumnAutoSize(header, column));
    }
}

public static void doColumnAutoSize(TableColumnHeader columnHeader, TableColumn column) {
    // use your preferred reflection utility method 
    FXUtils.invokeGetMethodValue(TableColumnHeader.class, columnHeader, "doColumnAutoSize", 
            new Class[] {TableColumnBase.class, Integer.TYPE}, 
            new Object[] {column, -1});
}

答案 2 :(得分:1)

使用АлександрКиберман发布的上述优秀答案,我创建了一个类来处理这个问题以及getSkin()== null的问题:

import com.sun.javafx.scene.control.skin.NestedTableColumnHeader;
import com.sun.javafx.scene.control.skin.TableColumnHeader;
import com.sun.javafx.scene.control.skin.TableHeaderRow;
import com.sun.javafx.scene.control.skin.TableViewSkin;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;

import java.lang.reflect.Method;

// ---------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
public class TableViewPlus extends TableView
{
  private boolean flSkinPropertyListenerAdded = false;

  // ---------------------------------------------------------------------------------------------------------------------
  public TableViewPlus()
  {
    super();

    this.setEditable(false);
  }

  // ---------------------------------------------------------------------------------------------------------------------
  public TableViewPlus(final ObservableList toItems)
  {
    super(toItems);

    this.setEditable(false);
  }

  // ---------------------------------------------------------------------------------------------------------------------
  public void resizeColumnsToFit()
  {
    if (this.getSkin() != null)
    {
      this.resizeColumnsPlatformCheck();
    }
    else if (!this.flSkinPropertyListenerAdded)
    {
      this.flSkinPropertyListenerAdded = true;

      // From https://stackoverflow.com/questions/38718926/how-to-get-tableheaderrow-from-tableview-nowadays-in-javafx
      // Add listener to detect when the skin has been initialized and therefore this.getSkin() != null.
      this.skinProperty().addListener((a, b, newSkin) -> this.resizeColumnsPlatformCheck());
    }

  }

  // ---------------------------------------------------------------------------------------------------------------------
  private void resizeColumnsPlatformCheck()
  {
    if (Platform.isFxApplicationThread())
    {
      this.resizeAllColumnsUsingReflection();
    }
    else
    {
      Platform.runLater(this::resizeAllColumnsUsingReflection);
    }
  }

  // ---------------------------------------------------------------------------------------------------------------------
  // From https://stackoverflow.com/questions/38090353/javafx-how-automatically-width-of-tableview-column-depending-on-the-content
  // Geesh. . . .
  private void resizeAllColumnsUsingReflection()
  {
    final TableViewSkin<?> loSkin = (TableViewSkin<?>) this.getSkin();
    // The skin is not applied till after being rendered. Which is happening with the About dialog.
    if (loSkin == null)
    {
      System.err.println("Skin is null");
      return;
    }

    final TableHeaderRow loHeaderRow = loSkin.getTableHeaderRow();
    final NestedTableColumnHeader loRootHeader = loHeaderRow.getRootHeader();
    for (final TableColumnHeader loColumnHeader : loRootHeader.getColumnHeaders())
    {
      try
      {
        final TableColumn<?, ?> loColumn = (TableColumn<?, ?>) loColumnHeader.getTableColumn();
        if (loColumn != null)
        {
          final Method loMethod = loSkin.getClass().getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
          loMethod.setAccessible(true);
          loMethod.invoke(loSkin, loColumn, 30);
        }
      }
      catch (final Throwable loErr)
      {
        loErr.printStackTrace(System.err);
      }
    }

  }

  // ---------------------------------------------------------------------------------------------------------------------
}
// ---------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------

答案 3 :(得分:0)

    table.skinProperty().addListener((a, b, newSkin) -> {
        TableViewSkin<?> skin = (TableViewSkin<?>) table.getSkin();
        TableHeaderRow headerRow = skin.getTableHeaderRow();
        NestedTableColumnHeader rootHeader = headerRow.getRootHeader();
        for (TableColumnHeader columnHeader : rootHeader.getColumnHeaders()) {
            try {
                TableColumn<?, ?> column = (TableColumn<?, ?>) columnHeader.getTableColumn();
                if (column != null) {
                    Method method = skin.getClass().getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
                    method.setAccessible(true);
                    method.invoke(skin, column, 30);
                }
            } catch (Throwable e) {
                e = e.getCause();
                e.printStackTrace(System.err);
            }
        }

    });

为了防止getSkin()== null;