title: GridBagLayout: how to fill vertically using preferred width horizontally
body: <p>I have an issue trying to fill vertically a <code>JScrollPane</code> (which contains a <code>JTable</code>) inside a <code>JPanel</code>: the panel should not be filled horizontally, instead, the <code>JScrollPane</code> should take only the "necessary" space.</p>
  
  <p>I'm using some code found on SO to set the table preferred width according to its content (i'm also overrding  <code>JTable</code>'s <code>getPreferredScrollableViewportSize</code> method).</p>
  
  <p>This is a screenshot of what i want to achieve:</p>
  
  <p><a href="https://i.stack.imgur.com/aZD1e.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/aZD1e.jpg" alt="enter image description here"></a></p>
  
  <p>The <code>JPanel</code> is wider because in my application it will be part of a <code>CardLayout</code>, so the other cards width and height will determine this panel size (in the code below i'm overriding <code>getPreferredSize</code> method for convenience, but i don't want to use it).</p>
  
  <p>This result can be achieved using the below code, you only need to change this line of code:</p>
  
  <pre><code>Object [][] data = new Object [100][1];
  </code></pre>
  
  <p>to:</p>
  
  <pre><code>Object [][] data = new Object [10][1];
  </code></pre>
  
  <p>The problem is when the <code>JTable</code> has more rows, in this case the vertical scrollbar will appear, but the scroll pane will "shrink":</p>
  
  <p><a href="https://i.stack.imgur.com/IkOek.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/IkOek.jpg" alt="enter image description here"></a></p>
  
  <p>This is the code i'm using:</p>
  
  <pre><code>import java.awt.Dimension;
  import java.awt.GridBagConstraints;
  import java.awt.GridBagLayout;
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.JTable;
  import javax.swing.SwingUtilities;
  import javax.swing.table.TableColumn;
  public class TableTest
  {
      public static void main (String [] a) {
          SwingUtilities.invokeLater (new Runnable () {
              @Override public void run () {
                  createAndShowGUI ();
              }
          });
      }
      private static void createAndShowGUI () {
          JFrame frame = new JFrame ("Table Test");
          frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
          frame.setContentPane (new MainPanel ());
          frame.pack ();
          frame.setLocationRelativeTo (null);
          frame.setVisible (true);
      }
  }
  class MainPanel extends JPanel
  {
      private static int MAX_HEIGHT = 600;
      private static int MAX_WIDTH = 600;
  
      private JTable table;
  
      protected MainPanel () {
          super (new GridBagLayout ());
          Object [][] data = new Object [100][1];
          for (int i = 0; i &lt; 10; i ++) data [i] = new String [] {"Some data ..."};
          table = new JTable (data, new String [] {""}) {
              @Override public Dimension getPreferredScrollableViewportSize () {
                  int width = 0;
                  for (int column = 0; column &lt; getColumnCount (); column ++) width += columnModel.getColumn (column).getPreferredWidth ();
                  return new Dimension (Math.min (MAX_WIDTH, width), Math.min (MAX_HEIGHT, getRowHeight () * getRowCount ()));
              }
          };
          table.setAutoResizeMode (JTable.AUTO_RESIZE_OFF);
          table.setShowGrid (false);
          table.setTableHeader (null);
          resizeColumns ();
          JScrollPane scrollPane = new JScrollPane (table);
          scrollPane.setBackground (table.getBackground ());
          scrollPane.getViewport ().setBackground (table.getBackground ());
          // --- Adding components ---
          GridBagConstraints c = new GridBagConstraints ();
          c.fill = GridBagConstraints.VERTICAL;
          c.weightx = 0.0;
          c.weighty = 1.0;
          add (scrollPane, c);
      }
      @Override public Dimension getPreferredSize () {
          return new Dimension (500, 400);
      }
      protected void resizeColumns () {
          for (int column = 0; column &lt; table.getColumnCount (); column ++) {
              TableColumn tableColumn = table.getColumnModel ().getColumn (column);
              int width = 0;
              for (int row = 0; row &lt; table.getRowCount (); row ++) {
                  width = Math.max (table.prepareRenderer (table.getCellRenderer (row, column), row, column).getPreferredSize ().width, width);
              }
              tableColumn.setPreferredWidth (width + table.getIntercellSpacing ().width);
          }
      }
  }
  </code></pre>
  
  <p>If i set <code>c.fill</code> to <code>GridBagConstraints.BOTH</code> and <code>c.weightx</code> to any positive value, the <code>JScrollPane</code> will fill the parent panel both horizontally and vertically.</p>
  
  <p>How can i let the table's preferred width to be used without manually setting the <code>JScrollPane</code> size? </p>
  
  <p><strong>EDIT</strong></p>
  
  <p>My code is very minimal, since i saw that my problem was not related to the number of table columns. But my real program has to deal with more columns, and a huge number of rows (a million or more in many cases). </p>
  
  <p>A <code>JList</code> was my first try, since i liked the way i could use a prototype value, but it was too slow to load the data (which can also be updated at runtime), all the GUI freezed with more than 200 000 rows, also due to the fact that i'm using a custom renderer.</p>
  
  <p>Also, i already tried to use a <code>BorderLayout</code>, but i really want the scrollpane height to fill my panel, i have tried different solutions, but still i can't solve it.</p>
  
  <p><strong>EDIT2</strong></p>
  
  <p>As @camickr suggests, i could use a BorderLayout for my panel, adding the scrollpane at BorderLayout.WEST to fill the panel vertically wihout taking all the horizontal space. This is the best solution for now, but this will cause the horizontal center alignment to be lost. Any ideas?</p>