User892313
User892313

Reputation: 245

Make JTable rows fill the entire height of JScrollPane

I've got a JTable inside a JScrollPane inside a JPanel. I would like to make the rows of the JTable fill the entire height of the JPanel. Like, if i have 10 rows, they strech out in height direction and fill the entire JPanel, and and if i add 10 more rows, the rows should resize so i could fit all 20 rows in the JPanel.

I've managed to make the JScrollPane fill the entire height of the panel, but the table cells stay at a fixed size. Is there a way to do this? I suppose it might be possible to fire an event upon resizing the window and then set the row height using the window height and number of rows, but it sounds like a lot of work so if there is an easier way to do this i would be very happy :)

Upvotes: 3

Views: 1456

Answers (1)

Marco13
Marco13

Reputation: 54709

In fact, my initial guess from the comments (or things like JTable#setFillsViewportHeight) don't help here: They only affect the height of the table itself, but not the height of the table cells.

Additionally, the handling of cell heights is a bit tricky, and there may be many corner cases, considering own cell renderer, row margins or the fact that you may manually modify the heights of individual rows (which internally causes the construction of a dedicated model that manages these row heights).

For the simplest case, a ComponentListener that simply sets the global row height of the table based on the space that is available in the enclosing scroll pane might be an option:

import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;

public class TableFillViewportHeight
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        String[] columnNames = {
            "First Name", "Last Name", "Sport" };
        Object[][] data = {
            {"Kathy", "Smith", "Snowboarding" },
            {"John", "Doe", "Rowing" },
            {"Sue", "Black", "Knitting"},
            {"Jane", "White", "Speed reading" },
            {"Joe", "Brown", "Pool" }
        };

        final JTable table = new JTable(data, columnNames);
        final JScrollPane scrollPane = new JScrollPane(table);
        table.addComponentListener(new ComponentAdapter()
        {
            @Override
            public void componentResized(ComponentEvent e)
            {
                table.setRowHeight(16);
                Dimension p = table.getPreferredSize();
                Dimension v = scrollPane.getViewportBorderBounds().getSize();
                if (v.height > p.height)
                {
                    int available = v.height - 
                        table.getRowCount() * table.getRowMargin();
                    int perRow = available / table.getRowCount();
                    table.setRowHeight(perRow);
                }
            }
        });

        f.getContentPane().add(scrollPane);
        f.setSize(500,500);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}

But note that this is a ... somewhat "pragmatic" approach for solving this, and is only tested with (and intended for) the simplest case of a default table. A more elegant and flexible solution might involve some more effort.

Upvotes: 2

Related Questions