4

either this doesn't exist, or I'm not thinking/searching correctly because it's late...

I want to set a JTable column width in Swing based on a prototype value for the largest string I expect (or know) to exist in a particular column. I don't know the # of pixels since I don't necessarily know the font at compile time.

Is there a way to set a prototype value for column width purposes, the way there is for row height purposes? If so, how?

Jason S
  • 184,598
  • 164
  • 608
  • 970

5 Answers5

3

You can try the following code:

/**
 * Sets the preferred width of the columns of a table from prototypes
 * @param table the target table
 * @param prototypes an array of prototypes, {@code null} values will be ignored
 * @param setMaxWidth {@code true} if the maximum column width should also be set
 */
public static void setWidthFromPrototype(JTable table, Object[] prototypes, boolean setMaxWidth) {
if (prototypes.length != table.getColumnCount())
  throw new IllegalArgumentException("The prototypes array should contain exactly one element per table column");
for (int i = 0; i < prototypes.length; i++) {
    if (prototypes[i] != null) {
        Component proto = table.getCellRenderer(0,i)
                .getTableCellRendererComponent(table, prototypes[i], false, false, 0, i);
        int prefWidth = (int) proto.getPreferredSize().getWidth() + 1;
        table.getColumnModel().getColumn(i).setPreferredWidth(prefWidth);
        if (setMaxWidth)
            table.getColumnModel().getColumn(i).setMaxWidth(prefWidth);
    }
}
}
Victor P.
  • 630
  • 1
  • 6
  • 14
  • to use it, just call setWidthFromPrototype(myTable, new Object[]{"Not Applicable"}); – Victor P. Mar 28 '12 at 08:41
  • upvoted for measuring the component provided by the renderer - just getting the renderer is wrong: you have to ask the table for it (table.getRenderer(row, column)), otherwise, you'll miss per-column renderers - please edit for perfection :-) – kleopatra Mar 28 '12 at 11:49
  • thanks for the suggestions @kleopatra, but I don't see the `JTable.getRenderer(int,int)` method. In all cases I think `getDefaultRenderer` is safer as it returns the renderer associated with a type, which can be useful if you don't want to create a full instance of the object, and for instance just pass its string representation. – Victor P. Mar 30 '12 at 08:06
  • And no, you are wrong in thinking _getDefaultRenderer is safer_: it's up to the table to decide which renderer to use which happens in getCellRenderer (indeed, you found the correct method name :-) The last part of your comment doesn't make much sense, though: the renderer lookup mechanism doesn't care about what how your data is stored in the model ... – kleopatra Mar 30 '12 at 09:33
  • Allow me to clarify: suppose you have a class Student that store a name, id, full history of grades. You may define a custom renderer that will render an instance of Student in the form "Name Surname GPA". If you are just interested in setting the column width, you may not want (or be able to) create a full instance of Student, but just pass "John Doe 4.5" as a prototype, in which case using the rendered provided by `JTable.getCellRenderer(int,int)` will likely cause a casting exception. – Victor P. Apr 02 '12 at 11:55
  • only if the renderer is crappily implemented - fix it ;-) – kleopatra Apr 02 '12 at 12:16
  • ok I see your point, I updated the code (and fixed my renderer ^^) – Victor P. Apr 05 '12 at 11:48
1

Have you tried creating a JLabel at run time and using its size to resize your table?

// create a label that will be using the run-time font
JLabel prototypeLabel = new JLabel("Not Applicable")

// get the labels preferred sizes
int preferredWidth = prototypeLabel.getPreferredSize().getWidth();
int preferredHeight = prototypeLabel.getPreferredSize().getHeight();

// set the sizes of the table's row and columns
myTable.setRowHeight(preferredHeight);

for(TableColumn column : myTable.getColumnModel.getColumns()){
   column.setPreferredWidth(preferredWidth);        
}
Andrew
  • 1,167
  • 7
  • 5
  • oh, that's clever. Is there any way I can be sure the JLabel and the table column entries use the same font? – Jason S May 09 '09 at 20:38
  • It would probably depend on whatever font your TableCellRenderer was using. If you had access to the renderer(s), and they were JLabel's as well, you could create your prototype label using the same font with something like: JLabel prototypeLabel = new JLabel("Not Applicable"); prototypeLabel.setFont(cellRenderer.getFont()) – Andrew May 11 '09 at 01:17
  • 1
    -1 not a good idea to use an arbritrary component for measuring the size. Instead, use the rendering component as provided by the table – kleopatra Mar 28 '12 at 11:45
1

SwingX extended JXTable/Column support setting prototypes for initial column width sizing, you can do so either after the columns have been created

for(int col = 0; ....) {
    table.getColumnExt(col).setPrototypeValue(myPrototype[col]
}

or by implementing a custom ColumnFactory which configures the columns on creation

ColumnFactory factory = new ColumnFactory() {
    @Override
    protected void configureTableColumn(TableModel model, TableColumnExt columnExt) {
        super(...);
        columnExt.setPrototypeValue(myPrototype[columnExt.getModelIndex()];
    }
}
table.setColumnFactory(factory);
table.setModel(myModel);
kleopatra
  • 51,061
  • 28
  • 99
  • 211
0

Instead of creating a Label, get the actual component from the TableCellRenderer and test the size on that:

// create the component that will be used to render the cell
Comp prototype = table.getDefaultRenderer(model.getColumnClass(i)).getTableCellRendererComponent(table, "Not Applicable", false, false, 0, i);

// get the labels preferred sizes
int preferredWidth = comp.getPreferredSize().getWidth();
int preferredHeight = comp.getPreferredSize().getHeight();

This is a single column example, you'll need to repeat this to get the size for each column (and also set it). See http://www.exampledepot.com/egs/javax.swing.table/PackCol.html for an example of this.

tekumara
  • 8,357
  • 10
  • 57
  • 69
  • ??? And how does this reflect the width/height of a particular maximum-length string? I want my column that can contain "$222.22" to be a smaller width than the one that can contain "Miscellaneous grocery purchases". – Jason S Jul 13 '10 at 23:31
  • This is a single column example, you'll need to repeat this to get the size for each column (and also set it). See http://www.exampledepot.com/egs/javax.swing.table/PackCol.html for an example of this. The JLabel answer will have the same problem because you are setting every column to the same preferred width. – tekumara Jul 15 '10 at 23:26
-1

If you don't know the font at compile time then the width of any JTable column is always going to be unknown. As a sanity check, open a text document and play with different fonts whilst keeping the point size constant. The length of what is written varies on a font-by-font basis but the height doesn't.

The height of a JTable row should be able to be determined for any font size (in points) as it is a defined standard. It might take a bit of experimenting, though, given that JTable probably gives a bit of spacing inbetween cells.

If you can't guarantee neither the font size nor the font itself at compile time then I'm interested in what answers other people come up with :)

Catchwa
  • 5,845
  • 4
  • 31
  • 57
  • "the width of any JTable column is always going to be unknown." ??? I have some example text, e.g. "Not Applicable" that I want to use as the maximum column width. Surely at runtime, when the font is known, it is possible to determine column width from that? – Jason S May 08 '09 at 13:17