title: How to calculate jTable width and Height after column adjustment if data is changed from a cellrenderer
body: <p>I am working on an application in which I have to calculate JTable width and height, if model data gets changed at runtime and after column width adjustment, width and column is not calculated properly. Following is the sample code:-</p>
  
  <p>**</p>
  
  <ul>
  <li>SimpleTableDemo.java</li>
  </ul>
  
  <p>**</p>
  
  <pre><code>     package com.swing.data;
  
  import java.awt.Dimension;
  import java.awt.GridLayout;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  
  import javax.swing.JButton;
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.JTable;
  import javax.swing.table.TableModel;
  
  public class SimpleTableDemo extends JPanel implements ActionListener {
      private boolean DEBUG = false;
      private JTable table = null;
      private TableColumnAdjuster app = null;
      String[] columnNames = {"First Name",
              "Last Name",
              "Sport",
              "# of Years",
              "Vegetarian"};
      Object[][] data = {
              {"Kathy", "Smith",
               "Snowboarding", new Integer(5), new Boolean(false)},
              {"John", "Doe",
               "Rowing", new Integer(3), new Boolean(true)},
              {"Sue", "Black",
               "Knitting", new Integer(2), new Boolean(false)},
              {"Jane", "White",
               "Speed reading", new Integer(20), new Boolean(true)},
              {"Joe", "Brown",
               "Pool", new Integer(10), new Boolean(false)}
              };
      CutomTableCellRenderer renderer = null;
      public SimpleTableDemo() {
          super(new GridLayout(1,0));
          table = new JTable(data, columnNames);
          table.setPreferredScrollableViewportSize(new Dimension(500, 70));
          table.setFillsViewportHeight(true);
  
          if (DEBUG) {
              table.addMouseListener(new MouseAdapter() {
                  public void mouseClicked(MouseEvent e) {
                      printDebugData(table);
                  }
              });
          }
          renderer = new CutomTableCellRenderer(table.getDefaultRenderer(Object.class));
          table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
          table.setDefaultRenderer(Object.class, renderer);
          //table.setSelectionMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
          JScrollPane scrollPane = new JScrollPane(table);
          app = new TableColumnAdjuster(table);
          app.adjustColumns();
         // scrollPane.setRowHeaderView(jRowTable);
          //scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,jRowTable.getTableHeader());
          //scrollPane.setSize(300,300);
          //Create the scroll pane and add the table to it.
  
          //Add the scroll pane to this panel.
          add(scrollPane);
          JButton button = new JButton("Change");
          add(button);
          button.addActionListener(this);
  
      }
  
      private void printDebugData(JTable table) {
          int numRows = table.getRowCount();
          int numCols = table.getColumnCount();
          javax.swing.table.TableModel model = table.getModel();
  
          System.out.println("Value of data: ");
          for (int i=0; i &lt; numRows; i++) {
              System.out.print("    row " + i + ":");
              for (int j=0; j &lt; numCols; j++) {
                  System.out.print("  " + model.getValueAt(i, j));
              }
              System.out.println();
          }
          System.out.println("--------------------------");
      }
  
      /**
       * Create the GUI and show it.  For thread safety,
       * this method should be invoked from the
       * event-dispatching thread.
       */
      private static void createAndShowGUI() {
          //Create and set up the window.
          JFrame frame = new JFrame("SimpleTableDemo");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  
          //Create and set up the content pane.
          SimpleTableDemo newContentPane = new SimpleTableDemo();
          newContentPane.setOpaque(true); //content panes must be opaque
          frame.setContentPane(newContentPane);
  
          //Display the window.
          frame.pack();
          frame.setVisible(true);
      }
  
      public static void main(String[] args) {
          //Schedule a job for the event-dispatching thread:
          //creating and showing this application's GUI.
          javax.swing.SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                  createAndShowGUI();
              }
          });
      }
  
      @Override
      public void actionPerformed(ActionEvent e) {
          renderer.setText("Modified.............................");  
          app.adjustColumns();
          System.out.println("tableWidth:" + table.getWidth() + "tableHeight:" + table.getHeight());
      }
  }
  </code></pre>
  
  <p>**</p>
  
  <ul>
  <li>TableColumnAdjuster.java</li>
  </ul>
  
  <p>**</p>
  
  <pre><code>package com.swing.data;
  
  import java.awt.*;
  import java.awt.event.*;
  import java.beans.*;
  import java.util.*;
  import javax.swing.*;
  import javax.swing.event.*;
  import javax.swing.table.*;
  
  /*
   *  Class to manage the widths of colunmns in a table.
   *
   *  Various properties control how the width of the column is calculated.
   *  Another property controls whether column width calculation should be dynamic.
   *  Finally, various Actions will be added to the table to allow the user
   *  to customize the functionality.
   *
   *  This class was designed to be used with tables that use an auto resize mode
   *  of AUTO_RESIZE_OFF. With all other modes you are constrained as the width
   *  of the columns must fit inside the table. So if you increase one column, one
   *  or more of the other columns must decrease. Because of this the resize mode
   *  of RESIZE_ALL_COLUMNS will work the best.
   */
  public class TableColumnAdjuster implements PropertyChangeListener, TableModelListener
  {
      private JTable table;
      private int spacing;
      private boolean isColumnHeaderIncluded;
      private boolean isColumnDataIncluded;
      private boolean isOnlyAdjustLarger;
      private boolean isDynamicAdjustment;
      private Map&lt;TableColumn, Integer&gt; columnSizes = new HashMap&lt;TableColumn, Integer&gt;();
  
      /*
       *  Specify the table and use default spacing
       */
      public TableColumnAdjuster(JTable table)
      {
          this(table, 6);
      }
  
      /*
       *  Specify the table and spacing
       */
      public TableColumnAdjuster(JTable table, int spacing)
      {
          this.table = table;
          this.spacing = spacing;
          setColumnHeaderIncluded( true );
          setColumnDataIncluded( true );
          setOnlyAdjustLarger( true );
          setDynamicAdjustment( false );
          installActions();
      }
  
      /*
       *  Adjust the widths of all the columns in the table
       */
      public void adjustColumns()
      {
          TableColumnModel tcm = table.getColumnModel();
  
          for (int i = 0; i &lt; tcm.getColumnCount(); i++)
          {
              adjustColumn(i);
          }
      }
  
      /*
       *  Adjust the width of the specified column in the table
       */
      public void adjustColumn(final int column)
      {
          TableColumn tableColumn = table.getColumnModel().getColumn(column);
  
          if (! tableColumn.getResizable()) return;
  
          int columnHeaderWidth = getColumnHeaderWidth( column );
          int columnDataWidth   = getColumnDataWidth( column );
          int preferredWidth    = Math.max(columnHeaderWidth, columnDataWidth);
  
          updateTableColumn(column, preferredWidth);
      }
  
      /*
       *  Calculated the width based on the column name
       */
      private int getColumnHeaderWidth(int column)
      {
          if (! isColumnHeaderIncluded) return 0;
  
          TableColumn tableColumn = table.getColumnModel().getColumn(column);
          Object value = tableColumn.getHeaderValue();
          TableCellRenderer renderer = tableColumn.getHeaderRenderer();
  
          if (renderer == null)
          {
              renderer = table.getTableHeader().getDefaultRenderer();
          }
  
          Component c = renderer.getTableCellRendererComponent(table, value, false, false, -1, column);
          return c.getPreferredSize().width;
      }
  
      /*
       *  Calculate the width based on the widest cell renderer for the
       *  given column.
       */
      private int getColumnDataWidth(int column)
      {
          if (! isColumnDataIncluded) return 0;
  
          int preferredWidth = 0;
          int maxWidth = table.getColumnModel().getColumn(column).getMaxWidth();
  
          for (int row = 0; row &lt; table.getRowCount(); row++)
          {
              preferredWidth = Math.max(preferredWidth, getCellDataWidth(row, column));
  
              //  We've exceeded the maximum width, no need to check other rows
  
              if (preferredWidth &gt;= maxWidth)
                  break;
          }
  
          return preferredWidth;
      }
  
      /*
       *  Get the preferred width for the specified cell
       */
      private int getCellDataWidth(int row, int column)
      {
          //  Inovke the renderer for the cell to calculate the preferred width
  
          TableCellRenderer cellRenderer = table.getCellRenderer(row, column);
          Component c = table.prepareRenderer(cellRenderer, row, column);
          int width = c.getPreferredSize().width + table.getIntercellSpacing().width;
  
          return width;
      }
  
      /*
       *  Update the TableColumn with the newly calculated width
       */
      private void updateTableColumn(int column, int width)
      {
          final TableColumn tableColumn = table.getColumnModel().getColumn(column);
  
          if (! tableColumn.getResizable()) return;
  
          width += spacing;
  
          //  Don't shrink the column width
  
          if (isOnlyAdjustLarger)
          {
              width = Math.max(width, tableColumn.getPreferredWidth());
          }
  
          columnSizes.put(tableColumn, new Integer(tableColumn.getWidth()));
          table.getTableHeader().setResizingColumn(tableColumn);
          tableColumn.setWidth(width);
      }
  
      /*
       *  Restore the widths of the columns in the table to its previous width
       */
      public void restoreColumns()
      {
          TableColumnModel tcm = table.getColumnModel();
  
          for (int i = 0; i &lt; tcm.getColumnCount(); i++)
          {
              restoreColumn(i);
          }
      }
  
      /*
       *  Restore the width of the specified column to its previous width
       */
      private void restoreColumn(int column)
      {
          TableColumn tableColumn = table.getColumnModel().getColumn(column);
          Integer width = columnSizes.get(tableColumn);
  
          if (width != null)
          {
              table.getTableHeader().setResizingColumn(tableColumn);
              tableColumn.setWidth( width.intValue() );
          }
      }
  
      /*
       *  Indicates whether to include the header in the width calculation
       */
      public void setColumnHeaderIncluded(boolean isColumnHeaderIncluded)
      {
          this.isColumnHeaderIncluded = isColumnHeaderIncluded;
      }
  
      /*
       *  Indicates whether to include the model data in the width calculation
       */
      public void setColumnDataIncluded(boolean isColumnDataIncluded)
      {
          this.isColumnDataIncluded = isColumnDataIncluded;
      }
  
      /*
       *  Indicates whether columns can only be increased in size
       */
      public void setOnlyAdjustLarger(boolean isOnlyAdjustLarger)
      {
          this.isOnlyAdjustLarger = isOnlyAdjustLarger;
      }
  
      /*
       *  Indicate whether changes to the model should cause the width to be
       *  dynamically recalculated.
       */
      public void setDynamicAdjustment(boolean isDynamicAdjustment)
      {
          //  May need to add or remove the TableModelListener when changed
  
          if (this.isDynamicAdjustment != isDynamicAdjustment)
          {
              if (isDynamicAdjustment)
              {
                  table.addPropertyChangeListener( this );
                  table.getModel().addTableModelListener( this );
              }
              else
              {
                  table.removePropertyChangeListener( this );
                  table.getModel().removeTableModelListener( this );
              }
          }
  
          this.isDynamicAdjustment = isDynamicAdjustment;
      }
  //
  //  Implement the PropertyChangeListener
  //
      public void propertyChange(PropertyChangeEvent e)
      {
          //  When the TableModel changes we need to update the listeners
          //  and column widths
  
          if ("model".equals(e.getPropertyName()))
          {
              TableModel model = (TableModel)e.getOldValue();
              model.removeTableModelListener( this );
  
              model = (TableModel)e.getNewValue();
              model.addTableModelListener( this );
              adjustColumns();
          }
      }
  //
  //  Implement the TableModelListener
  //
      public void tableChanged(TableModelEvent e)
      {
          if (! isColumnDataIncluded) return;
  
          //  A cell has been updated
  
          if (e.getType() == TableModelEvent.UPDATE)
          {
              int column = table.convertColumnIndexToView(e.getColumn());
  
              //  Only need to worry about an increase in width for this cell
  
              if (isOnlyAdjustLarger)
              {
                  int row = e.getFirstRow();
                  TableColumn tableColumn = table.getColumnModel().getColumn(column);
  
                  if (tableColumn.getResizable())
                  {
                      int width = getCellDataWidth(row, column);
                      updateTableColumn(column, width);
                  }
              }
  
              //  Could be an increase of decrease so check all rows
  
              else
              {
                  adjustColumn( column );
              }
          }
  
          //  The update affected more than one column so adjust all columns
  
          else
          {
              adjustColumns();
          }
      }
  
      /*
       *  Install Actions to give user control of certain functionality.
       */
      private void installActions()
      {
          installColumnAction(true,  true,  "adjustColumn",   "control ADD");
          installColumnAction(false, true,  "adjustColumns",  "control shift ADD");
          installColumnAction(true,  false, "restoreColumn",  "control SUBTRACT");
          installColumnAction(false, false, "restoreColumns", "control shift SUBTRACT");
  
          installToggleAction(true,  false, "toggleDynamic",  "control MULTIPLY");
          installToggleAction(false, true,  "toggleLarger",   "control DIVIDE");
      }
  
      /*
       *  Update the input and action maps with a new ColumnAction
       */
      private void installColumnAction(
          boolean isSelectedColumn, boolean isAdjust, String key, String keyStroke)
      {
          Action action = new ColumnAction(isSelectedColumn, isAdjust);
          KeyStroke ks = KeyStroke.getKeyStroke( keyStroke );
          table.getInputMap().put(ks, key);
          table.getActionMap().put(key, action);
      }
  
      /*
       *  Update the input and action maps with new ToggleAction
       */
      private void installToggleAction(
          boolean isToggleDynamic, boolean isToggleLarger, String key, String keyStroke)
      {
          Action action = new ToggleAction(isToggleDynamic, isToggleLarger);
          KeyStroke ks = KeyStroke.getKeyStroke( keyStroke );
          table.getInputMap().put(ks, key);
          table.getActionMap().put(key, action);
      }
  
      /*
       *  Action to adjust or restore the width of a single column or all columns
       */
      class ColumnAction extends AbstractAction
      {
          private boolean isSelectedColumn;
          private boolean isAdjust;
  
          public ColumnAction(boolean isSelectedColumn, boolean isAdjust)
          {
              this.isSelectedColumn = isSelectedColumn;
              this.isAdjust = isAdjust;
          }
  
          @Override
          public void actionPerformed(ActionEvent e)
          {
              //  Handle selected column(s) width change actions
  
              if (isSelectedColumn)
              {
                  int[] columns = table.getSelectedColumns();
  
                  for (int i = 0; i &lt; columns.length; i++)
                  {
                      if (isAdjust)
                          adjustColumn(columns[i]);
                      else
                          restoreColumn(columns[i]);
                  }
              }
              else
              {
                  if (isAdjust)
                      adjustColumns();
                  else
                      restoreColumns();
              }
          }
      }
  
      /*
       *  Toggle properties of the TableColumnAdjuster so the user can
       *  customize the functionality to their preferences
       */
      class ToggleAction extends AbstractAction
      {
          private boolean isToggleDynamic;
          private boolean isToggleLarger;
  
          public ToggleAction(boolean isToggleDynamic, boolean isToggleLarger)
          {
              this.isToggleDynamic = isToggleDynamic;
              this.isToggleLarger = isToggleLarger;
          }
  
          @Override
          public void actionPerformed(ActionEvent e)
          {
              if (isToggleDynamic)
              {
                  setDynamicAdjustment(! isDynamicAdjustment);
                  return;
              }
  
              if (isToggleLarger)
              {
                  setOnlyAdjustLarger(! isOnlyAdjustLarger);
                  return;
              }
          }
      }
  }
  </code></pre>
  
  <p>**</p>
  
  <ul>
  <li>CutomTableCellRenderer.java</li>
  </ul>
  
  <p>**</p>
  
  <pre><code>package com.swing.data;
  
  import java.awt.Color;
  import java.awt.Component;
  
  import javax.swing.JLabel;
  import javax.swing.JTable;
  import javax.swing.table.DefaultTableCellRenderer;
  import javax.swing.table.TableCellRenderer;
  public class CutomTableCellRenderer extends DefaultTableCellRenderer 
  {   
      private TableCellRenderer mWrappedRenderer; 
      private String text = "Original";
      public String getText() {
          return text;
      }
  
      public void setText(String text) {
          this.text = text;
      }
  
      public CutomTableCellRenderer(TableCellRenderer pWrappedRenderer) { 
          mWrappedRenderer = pWrappedRenderer; 
          } 
  
      public Component getTableCellRendererComponent
         (JTable table, Object value, boolean isSelected,
         boolean hasFocus, int row, int column) 
      {
          Component cell = mWrappedRenderer.getTableCellRendererComponent(table, value, isSelected,
                     hasFocus, row, column); 
  
  
              if( row == 1 )
              {
  
                  JLabel label = (JLabel)cell;
                  label.setText(text);
              }
              else
              {
                  cell.setBackground( Color.white );
              }
  
          return cell;
      }
  }
  </code></pre>
  
  <p>From the above code the actual data in the model doesn't gets changed. But table width and height is not calculated correctly on first click of change button. On next change click the modified table width and height is shown. I am very new to this. </p>
  
  <p>How can I retrieve the actual width and height of JTable if data is changed from cell 
  renderer?</p>
  
  <p>How can I calculate table width and height properly.</p>