Home > Enterprise >  Why doesn't frame.pack() work with a JTable?
Why doesn't frame.pack() work with a JTable?

Time:02-05

I have a super basic JTable which I'm adding to a JFrame, but for some reason frame.pack() doesn't work. I'm setting the row height to the column width so that the cells of the table are squares, but this doesn't seem to work when the window is resized. So how can I make it so that the cells of the table are always squares, even when resized, and the frame is properly packed? Here's the code for the window:

package me.an.ar.window;

import java.awt.Container;

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

public class DayPlanner
{
    private JFrame frame;

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

        Container container = frame.getContentPane();

        Object[][] data = new Object[5][7];
        String[] columnNames = { "Day1", "Day2", "Day3", "Day4", "Day5", "Day6", "Day7" };
        JTable table = new JTable(data, columnNames);

        for (int col = 0; col < table.getColumnCount(); col  )
        {
            for (int row = 0; row < table.getRowCount(); row  )
            {
                int colWidth = table.getColumnModel().getColumn(col).getWidth();
                table.setRowHeight(row, colWidth);
            }
        }

        container.add(new JScrollPane(table));

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void show()
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    public DayPlanner()
    {
        show();
    }

    public static void main(String[] args)
    {
        new DayPlanner();
    }
}

CodePudding user response:

You did not set any LayoutManager. The default is not a FlowLayout but at least not null:

The default content pane will have a BorderLayout manager set on it. (Java 17 API)

This would mean by resizing the window you would more have to fight with the scrollpane's resizing. What happens if you use

container.add(new JScrollPane(table), BorderLayout.CENTER);

That should let the scrollpane grow and shrink with the frame, and the amount of rows/columns inside the table might vary. This might also get impacted by JTable.setAutoResizeMode().

CodePudding user response:

Option 1

You haven't really mentioned how you are about to use this table (what data will be held and how the user is expected to interact with); however, it sounds like a use case for GridLayout (regarding data cells), as well as GridBagLayout (regarding header cells). Example below:

public class DayPlanner {
    private JFrame frame;
    Dimension cellSize = new Dimension(75, 75);

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

        // Create header cells
        JPanel p1 = new JPanel(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        String[] columnNames = { "Day 1", "Day 2", "Day 3", "Day 4", "Day 5", "Day 6", "Day 7" };
        int count = 0;
        for (int i = 0; i < columnNames.length; i  ) {
            JLabel l = new JLabel(columnNames[i], SwingConstants.CENTER);
            l.setFont(new Font("Times New Roman", Font.BOLD, 14));
            l.setBackground(new Color(238, 238, 238));
            l.setOpaque(true);
            l.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, new Color(122, 138, 153)));
            c.fill = GridBagConstraints.HORIZONTAL;
            c.ipady = 5; // adjusts cell's height
            c.weightx = 0.5;
            c.gridx = count  ;
            c.gridy = 0;
            p1.add(l, c);
        }

        // Create data cells
        JPanel p2 = new JPanel();
        p2.setLayout(new GridLayout(5, 7));
        for (int i = 0; i < 35; i  ) {
            JLabel l = new JLabel("<html> This is some sample text "   i   "</html>"); // html tags allow text-wrapping
            l.setFont(new Font("Times New Roman", Font.PLAIN, 14));
            l.setVerticalAlignment(SwingConstants.TOP);
            l.setHorizontalAlignment(SwingConstants.LEFT);
            l.setPreferredSize(cellSize);
            l.setBackground(Color.WHITE);
            l.setOpaque(true);
            l.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 1, new Color(122, 138, 153)));
            p2.add(l);
        }


        JScrollPane sp = new JScrollPane(p2);
        sp.getVerticalScrollBar().setUnitIncrement((int) cellSize.getHeight() / 2); // adjusts scrolling speed
        sp.getViewport().setBackground(Color.WHITE);
        Container container = frame.getContentPane();
        container.add(p1, BorderLayout.NORTH);
        container.add(sp, BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

Option 2

If you still want to use the JTable given in your question, you could add a ComponentListener to your JFrame, so that you can listen to "resize events", allowing you to readjust the cells' size and retain their square shape.

frame.addComponentListener(new ComponentAdapter() {
    public void componentResized(ComponentEvent evt) {
        for (int row = 0; row < table.getRowCount(); row  ) {
            int colWidth = table.getColumnModel().getColumn(0).getWidth();
            table.setRowHeight(row, colWidth);
        }
    }
});

As for the pack() issue, you could set the initial size of the JFrame according to the columns and rows in your table (remember to comment out frame.pack();). The below, although it would remove the empty space at the bottom of the frame, it wouldn't, however, stop the user from resizing the window and bringing that back.

int colWidth = table.getColumnModel().getColumn(0).getWidth();
frame.setSize(7 * colWidth, 5 * table.getRowHeight(0)   25);
//frame.pack();
  •  Tags:  
  • Related