2

I decided to use a GridLayout LayoutManager for my Java Swing app because each cell within the grid is supposed to be exactly the same size.

From the Java Tutorials:

A GridLayout object places components in a grid of cells. Each component takes all the available space within its cell, and each cell is exactly the same size.

And even in the description of the GridLayout class:

The GridLayout class is a layout manager that lays out a container's components in a rectangular grid. The container is divided into equal-sized rectangles, and one component is placed in each rectangle.

However, my code seems to make a certain cell twice as large as the others. I added 3 JPanels to a Container with GridLayout, and gave each JPanel a different background color. This was the result:

enter image description here

Clearly, the first JPanel (red background) is twice as big as the others (green and yellow). The code that produced this is the following:

public void updateListFrameContentPane(Container mainPane) {
    mainPane.setLayout(new GridLayout(1,0));
    JPanel listPanel = new JPanel();
    listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.Y_AXIS));
    listPanel.add(friendsLabel);        
    listPanel.add(listScrollPane);
    listPanel.setBackground(Color.RED);
    mainPane.add(listPanel);
    for(JPanel chatPanel : chatPanels) {
        chatPanel.setBackground((Math.random()>0.5 ? Color.YELLOW : Color.GREEN));
        mainPane.add(chatPanel);
    }
}

All I do is set the Container's layout to GridLayout with 1 row and any number of columns, and then add 3 JPanels to that. So why is the first JPanel so much larger? Strangely this only happens when two or more chatPanels are added. When there is only one, it formats correctly.

asaini007
  • 858
  • 5
  • 19
  • They should be, and normally are, the same size just as the documentation says. Are you adding the components after the window has been made visible? If so, did you `revalidate()` the layout? – kiheru Jan 21 '14 at 21:47
  • Are you adding components to `mainPane` in another method? –  Jan 21 '14 at 21:49
  • @JohnGaughan no, this method is run each time I want to add components – asaini007 Jan 21 '14 at 21:56
  • @kiheru Yes, I am. What does revalidate() do? I can't find the method in `GridLayout` – asaini007 Jan 21 '14 at 21:57
  • It's a method of `JComponent`, not that of the layout manager. It will eventually results in recalculating the layout. The customary thing to do after changing contents of a container at run time is calling `revalidate(); repaint();` – kiheru Jan 21 '14 at 22:06
  • @asaini007 the reason I ask is because it appears there is a fourth cell to the left of `listPanel`. Are you sure the code that calls this method is not adding anything to it? Is there another panel that contains `listPanel` which has another component? –  Jan 21 '14 at 22:08
  • 1
    Yes, are cells in a GridLayout are the same size. Reposting a question (http://stackoverflow.com/q/21244363/131872) will not help you get an answer. Instead post a proper [MVCE](http://stackoverflow.com/help/mcve) that demonstrates the problem. Most time when you attempt to create the MVCE you will solve your own problem. – camickr Jan 21 '14 at 23:14
  • Please have a look at the [difference between validate(), revalidate() and invalidate()](http://stackoverflow.com/q/9510125/1057230). Hope it explains a bit :-) – nIcE cOw Jan 22 '14 at 01:18

1 Answers1

1

Kiheru is right. revalidate/repaint after changing the contents of a container. Here's a rough but working example:

public class GridLayoutExample {

private JFrame frame;
private Map<String,JPanel> chatBoxes = new HashMap<String,JPanel>();
private String lastKey = "0";

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                GridLayoutExample window = new GridLayoutExample();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the application.
 */
public GridLayoutExample() {
    initialize();
}

private void addChatBox() {
    /*
     * JPanel (border layout)
     * - JPanel (Border South, Border layout)
     * - - JTextField ( Border center )
     * - - JButton ( Border east )
     * - JLabel (Border North )
     * - JTextArea (Border Center);
     */
    int lk = Integer.valueOf(lastKey)+1;
    lastKey = Integer.toString(lk);
    JPanel np = new JPanel();
    np.setLayout(new BorderLayout(0,0));
    np.setBackground((lk%2 == 0) ? Color.GREEN : Color.YELLOW);

    JPanel south = new JPanel();
    south.setLayout(new BorderLayout(0,0));
    np.add(south,BorderLayout.SOUTH);

    JButton b = new JButton("New Button");
    south.add(b,BorderLayout.EAST);

    JTextField field = new JTextField();
    south.add(field,BorderLayout.CENTER);

    JLabel label = new JLabel(lastKey);
    label.setHorizontalAlignment(SwingConstants.CENTER);
    np.add(label,BorderLayout.NORTH);

    JTextArea text = new JTextArea();
    np.add(text,BorderLayout.CENTER);

    chatBoxes.put(lastKey, np);
    frame.getContentPane().add(np);
    frame.revalidate();                 // CRITICAL MISSING LINES
    frame.repaint();                    // CRITICAL MISSING LINES
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 923, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(new GridLayout(1, 0, 0, 0));

    JPanel panel = new JPanel();
    panel.setBackground(Color.RED);
    frame.getContentPane().add(panel);
    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

    JLabel lblNewLabel = new JLabel("Online Users");
    panel.add(lblNewLabel);

    JList list = new JList();
    list.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            addChatBox();
        }
    });
    list.setModel(new AbstractListModel() {
        String[] values = new String[] {"Alpha", "Beta", "Gamma", "Delta", "Epsilon"};
        public int getSize() {
            return values.length;
        }
        public Object getElementAt(int index) {
            return values[index];
        }
    });
    panel.add(list);

}
}

I chose to revalidate/repaint the entire frame, but it may be possible to have it work while repainting a lesser container. Certainly without the critical lines marked above, it doesn't matter how often you click on the list elements, nothing new will show up. With those lines, every time you click, a new chatbox is added.

Huh... just noticed this. If the red area is considered two separate panels, then they're all the exactly correct size. Have you perhaps accidentally added an extra panel?

EdwinW
  • 1,007
  • 2
  • 13
  • 32
  • `Have you perhaps accidentally added an extra panel?` - That is why the OP has been asked for an `MVCE`. We can't tell what he is doing wrong based on 10 lines of code. The problem is surely with code that is not posted. – camickr Jan 22 '14 at 02:08