GridLayout没有填充JPanel

我遇到了GridLayout的问题,并且整个JPanel没有被填充。 我有一个N * M网格,我用N * M Tiles填充它(它们扩展了JPanel)。 添加所有这些图块后,JPanel的底部和右侧仍有空间。 我认为GridLayout应该填满整个JPanel,并使其中的所有内容均匀分布?

编辑:我不想发布所有代码,因为有多个类。 想到也许有一个简单的解决方案。

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); } 

由于您没有发布代码,我们不得不猜测(这并不好)。

我的猜测:您可能正在设置某些组件或GUI的大小或首选大小,这会导致GUI边缘出现间隙。

解决方案:不要这样做。 在GUI上调用pack()时,让组件通过其首选大小和布局管理器自行resize。

有关更多有用的帮助,请创建并发布您的sscce 。 对于这样的问题,代码确实是强制性的,实际上我没有发布你的代码,我有点惊讶。


编辑1

例如,请注意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(); } }); } } 

在第二个对话框中,我让JLabel返回一个首选大小,并让容纳它们的容器设置为显示GUI的最佳大小,并且您将进行第二次尝试,网格更适合。

这显示第一次(坏)尝试内部和外部组件之间的差距:

在此处输入图像描述

第二次(好的)尝试没有显示出这样的差距:

在此处输入图像描述

GridLayout应该填满整个JPanel,并使其中的所有内容均匀分布

这两个是相反的力量,只有当面板宽度是列宽的倍数时,管理者才能同时做两个:

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

如果这是不可能的,它有利于等大小约束,通过将子节点调整到最大宽度以使它们相等并将整个块定位在父节点的中心,从而暴露父节点的背景。 基本上,你看到整数数学的影响:-)


至于其他答案的讨论 ,

首先:我对setXXSize的看法是众所周知的 – 在应用程序代码中使用它总是错误的我认为这是一个设计意外,首先应该永远不会发生,因为大多数时候它引入了比看起来更多的问题(表面上看!)解决。

下一个最近的解决方案似乎覆盖了getXXSize:如果完成返回任意硬编码的固定大小,它只比调用setXXSize稍微好一点(在不传播最差实践:) :):返回值应该与内部状态相关。 它应该保持超级完整的内部计算(如果有的话)并且可以修改它。 另外严格来说,它应该符合super的合同,它确实表明(在setXXSize中有点隐藏)通过setXXSize应用的维度优先

将此组件的首选大小设置为常量值。 对getPreferredSize的后续调用将始终返回此值。

在代码中:

 // 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's 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's contract @Override public Dimension getPreferredSize() { Dimension labelPrefSize = super.getPreferredSize(); if (isPreferredSizeSet()) return labelPrefSize; // any of the good thingies ... } 

但理想情况下,您根本不会触及尺寸提示的内部计算。 而是使用LayoutManager,它允许微调布局以完全满足您的需要。 请记住:经理接受提示并且无论如何都可以随意resize:-)

更新

编辑上面试图强调“与内部状态相关”的东西:尺寸提示应该返回他们自己孤立的,以自我为中心的要求而不关心背景。 所以最重要的是返回满足外界需求的东西是不理想的。