GridLayout does not populate JPanel

I have a problem with GridLayout and the whole JPanel is not populating. I have an N * M grid and I fill it with N * M tiles (they extend the JPanel). After adding all these fragments, there is still a place below and to the right of JPanel. I thought GridLayout was supposed to populate the entire JPanel and do everything in it evenly?

Edit: I did not want to publish all the code, as there are several classes. Perhaps there was a simple solution.

public class MainFrame extends JFrame { private static final long serialVersionUID = 3985493842977428355L; private final int FRAME_HEIGHT = 800; private final int FRAME_WIDTH = 700; private MainPanel mainPanel; public MainFrame() { super("Test"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(FRAME_HEIGHT, FRAME_WIDTH); setLocationRelativeTo(null); mainPanel = new MainPanel(); getContentPane().add(mainPanel); setVisible(true); } } public class MainPanel extends JPanel { /** * */ private static final long serialVersionUID = 3421071253693531472L; private RoutePanel routePanel; private ControlPanel controlPanel; private GridBagConstraints gridBagConstraints; private GridBagLayout gridBagLayout; public MainPanel() { routePanel = new RoutePanel(); controlPanel = new ControlPanel(); setBackground(Color.black); gridBagLayout = new GridBagLayout(); setLayout(gridBagLayout); gridBagConstraints = new GridBagConstraints(); createLayout(); } private void createLayout() { gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 1; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagLayout.setConstraints(routePanel, gridBagConstraints); add(routePanel); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = .05; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = GridBagConstraints.SOUTH; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagLayout.setConstraints(controlPanel, gridBagConstraints); add(controlPanel); } } public class RoutePanel extends JPanel{ /** * */ private static final long serialVersionUID = 4366703088208967594L; private final int GRID_ROWS = 30; private final int GRID_COLS = 47; public RoutePanel() { setLayout(new GridLayout(GRID_ROWS, GRID_COLS, 0, 0)); for(int i = 0; i < GRID_ROWS * GRID_COLS; i++) { add(new Tile()); } setBackground(Color.orange); } } public ControlPanel() { } public Tile() { setBackground(Color.gray); Border blackline; blackline = BorderFactory.createLineBorder(Color.black); setBorder(blackline); } 
+4
source share
2 answers

Since you are not sending the code, we are forced to guess (and this is not good).

My guess: you can specify the size or preferred sizes of some of your components or the GUI, and this causes spaces at the edges of your GUI.

Solution: do not do this. Have the components themselves compose with their preferred sizes and layout managers when pack() is called in the GUI.

For more helpful help, create and publish sscce . For such a question, the code is indeed mandatory, and I'm a little surprised that you did not post your messages.


Change 1

For example, pay attention to the difference in the created GUI:

 import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import javax.swing.*; public class GapExample { private static final int M = 5; private static final int N = 6; private static final int PREF_W = 700; private static final int PREF_H = 500; @SuppressWarnings("serial") private static void createAndShowGui() { // *** attempt 1: set preferredSize of the mainPanel JPanel *** JPanel mainPanel = new JPanel(new GridLayout(M, N)); mainPanel.setBorder(BorderFactory.createLineBorder(Color.red)); mainPanel.setPreferredSize(new Dimension(PREF_W, PREF_H)); for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { String text = String.format("Foo [%d, %d]", i, j); JLabel label = new JLabel(text, SwingConstants.CENTER); label.setBorder(BorderFactory.createLineBorder(Color.blue)); mainPanel.add(label); } } JOptionPane.showMessageDialog(null, mainPanel, "Attempt 1, setPreferredSize of mainPane", JOptionPane.PLAIN_MESSAGE); // *** attempt 2: override the getPreferredSize of the JLabel cells in the // grid *** mainPanel = new JPanel(new GridLayout(M, N)); mainPanel.setBorder(BorderFactory.createLineBorder(Color.red)); final Dimension labelPrefSize = new Dimension(PREF_W / N, PREF_H / M); for (int i = 0; i < M; i++) { for (int j = 0; j < N; j++) { String text = String.format("Foo [%d, %d]", i, j); JLabel label = new JLabel(text, SwingConstants.CENTER) { @Override public Dimension getPreferredSize() { return labelPrefSize; } }; label.setBorder(BorderFactory.createLineBorder(Color.blue)); mainPanel.add(label); } } JOptionPane .showMessageDialog(null, mainPanel, "Attempt 2, override getPreferredSize of the JLabel cells in the grid", JOptionPane.PLAIN_MESSAGE); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } } 

In the second dialog box, I have JLabels that returns the preferred size, and let the containers that hold them set the best size for the GUI to display, and with the second attempt, the grid will be much better.

This shows for the first (bad) attempt a gap between the internal and external components:

enter image description here

And the second (good) attempt does not show such a gap:

enter image description here

+7
source

GridLayout was supposed to fill the whole JPanel and do everything in it evenly

these two are opposite forces, the manager can do both at the same time only if the panel width is a multiple of the column width:

 panel.width == column.width * column.count 

If this is not possible, it maintains the restriction of equal size by determining the size of the children to the largest width to make them equal, and positions the entire block in the center of the parent, thereby exposing the parent background. Basically, you see the effects of integer math :-)


As for the discussion in another answer ,

First: my setXXSize trick is well known - it is always mistakenly used in application code. I think it was a design crash, it should never have happened in the first because most of the time it introduces more problems than it seems (superficially!) , to solve.

The closest solution seems to override getXXSize: if you do this to return an arbitrary fixed fixed size, it is only slightly better than calling setXXSize (if the worst methods are not propagated :): the return value should be related to the internal state. It should contain an internal calculation (if any), which may be intact and may modify it. Plus, strictly speaking, it must correspond to a supercontract that really indicates (a little hidden in setXXSize) that the size applied through setXXSize takes precedence

Sets the preferred size of this component to a constant value. Subsequent calls to getPreferredSize always return this value.

In code:

 // always wrong in application code someComponent.setPreferredSize(labelPrefSize); // suboptimal: arbitrary hard-coded fixed size @Override public Dimension getPreferredSize() { return new Dimension(labelPrefSize); } // good: fixed value based on internal state @Override public Dimension getPreferredSize() { return new Dimension(labelPrefSize); } // the size has some meaning fi when painting @Override protected void paintComponent(Graphics g) { g.drawRect(0, 0, labelPrefSize.width, labelPrefSize.height); } // good: prefsize relative to super calculation @Override public Dimension getPreferredSize() { Dimension labelPrefSize = super.getPreferredSize(); int maxSide = Math.max(labelPrefSize.width, labelPrefSize.height); labelPrefSize.setSize(maxSide, maxSide); return labelPrefSize; } // better: prefsize relative to default calculation // _and_ comply to super contract @Override public Dimension getPreferredSize() { Dimension labelPrefSize = super.getPreferredSize(); if (isPreferredSizeSet()) return labelPrefSize; // any of the good thingies ... } 

Ideally, however, you would not touch on the internal calculation of prompts. Instead, use the LayoutManager, which allows you to fine-tune the layout to suit your needs. Remember: the manager takes the hints and has the right to size, but she likes it anyway :-)

Update

edited above, trying to emphasize the “related to the internal state”: size tips should return their isolated, egocentric demand, not caring about the context. Therefore, redefinition for the return of something that is like an external necessity is suboptimal.

+3
source

Source: https://habr.com/ru/post/1491235/


All Articles