Showing posts with label swing. Show all posts
Showing posts with label swing. Show all posts

Monday, June 19, 2006

Programmatically show a tool tip in Swing

A better way to do this exists, I am sure, but I failed to find it easily with Google: How to display a tool tip programmatically in Swing:

ToolTipManager.sharedInstance().mouseMoved(
        new MouseEvent(targetComponent, 0, 0, 0,
                0, 0, // X-Y of the mouse for the tool tip
                0, false));

Note the commented line. This is the relative location of the synthetic mouse event to the target component. The (0, 0) example above is as if the user had paused the mouse at the upper-left corner of the component, and the tool tip displays accordingly.

Another choice might be (targetComponent.getWidth(), targetComponent.getHeight()) for the lower-right corner, etc.

I wish Swing had a more straight-forward way of using the tool tip framework programmatically. I would like to be able to reuse tool tips for form validation. But at least this works.

UPDATE: 4 years on and I still get more positive comments on this post than any other. Hopefully the JDK improves in this area.

Monday, January 02, 2006

Getting JTable columns widths to fit the data

I've been stumped on a JTable problem for quite a while now: how to get the columns to fit the width of the data in the cells. Out of the box, JTable uses the same width for all columns in a table. This is very annoying for non-editable tables which just display data. I want my Java tables to looks similar to HTML tables which resize column widths according to the cell contents.

A likely solution is simply that I did not search Google well enough, but information was frustratingly rare to find for me.

I did, however, eventually stumble across the prepareRenderer(TableCellRenderer renderer, int row, int column):Component method (and likewise prepareRenderer(TableCellEditor editor, int row, int column):Component). A flash of insight illuminated the solution at once:

{
    final TableCellRenderer renderer = getTableHeader()
            .getDefaultRenderer();

    for (int i = 0; i < getColumnCount(); ++i)
        getColumnModel().getColumn(i).setPreferredWidth(
                renderer.getTableCellRendererComponent(this,
                        getModel().getColumnName(i), false, false, 0, i)
                        .getPreferredSize().width);
}

public Component prepareRenderer(final TableCellRenderer renderer,
        final int row, final int column) {
    final Component prepareRenderer = super
            .prepareRenderer(renderer, row, column);
    final TableColumn tableColumn = getColumnModel().getColumn(column);

    tableColumn.setPreferredWidth(max(
            prepareRenderer.getPreferredSize().width,
            tableColumn.getPreferredWidth()));

    return prepareRenderer;
}

My solution has two parts. Addressing first prepareRenderer: as the table is drawn, adjust the preferred width of a column to be at least as wide as the widest cell seen so far. This was 90% of my problem right there. Immediately I stopped having truncated cells, and the table adjusted gracefully to new cell data which did not fit the old column widths.

The second part is more obscure: the instance initializer. Although my cell contents were now always visible, the proportions among the columns did not look quite right: narrow columns were not narrow enough with excess slop on either side of column titles. So I instructed the table to shrink column widths down to just that necessary to show the title (prepareRenderer will widen them again as needed for cell contents). Perfect!

What surprises me is that I was unable to find this or a similar solution anywhere in my Google searches. I can scarcely believe this is the first attempt at this approach. Hopefully Sun will include a solution in the JDK—this is not an uncommon JTable problem.

UPDATE: This topic continues to deliver: Alex Boosmeeuw posts with a different approach.