web-dev-qa-db-ja.com

JavaFXTableColumnのサイズをセルの内容に合わせて変更

TableViewのTableColumnのサイズを変更して、すべてのコンテンツが各セルに表示されるようにする方法を探しています(つまり、切り捨てられません)。

列の仕切りをダブルクリックすると、列がセルの内容に自動的にフィットすることに気付きました。これをプログラムでトリガーする方法はありますか?

10
jckdnk111

Javafxソースを調べてみると、TableView列の仕切りをクリックしたときに呼び出される実際のメソッドは

/*
 * FIXME: Naive implementation ahead
 * Attempts to resize column based on the pref width of all items contained
 * in this column. This can be potentially very expensive if the number of
 * rows is large.
 */
@Override protected void resizeColumnToFitContent(TableColumn<T, ?> tc, int maxRows) {
    if (!tc.isResizable()) return;

// final TableColumn<T, ?> col = tc;
    List<?> items = itemsProperty().get();
    if (items == null || items.isEmpty()) return;

    Callback/*<TableColumn<T, ?>, TableCell<T,?>>*/ cellFactory = tc.getCellFactory();
    if (cellFactory == null) return;

    TableCell<T,?> cell = (TableCell<T, ?>) cellFactory.call(tc);
    if (cell == null) return;

    // set this property to tell the TableCell we want to know its actual
    // preferred width, not the width of the associated TableColumnBase
    cell.getProperties().put(TableCellSkin.DEFER_TO_PARENT_PREF_WIDTH, Boolean.TRUE);

    // determine cell padding
    double padding = 10;
    Node n = cell.getSkin() == null ? null : cell.getSkin().getNode();
    if (n instanceof Region) {
        Region r = (Region) n;
        padding = r.snappedLeftInset() + r.snappedRightInset();
    } 

    int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows);
    double maxWidth = 0;
    for (int row = 0; row < rows; row++) {
        cell.updateTableColumn(tc);
        cell.updateTableView(tableView);
        cell.updateIndex(row);

        if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) {
            getChildren().add(cell);
            cell.applyCss();
            maxWidth = Math.max(maxWidth, cell.prefWidth(-1));
            getChildren().remove(cell);
        }
    }

    // dispose of the cell to prevent it retaining listeners (see RT-31015)
    cell.updateIndex(-1);

    // RT-36855 - take into account the column header text / graphic widths.
    // Magic 10 is to allow for sort arrow to appear without text truncation.
    TableColumnHeader header = getTableHeaderRow().getColumnHeaderFor(tc);
    double headerTextWidth = Utils.computeTextWidth(header.label.getFont(), tc.getText(), -1);
    Node graphic = header.label.getGraphic();
    double headerGraphicWidth = graphic == null ? 0 : graphic.prefWidth(-1) + header.label.getGraphicTextGap();
    double headerWidth = headerTextWidth + headerGraphicWidth + 10 + header.snappedLeftInset() + header.snappedRightInset();
    maxWidth = Math.max(maxWidth, headerWidth);

    // RT-23486
    maxWidth += padding;
    if(tableView.getColumnResizePolicy() == TableView.CONSTRAINED_RESIZE_POLICY) {
        maxWidth = Math.max(maxWidth, tc.getWidth());
    }

    tc.impl_setWidth(maxWidth);
}

それはで宣言されています

com.Sun.javafx.scene.control.skin.TableViewSkinBase

メソッドシグネチャ

protected abstract void resizeColumnToFitContent(TC tc, int maxRows)

保護されているため、たとえばから呼び出すことはできません。 tableView.getSkin()ですが、いつでもTableViewSkinを拡張して、resizeColumnToFitContentメソッドのみをオーバーライドしてパブリックにすることができます。

8
Tomasz

@Tomaszの提案として、私は反省によって解決します:

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

TableView.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);を使用できます。

TableView.UNCONSTRAINED_RESIZE_POLICYだけではニーズに合わない場合は、TableView.CONSTRAINED_RESIZE_POLICYとTableView.UNCONSTRAINED_RESIZE_POLICYの2つのポリシーを切り替えてみることもできます。

ここに 便利なリンク。

0
Tamad Lang