0

I have found similar questions here on Stackoverflow, but for some reason when I try to implement what is suggested, I get a strange exception.

So I am trying to get adjust some of the heights on 3 of the columns dynamically.

public class AcquisitionTechniquesPanel extends JPanel {
    private static final long serialVersionUID = -3326535610858334494L;

    public static final int SIZE_OF_TABLE = 8;

    private final JTable table;
    private JCheckBox acquisitionTechniquesDone;

    private Object[][] tableData;
    private final String[] columnNames;

    public AcquisitionTechniquesPanel() {
        this.columnNames = new String[] { ApplicationStrings.ID, ApplicationStrings.TYPE, "Foo", "Bar", "Biz", "Baz", "Boz", ApplicationStrings.NO_OF_AR_S };
        this.table = new JTable(tableData, columnNames);

        initGUI();
    }


    public void initGUI() {
      table.setColumnSelectionAllowed(
      table.setDragEnabled(false);
      table.setOpaque(true);
      table.getTableHeader().setReorderingAllowed(false);
      table.setModel(new DefaultTableModel());
      JScrollPane scrollPane = new JScrollPane(table);
      scrollPane.setPreferredSize(new Dimension(800, 320));

      SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                table.getColumnModel().getColumn(2).setCellRenderer(new VariableRowHeightRenderer());
                table.getColumnModel().getColumn(3).setCellRenderer(new VariableRowHeightRenderer());
                table.getColumnModel().getColumn(4).setCellRenderer(new VariableRowHeightRenderer());
            }
        });
    }

public static class VariableRowHeightRenderer extends JLabel implements TableCellRenderer {
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            setText(String.valueOf(value));
            if(getPreferredSize().height > 1)
                table.setRowHeight(row, getPreferredSize().height);
            return this;
        }
    }
}

Now when I run this code, for some reason I get java.lang.ArrayIndexOutOfBoundsException: 2 >= 0 I get this exception on the code table.getColumnModel().getColumn(2).setCellRenderer(new VariableRowHeightRenderer()); Which is strange, because the table should have 8 columns.

Does anyone know what I am doing wrong?

Please note that I am only showing relevant code

