1

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();
    }
}
Chris
  • 18,724
  • 6
  • 46
  • 80
Denny Williams
  • 109
  • 1
  • 7
  • 1
    1) add the scroll pane to the CENTER of the BorderLayout. 2) You need to define the resize behaviour of the JTable. Check out the `setAutoResizeMode(...)` method. *So how can I make it so that the cells of the table are always squares,* - only the width will be resized. There is no automatic resizing of heights. – camickr Feb 03 '22 at 22:17
  • 1
    I don't think a `JTable` is the right component for this. Perhaps instead look to this question about the [layout of a chess board](https://stackoverflow.com/q/21142686/418556). It includes answers from both myself and @camickr, and discusses (more camickr) the pitfalls of layout when the available space cannot accommodate same size cells. – Andrew Thompson Feb 03 '22 at 22:26

2 Answers2

0

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().

Queeg
  • 7,748
  • 1
  • 16
  • 42
  • Yeah, but doesn't the container have FlowLayout by default? I thought it wouldn't matter. – Denny Williams Feb 03 '22 at 22:03
  • Ok, I tried with the BorderLayout, but it works exactly the same. With FlowLayout the table didn't resize at all, and with the BorderLayout it works exactly the same as before. – Denny Williams Feb 03 '22 at 22:18
0

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();
Chris
  • 18,724
  • 6
  • 46
  • 80