2013-07-13 131 views
4

我遇到了GridLayout的問題,並且沒有填充整個JPanel。我有一個N * M網格,我用N * M Tiles填充(它們擴展了JPanel)。添加所有這些瓷磚後,JPanel的底部和右側仍有空間。我認爲GridLayout應該填滿整個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); 
    } 
+0

下一次,請顯示SSCCE(上面沒有) - 特別是佈局問題不能完全支持沒有 – kleopatra

回答

7

由於您沒有發佈代碼,我們被迫猜測(這不是很好)。

我的猜測是:您可能正在設置一些組件或GUI的大小或首選大小,這會在GUI的邊緣造成間隙。

解決方法:不要這樣做。在GUI上調用pack()時,讓組件通過它們的首選大小和佈局管理器自行調整大小。

如需更多幫助,請創建併發布您的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,並且在第二次嘗試時,網格會更好。

這將顯示第一(壞)嘗試內部與外部部件之間的間隙:

enter image description here

第二(好)嘗試,並顯示沒有這樣的間隙:

enter image description here

+0

我有一個包的問題是它調整了一切,並使GUI非常小。 – Taztingo

+1

@ user1932934您使用包的問題是,您的子組件未向佈局管理器提供足夠準確的信息,以便他們針對程序的整體大小作出適當決策。 – MadProgrammer

+0

@ user1932934:請參閱編輯以進行回答。 –

3

GridLayout應該填滿整個JPanel,並且使其中的所有物品均勻大小

這兩個是相反的力量,管理者可以在只有當面板寬度爲列寬的倍數,同時做到既:

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

如果這是不可能的,這有利於平等-size約束,通過調整兒童的最大寬度來使它們相等,並將整個塊定位在父母的中心,從而暴露父母的背景。基本上,你所看到的整數運算的效果:-)


至於discussion in the other answer

第一關:我拿上setXXSize是衆所周知的 - it's always wrong to use in application code我認爲這是一個設計的事故,不應該首先發生了,因爲大多數時候它引入了比看起來(表面上的!)更多的問題來解決。

下一個最接近的解決方案似乎覆蓋getXXSize:如果做返回任意硬編碼固定大小,它只是比調用setXXSize(在不傳播最壞的做法:)稍好一點:返回值應該與內部狀態。它應該保持超級完整的內部計算(如果有的話)並且可以修改它。另外嚴格地說,應該遵守超的合同這的確規定(有點隱藏在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 f.i. 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可以對佈局進行微調,使其完全符合您的需求。請記住:管理程序將提示和自由大小但是她反正喜歡:-)

更新

編輯上面試圖強調「相關內部狀態」啄:施膠提示應返回他們自己孤立的,以自我爲中心的需求而不關心上下文。因此,壓倒一切的回報外部需求是不理想的。