Shervin Asgari
  • 23,901
  • 30
  • 103
  • 143
  • **DONT** change the state of a table in your renderer, ever. Instead, listen to changes on the tableModel - that's the only time a rowHeight might change - and update the height/s as appropriate – kleopatra Oct 03 '12 at 08:48
  • ... and (unrelated, but not can't repeat it often enough ;-) don't call setXXSize, ever [for reasons](http://stackoverflow.com/a/7229519/203657) – kleopatra Oct 03 '12 at 08:50
  • @kleopatra Can you please provide example on how I might listen to changes in the tableModel so that I can act on it and adjust the height? – Shervin Asgari Oct 03 '12 at 08:51
  • hmm .. you know about a TableModelModelListener? Just implement one doing what you want and register with the table's model. – kleopatra Oct 03 '12 at 08:58
  • @kleopatra digging out the comment but, I just did what you suggested in a table, that is use a listener to update table row height when inserting/updating rows. When I debug my program, the listener is executed, and the rows are resized correctly. Right after that, the listener of the JTable itself (see `JTable#setModel` code) which resize all the rows back. If not in debug, it just seems that no resizing happen! How can I avoid that? I'm displaying in the table the thumbnails extracted from image metadata – remi Dec 18 '14 at 15:52
  • @remi no idea - you might consider asking a new question (if you didn't already, didn't check) with an SSCCE that demonstrates the problem – kleopatra Dec 18 '14 at 16:42

3 Answers3

2

The problem comes from here:

table.setModel(new DefaultTableModel());

You set an empty model on your JTable and therefore overwrite the implicit model you have created with the JTable constructor. Simply remove that line and you should have your 8 columns.

Btw, there is no need to wrap your call in an invokeLater.

Guillaume Polet
  • 47,259
  • 4
  • 83
  • 117
  • I can't remove that because I am using it later to change the content of the jtable. I haven't found out how to do that, so I just get that DefaultTableModel and use setDataVector() to update the content dynamically – Shervin Asgari Oct 03 '12 at 08:47
2

Below is an excerpt of SwingX' TableUtilies which provide the height adjustment. You use it like

this.table = new JTable(tableData, columnNames);
// initial sizing
TableUtilites.setPreferredRowHeights(table);
TableModelListener l = new TableModelListener() {
     public void tableChanged(...) {
         // dynamic sizing on changes
         SwingUtilities.invokeLater() {
              public void run() {
                  TableUtilities.setPreferredRowHeights(table);
              }
         };
     }
}; 
table.getModel().addTableModelListener(l);

Utility methods from TableUtilities:

/**
 * Returns the preferred height for the given row. It loops
 * across all visible columns and returns the maximal pref height of
 * the rendering component. Falls back to the table's base rowheight, i
 * f there are no columns or the renderers
 * max is zeor.<p>
 * 
 * @param table the table which provides the renderers, must not be null
 * @param row the index of the row in view coordinates
 * @return the preferred row height of
 * @throws NullPointerException if table is null.
 * @throws IndexOutOfBoundsException if the row is not a valid row index
 */
public static int getPreferredRowHeight(JTable table, int row) {
    int pref = 0;
    for (int column = 0; column < table.getColumnCount(); column++) {
        TableCellRenderer renderer = table.getCellRenderer(row, column);
        Component comp = table.prepareRenderer(renderer, row, column);
        pref = Math.max(pref, comp.getPreferredSize().height);
    }
    return pref > 0 ? pref : table.getRowHeight();
}

/**
 * 
 * @param table the table which provides the renderers, must not be null
 * @param row the index of the row in view coordinates
 * @throws NullPointerException if table is null.
 * @throws IndexOutOfBoundsException if the row is not a valid row index
 */
public static void setPreferredRowHeight(JTable table, int row) {
    int prefHeight = getPreferredRowHeight(table, row);
    table.setRowHeight(row, prefHeight);
}

/**
 * Sets preferred row heights for all visible rows. 
 * 
 * @param table the table to set row heights to
 * @throws NullPointerException if no table installed.
 */
public static void setPreferredRowHeights(JTable table) {
    // care about visible rows only
    for (int row = 0; row < table.getRowCount(); row++) {
        setPreferredRowHeight(table, row);
    }
}
kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • Thanks. We are already using swingx it seems. It is version 0.8. Can I safely upgrade to the latest version, or do you know of any show stoppers? I'm asking because I see you are one of the administrators. – Shervin Asgari Oct 03 '12 at 09:22
  • We are using `extends JXTable` and JXDatePicker. Are any of those classes backward compatible with 0.8 if I upgrade to the latest version? – Shervin Asgari Oct 03 '12 at 09:24
  • 0.8 is stone-age :-) At least update to 1.0 - even that is extremely old, but the last targeted at jdk 1.5. If you are on a later jdk, you might consider to switch to the latest 1.6.4. There are many changes, though, hopefully to the better, so some work will be required to adjust your codebase – kleopatra Oct 03 '12 at 09:27
  • Thats the problem. I don't have the authority if you will to change the existing codebase. But you know for a fact that there are breaking changes for the `JXTable` and `JXDatePicker`? Because then I am not willing to upgrade just yet. We are using JDK 6. Is there any changelongs? I haven't been able to find it – Shervin Asgari Oct 03 '12 at 09:31
  • never tried, but most probably there will be breaking changes (the whole sorting/filtering stack was changed to comply with the now core mechanism) The datePicker went through some rounds of renewal as well. No changelogs, I'm afraid: it's all in the forum and/or issue tracker. – kleopatra Oct 03 '12 at 09:35
1
  • remove, disable or change code line table.setColumnSelectionAllowed(

  • assume that ApplicationStrings.XXX are global variables that returns String value (or "")

mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Your assumption is right. It didn't help to do that. What seems to work is putting the tableData and columnNames in the `table.setModel(new DefaultTableModel(tableData, columnNames));` but I wonder why – Shervin Asgari Oct 03 '12 at 08:35
  • @kleopatra by default null value is replaced with a-z in column range, but TableHeader doeasn't accepting an exception, please "selection properties are unrelated" is about ???, or is there something important with selections properties (sorry no battery included, helicopter view, nor checking OP's code after uncompilable code), then (accepted by OP) rest was not important :-) – mKorbel Oct 03 '12 at 11:18