title: Drawing JTable rows and columns on a Panel
body: <p>I am writing one application in which I have to draw JTable component on a canvas. But after my several attempts still unable to draw a completely perfect picture of a JTable. I tried to draw using sizes of specific cells of a JTable using getCellRect api, but when data is big not able to draw specific cells on the canvas. Here is the sample code:-</p>
  
  <pre><code>import javax.swing.JFrame;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.JTable;
  import javax.swing.*;
  import java.awt.Dimension;
  import java.awt.GridLayout;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import javax.swing.table.*;
  import java.util.*;
  import java.awt.*;
  
  public class SimpleTableDemo extends JPanel {
      private boolean DEBUG = false;
        private int spacing = 6;
        private Map columnSizes = new HashMap();
        String[] columnNames = {"First Name",
                                  "Last Name",
                                  "Sport",
                                  "# of Years",
                                  "Vegetarian"};
  
          Object[][] data = {
          {"Kathy", "Smith",
           "SnowboardingXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 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)}
          };
  
          final JTable table = new JTable(data, columnNames);
          Panel1 panel;
  
      public SimpleTableDemo() {
          super(new GridLayout(3,0));
  
  
          table.setPreferredScrollableViewportSize(new Dimension(500, 70));
          //table.setFillsViewportHeight(true);
  
          if (DEBUG) {
              table.addMouseListener(new MouseAdapter() {
                  public void mouseClicked(MouseEvent e) {
                      printDebugData(table);
                  }
              });
          }
  
          //Create the scroll pane and add the table to it.
          JScrollPane scrollPane = new JScrollPane(table);
  
          //Add the scroll pane to this panel.
          add(scrollPane);
  
          panel = new Panel1();
          Rectangle rect = table.getCellRect(0,0,true);
  
          panel.setX(table.getWidth());
          panel.setY(0);
          panel.setWidth(rect.width);
          panel.setHeight(rect.height);
          panel.setStr(table.getModel().getValueAt(0,0).toString());
          panel.setModel(table);
  
          add(panel);
  
          final JComboBox jNumberComboBoxSize = new JComboBox();
          jNumberComboBoxSize.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "11", "12", "14", "16", "18", "20", "24", "30", "36", "48", "72" }));
          jNumberComboBoxSize.addActionListener(new java.awt.event.ActionListener() {
              public void actionPerformed(java.awt.event.ActionEvent evt) {
                 jNumberComboBoxSizeActionPerformed(jNumberComboBoxSize);
              }
          });
  
          JPanel panel2 = new JPanel();
          panel2.add(jNumberComboBoxSize);
  
          add(panel2);
          adjustColumns();
  
      }
  
      private void jNumberComboBoxSizeActionPerformed(JComboBox jNumberComboBoxSize)
      {
          int fontSize = Integer.parseInt(jNumberComboBoxSize.getSelectedItem().toString());
          table.setRowHeight(fontSize);
          table.setFont(new Font("Serif", Font.BOLD, fontSize));
          Rectangle rect = table.getCellRect(0,0,true);
          panel.setX(0);
          panel.setY(0);
         // panel.setWidth(rect.width);
          panel.setHeight(rect.height);
          panel.setStr(table.getModel().getValueAt(0,0).toString());
          panel.setModel(table);
          panel.repaint();
          table.revalidate();
      }
  
      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("--------------------------");
      }
  
       /*
       *  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);
          panel.setWidth(preferredWidth);
          updateTableColumn(column, preferredWidth);
      }
  
      /*
       *  Calculated the width based on the column name
       */
      private int getColumnHeaderWidth(int column)
      {
          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)
      {
          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
  
          width = Math.max(width, tableColumn.getPreferredWidth());
  
  
          columnSizes.put(tableColumn, new Integer(tableColumn.getWidth()));
          table.getTableHeader().setResizingColumn(tableColumn);
          tableColumn.setWidth(width);
      }
  
      /**
       * 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();
              }
          });
      }
  }
  
  class Panel1 extends JPanel
  {
      int x;
      int y;
      int width;
      int height;
      String str;
      JTable model;
  
      public void setModel(JTable model)
      {
         this.model = model;
      }
  
      public void setX(int x)
      {
          this.x = x;
      }
  
      public void setY(int y)
      {
          this.y = y;
      }
  
      public void setWidth(int w)
      {
          this.width = w;
      }
  
      public void setHeight(int h)
      {
          this.height = h;
      }
  
      public void setStr(String s)
      {
          this.str = s;
      }
  
      public void paint(Graphics g)
      {
          super.paint(g);
          int initX= 0;
          for(int row=0;row &lt; 5; ++row)
          {
              initX = x;
              for (int col=0;col &lt; 5;++col)
              {
                  g.drawRect(x,y,width,height);
                  g.drawString(model.getModel().getValueAt(row,col).toString(),x + 10,y + 10);
                  x = x + width;
              }
              x = initX;
              y = y + height;
  
          }
  
      }
  };
  </code></pre>
  
  <hr>
  
  <p>I modified this code to redraw column cells with Font sizes and borders. I want to draw all these table customizations, Please take a look and suggest something.</p>
  
  <p>Thanks</p>
  
  <p><strong>SimpleTableDemo.java</strong></p>
  
  <pre><code>   package com.swing.data;
  
  
  import java.awt.Color;
  import java.awt.Component;
  import java.awt.Dimension;
  import java.awt.Font;
  import java.awt.GridLayout;
  import java.awt.Rectangle;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.util.HashMap;
  import java.util.Map;
  
  import javax.swing.BorderFactory;
  import javax.swing.JComboBox;
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.JTable;
  import javax.swing.table.TableCellRenderer;
  import javax.swing.table.TableColumn;
  import javax.swing.table.TableColumnModel;
  
  public class SimpleTableDemo extends JPanel 
  {
      private boolean DEBUG = false;
      private int spacing = 6;
      private Map columnSizes = new HashMap();
      String[] columnNames = {"First Name","Last Name","Sport","# of Years","Vegetarian"};
  
      Object[][] data = 
          {
              {"Kathy", "Smith","SnowboardingXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 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)}
          };
  
      JTable table = new JTable(data, columnNames);
      Panel1 panel;
  
      public SimpleTableDemo() 
      {
          super(new GridLayout(3,0));      
          table.setPreferredScrollableViewportSize(new Dimension(500, 70));
          if (DEBUG) 
          {
              table.addMouseListener(new MouseAdapter() {
                  public void mouseClicked(MouseEvent e) {
                      printDebugData(table);
                  }
              });
          }
          //Create the scroll pane and add the table to it.
          JScrollPane scrollPane = new JScrollPane(table);
  
  
          //Add the scroll pane to this panel.
          add(scrollPane);
  
          panel = new Panel1();
  //      Rectangle rect = table.getCellRect(0,0,true);
  //
  // 
  //      panel.setX(table.getWidth());
  //
  //      panel.setY(0);
  //      panel.setWidth(rect.width);
  //      panel.setHeight(rect.height);
  //      panel.setStr(table.getModel().getValueAt(0,0).toString());
  
          panel.setModel(table);
  
          add(panel);
  
          final JComboBox jNumberComboBoxSize = new JComboBox();
          jNumberComboBoxSize.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "11", "12", "14", "16", "18", "20", "24", "30", "36", "48", "72" }));
          jNumberComboBoxSize.addActionListener(new java.awt.event.ActionListener() {
              public void actionPerformed(java.awt.event.ActionEvent evt) {
                 jNumberComboBoxSizeActionPerformed(jNumberComboBoxSize);
              }
          });
  
          JPanel panel2 = new JPanel();
          panel2.add(jNumberComboBoxSize);
  
          add(panel2);
          adjustColumns();
      }
  
      private void jNumberComboBoxSizeActionPerformed(JComboBox jNumberComboBoxSize)
      {
          int fontSize = Integer.parseInt(jNumberComboBoxSize.getSelectedItem().toString());
          table.setRowHeight(fontSize);
          setBorder(new Font("Serif", Font.BOLD, fontSize));
          table.setFont(new Font("Serif", Font.BOLD, fontSize));
          panel.setFont(new Font("Serif", Font.BOLD, fontSize));
          Rectangle rect = table.getCellRect(0,0,true);
          panel.setX(0);
          panel.setY(0);
          panel.setHeight(rect.height);
          panel.setStr(table.getModel().getValueAt(0,0).toString());
          panel.setModel(table);
          panel.repaint();
          table.revalidate();
      }
  
      public void setBorder(Font f)
      {
          BorderCellRenderer cellRenderer = new BorderCellRenderer();
          cellRenderer.setColumnBorder(BorderFactory.createLineBorder(Color.BLACK, 2)); 
          cellRenderer.setFont(f);
          table.getColumnModel().getColumn(0).setCellRenderer(cellRenderer);
          table.getColumnModel().getColumn(1).setCellRenderer(cellRenderer);
  
      }
      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("--------------------------");
      }
  
       /*
       *  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(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);
          panel.setWidth(preferredWidth);
          updateTableColumn(column, preferredWidth);
      }
  
      /*
       *  Calculated the width based on the column name
       */
      private int getColumnHeaderWidth(int column)
      {
          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)
      {
          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));
  
              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
  
          width = Math.max(width, tableColumn.getPreferredWidth());
  
  
          columnSizes.put(tableColumn, new Integer(tableColumn.getWidth()));
          table.getTableHeader().setResizingColumn(tableColumn);
          tableColumn.setWidth(width);
      }
  
      /**
       * 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();
              }
          });
      }
  }
  
  **Panel1.java**
  
      package com.swing.data;
  
  import java.awt.Font;
  import java.awt.Graphics;
  import java.awt.Rectangle;
  
  import javax.swing.JPanel;
  import javax.swing.JTable;
  
  
  class Panel1 extends JPanel
  {
      int x;
      int y;
      int width;
      int height;
      String str;
      JTable model;
      Font font;
  
      public Font getFont() {
          return font;
      }
      public void setFont(Font font) {
          this.font = font;
      }
      public void setModel(JTable model)
      {
         this.model = model;
      }
      public JTable getModel()
      {
          return model;
      }
  
      public void setX(int x)
      {
          this.x = x;
      }
  
      public void setY(int y)
      {
          this.y = y;
      }
  
      public void setWidth(int w)
      {
          this.width = w;
      }
  
      public void setHeight(int h)
      {
          this.height = h;
      }
  
      public void setStr(String s)
      {
          this.str = s;
      }
  
      public void paint(Graphics g)
      {
          super.paint(g);
  //      int initX= 0;
  //      for(int row=0;row &lt; 5; ++row)
  //      {
  //          initX = x;
  //          for (int col=0;col &lt; 5;++col)
  //          {
  //              g.drawRect(x,y,width,height);
  //              String str = model.getModel().getValueAt(row, col).toString();
  //              int xloc =  (x+10);
  //              int yloc = y +10;
  ////                System.out.println("xloc : "+xloc);
  ////                System.out.println("yloc : "+yloc);
  ////                System.out.println("width : "+width);
  ////                System.out.println("height : "+height);
  ////                System.out.println("str : "+str);
  //              
  //              g.drawString(model.getModel().getValueAt(row,col).toString(),x + 10,y + 10);
  //              x = x + width;
  //          }
  //            x = initX;
  //          y = y + height;
  // 
  //      }
  
          System.out.println("Inside paint() &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;");
  
          JTable table = getModel();
          int columnCount = table.getModel().getColumnCount();
          int rowCount = table.getModel().getRowCount();
          int yLoc = 10;
          int rowHeight = 0 ;
          int columnWidth  = 0 ;
          g.setFont(font);
          for(int r = 0 ; r &lt; rowCount; r++)
          {
              int xLoc = 0 ;
              for(int c= 0 ; c&lt; columnCount; c++)
              {
                  Rectangle rect = table.getCellRect(r, c, true);
                  columnWidth = rect.width;
                  rowHeight = rect.height;
                  g.drawRect(xLoc, yLoc, columnWidth, rowHeight);
                  String displayString = table.getValueAt(r, c).toString(); 
                  System.out.println("displayString ::"+displayString);
                  g.drawString(displayString, xLoc+5, yLoc+15);
                  xLoc+= columnWidth; 
              }
              yLoc+= rowHeight;
          }
      }
  }
  
  **BorderCellRenderer.java**
  package com.swing.data;
  
  import java.awt.*;
  import javax.swing.*;
  import javax.swing.table.*;
  import javax.swing.border.*;
  
  /**
   * @version 1.0 03/06/99
   */
  public class BorderCellRenderer extends JLabel
      implements TableCellRenderer {
    protected Border noFocusBorder; 
    protected Border columnBorder; 
    protected Font font;
  
    public Font getFont() {
      return font;
  }
  
  public void setFont(Font font) {
      this.font = font;
  }
  
  public BorderCellRenderer() {
      noFocusBorder = new EmptyBorder(1, 2, 1, 2);
      setOpaque(true);
    }
  
    public Component getTableCellRendererComponent(JTable table, Object value,
                   boolean isSelected, boolean hasFocus, int row, int column) {
        setText((value == null) ? "" : value.toString());
        setBorder(columnBorder);
        setFont(font);
      return this;
    }
  
    public void setColumnBorder(Border border) {
      columnBorder = border;
    }
  
    public Border getColumnBorder() {
      return columnBorder;
    }
  }
  </code></pre>
  
  <p>Please suggest something to redraw the appropriate JTable font and borders.</p>