0

The FXML for the TableView is as such:

<TableView fx:id="invocationStatsTable">
    <columns>
        <TableColumn fx:id="ruleName" text="Rule"/>
        <TableColumn fx:id="ruleClass" text="Rule class"/>
        <TableColumn fx:id="ruleType" text="Rule type"/>
        <TableColumn fx:id="nrCalls" text="Invocations"
            sortType="DESCENDING"/>
        <TableColumn fx:id="callDetail" text="N / E / F (*)"
            sortable="false"/>
        <TableColumn fx:id="callGraph" text="Graph" sortable="false"
            prefWidth="200.0"/>
    </columns>
</TableView>

which gives this (bottom):

the result

The problem is immediately, well, visible: columns are not sized correctly.

And I'd like to avoid having to set prefWidth by hand on all columns since

  1. it will always be a guess game and at some point the guess will be wrong, and
  2. it's time consuming.

I'd much rather the resize were automatic AND bound to the maximum width or either the column header or any data within, if possible...

For now, here is the code, first of the column initialization in the StatsTabDisplay class (which is the "JavaFX controller"):

@Override
public void init()
{
    setColumnValue(ruleName, r -> r.getRuleInfo().getName());
    setColumnValue(ruleClass, r -> r.getRuleInfo().getClassName());
    setColumnValue(ruleType, r -> r.getRuleInfo().getType());
    setColumnValue(nrCalls, r -> r.getEmptyMatches() + r.getFailedMatches()
        + r.getNonEmptyMatches());
    setColumnValue(callDetail, r -> String.format("%d / %d / %d",
        r.getNonEmptyMatches(), r.getEmptyMatches(), r.getFailedMatches()));
    setColumnValue(callGraph, Function.identity());
    callGraph.setCellFactory(CallGraphTableCell::new);
}

The setColumnValue() method is defined in a utility class:

public static <S, T> void setColumnValue(final TableColumn<S, T> column,
    final Function<? super S, ? extends T> f)
{
    column.setCellValueFactory(
        param -> new SimpleObjectProperty<T>()
        {
            @Override
            public T get()
            {
                return f.apply(param.getValue());
            }
        }
    );
}

The code to trigger the table refresh is:

public void handleRefreshInvocationStatistics()
{
    final boolean complete = model.isLoadComplete();

    taskRunner.computeOrFail(
        view::disableTableRefresh,
        model::getRuleInvocationStatistics,
        stats -> view.displayRuleInvocationStatistics(complete, stats),
        throwable -> mainView.showError("Load error",
            "Unable to load matcher statistics", throwable)
    );
}

and the matching code fragments in the view is this (the display member of the view is the instance of StatsTabDisplay):

@Override
public void displayRuleInvocationStatistics(final boolean complete,
    final List<RuleInvocationStatistics> stats)
{
    if (complete) {
        display.completionStatus.setVisible(false);
        display.tableRefresh.setVisible(false);
    }

    display.invocationStatsTable.getSortOrder().setAll(display.nrCalls);
    display.invocationStatsTable.getItems().setAll(stats);
    display.invocationStatsTable.sort();
    display.tableRefresh.setDisable(false);
}

@Override
public void disableTableRefresh()
{
    display.tableRefresh.setDisable(true);
}

It is possible to achieve the required feature?


EDIT well, I know it is definitely possible, since when you double click on the "right of the column header" (I don't know the exact term for it) it achieves exactly what I want; except that I'd like it to be in code, not requiring a user interaction...

fge
  • 119,121
  • 33
  • 254
  • 329

1 Answers1

2

I would suggest making use of the columnResizePolicy.

If you set tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY) all columns will be equally resized until the TableViews maximum width is reached. But you can write your own policy:

The policy is just a Callback where ResizeFeatures is given as input from where you have access to the TableColumn.

eckig
  • 10,964
  • 4
  • 38
  • 52
  • Does not work :/ Whether I put it in the table initialization code or in the view when the data is updated, columns don't get resized... I guess I need to have some sort of hook on data insertion or something – fge Feb 05 '15 at 10:30
  • Woops, It should have been `TableView.CONSTRAINED_RESIZE_POLICY`. That works if done during `TableView` initialization. – eckig Feb 05 '15 at 11:20
  • Nearly there! It does achieve resize, just that the whole width of the table is filled... But that is already much better than what I have! – fge Feb 05 '15 at 11:41
  • As I said: Implement your own resize policy. It is not what I would call an intuitive API but with some debugging you will get what you want ;-) – eckig Feb 05 '15 at 11:57
  • @fge Did you had any success with these hints? – eckig Feb 05 '15 at 19:18
  • Sorry, I didn't have the time to delve deep enough into it yet; I'll try later on. In the meanwhile, I also looked at the solution posted by @brian but it looks quite complicated for what I want to achieve... – fge Feb 05 '15 at 19:32