如何在GridBagLayout中让一个带有空JLabel的JPanel占据空间?

6
我正在学校的项目中为GUI编写程序,使用了swing中的GridBagLayout布局方式。我希望在布局中添加标签来指示输入内容(文件类型 @ x = 0, y = 0),接着是另一个标签(一旦选择了实际文件,则显示其名称 @ x=1,y=0),最后放置一个用于文件选择器的浏览按钮(@ x=2, y=0)。标签(1,0)最初为空,但当标签不包含文本时,我希望该文本占据一定的空间。同时,我还想保持标签(0,0)和按钮(2,0)之间的距离不变。
为了实现这个目标,我尝试将标签放到面板上,并进行布局调整。然而,我似乎无法达到所需的结果。是否有人可以提供一些建议?GridBagLayout的下三行将以完全相同的方式进行布局。
以下是GUI屏幕截图的链接:The pic
    calibrationFileSelectionValueLabel = new JLabel("",Label.LEFT);
    calibrationFileSelectionValueLabel.setName("calibrationFileSelection");
    calibrationFileSelectionValueLabel.setMinimumSize(new Dimension(100,0));



    calibrationFileSelectionValuePanel = new JPanel();
    calibrationFileSelectionValuePanel.setBorder(BorderFactory.createEtchedBorder());
    calibrationFileSelectionValuePanel.add(calibrationFileSelectionValueLabel);

    c.gridx = 0;
    c.gridy = 0;
    c.fill = GridBagConstraints.NONE;

    filesPanel.add(calibrationFileLabel,c);

    c.gridy = 1;
    filesPanel.add(frequencyFileLabel,c);

    c.gridy = 2;
    filesPanel.add(sampleFileLabel,c);

    c.gridy = 3;
    filesPanel.add(outputFileLabel,c);

    c.gridx = 1;
    c.gridy = 0;
    c.fill = GridBagConstraints.BOTH;

   // filesPanel.add(calibrationFileSelection,c);
    filesPanel.add(calibrationFileSelectionValuePanel,c);

    c.gridy = 1;
   // filesPanel.add(frequencyFileSelection,c);
    filesPanel.add(frequencyFileSelectionValueLabel,c);

    c.gridy = 2;
   // filesPanel.add(sampleFileSelection,c);
    filesPanel.add(sampleFileSelectionValueLabel,c);

    c.gridy = 3;
   // filesPanel.add(outputFileSelection,c);
    filesPanel.add(outputFileSelectionValueLabel,c);

    c.gridx = 2;
    c.gridy = 0;
    c.fill = GridBagConstraints.NONE;
    filesPanel.add(calibrationFileSelectionButton,c);

    c.gridy = 1;
    filesPanel.add(frequencyFileSelectionButton,c);      

    c.gridy = 2;
    filesPanel.add(sampleFileSelectionButton,c);

    c.gridy = 3;
    filesPanel.add(createOutputFileButton,c);       

    panelForFilesPanelBorder = new JPanel();
    panelForFilesPanelBorder.setBorder(BorderFactory.createCompoundBorder(new EmptyBorder(5,10,5,10), BorderFactory.createEtchedBorder()));
    panelForFilesPanelBorder.add(filesPanel);

    buttonsPanel = new JPanel();
    buttonsPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
    buttonsPanel.setBorder(BorderFactory.createCompoundBorder(new EmptyBorder(5,10,10,10), BorderFactory.createEtchedBorder()));
    buttonsPanel.add(startButton);
    buttonsPanel.add(stopButton);
    basePanel.add(panelForFilesPanelBorder);
    basePanel.add(numericInputPanel); 
    basePanel.add(buttonsPanel); 

制作一张图片,将其上传到其他地方并添加到您的问题中,这样我们就可以更好地理解。 - Sage
1
您可以通过调用setMinimumSize(Dimension d) 来设置JLabel的最小尺寸,这应该能满足您的需求。 - Hovercraft Full Of Eels
嗯,我试图添加一张图片。显然我需要10个声望投票。 - restin84
添加一张图片链接,我们可以为您将其添加到您的问题中。我的建议呢? - Hovercraft Full Of Eels
1
@HovercraftFullOfEels,在这种情况下,仅使用GridBagLayout设置最小大小是行不通的。请查看我的答案以获取详细信息,并指出我解释错误的地方 :) - Sage
显示剩余2条评论
4个回答

6
令人恼火的是,没有文字的标签不会占用任何垂直空间。当它为空时,您可以通过使用" "来解决此问题。
JLabel fileNameLabel = new JLabel(" ");

4
基本上,GridBagLayout将组件放置在网格中的矩形(单元格)中,然后使用组件的首选大小来确定单元格的大小。使用此布局时:
- 如果容器的大小小于首选大小,则仅使用最小大小。 - 对于空(“”)文本的JLabel \ JTextFeild \ JButton的首选大小约为(2,2),如果没有使用setPreferredSize(size)或覆盖getPreferredSize(size)显式地给出首选大小提示。
此时设置最小大小将不起作用,因为带有空文本的首选大小约为(2,2),并且容器的大小已经大于首选大小。GridBagLayout使用首选大小而不必担心最小大小。
实际上,您需要同时设置GridBagLayout的首选大小和最小大小,因为:
如果您尝试仅设置首选大小,则缩小窗口的大小最终会导致容器面板的大小缩小。容器面板的大小将小于组件的首选大小,并且JLabel \ JTextFeild \ JButton会缩小到其最小大小。如果此时没有给出最小大小提示,则使用默认最小大小:可能约为(2,2)。您将通过下面给出的工作示例更好地理解。
其他需要注意的一些事项:
   c.gridx = 1;
    c.gridy = 0;
    c.fill = GridBagConstraints.BOTH;

   // filesPanel.add(calibrationFileSelection,c);
    filesPanel.add(calibrationFileSelectionValuePanel,c);

你正在添加包含你的calibrationFileSelectionValueLabel的panel。你不需要使用额外的panel,而是通过设置preferredSize(而不是重写getPreferredSize(Size)更好)直接将calibrationFileSelectionValueLabel添加到网格中。但是,请尝试将inset设置为GridBagConstraints,以使第一个panel看起来更加美观:
   gridBagCnst.insets = new Insets(3, 3, 3, 3); 

一个最简工作示例:

如果您不理解我们在说什么,这个示例我只设置了首选大小来解决您的问题。但是由于我没有设置最小大小,请尝试调整窗口以与上述说明匹配。

enter image description here

源代码:

import java.awt.*;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import javax.swing.*;
import javax.swing.SwingUtilities;
import javax.swing.border.*;


/**
 *
 * @author Rashed
 */
 class GridBagLayoutDemo extends JFrame{


    public JLabel createLabel(String txt, int width, int height, Color color)
    {
        JLabel label = new JLabel(txt);
        label.setOpaque(true);
        label.setBackground(color);
        label.setPreferredSize(new Dimension(width, height));
        return label;
    }

    public GridBagLayoutDemo() throws HeadlessException {
      // setSize(400,400);
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

       JPanel panel = new JPanel(new java.awt.GridBagLayout());
       panel.setBorder(new EmptyBorder(10, 10, 10, 10));
       GridBagConstraints labCnst = new GridBagConstraints();

       Dimension preferredSize = new Dimension(140,20);

       labCnst.insets = new Insets(3, 3, 3, 3);

       JLabel title = new JLabel("My Title");
       JLabel title2 = new JLabel("My Title");
       JLabel title3 = new JLabel("My Title");

       JLabel selectionLabel1 = new JLabel("");
       selectionLabel1.setBorder(new LineBorder(Color.BLACK));
       JLabel selectionLabel2 = new JLabel("");
       selectionLabel2.setBorder(new LineBorder(Color.BLACK));
       JLabel selectionLabel3 = new JLabel("");
       selectionLabel3.setBorder(new LineBorder(Color.BLACK));

       selectionLabel1.setPreferredSize(preferredSize);
       selectionLabel2.setPreferredSize(preferredSize);
       selectionLabel3.setPreferredSize(preferredSize);

       JButton browse1 = new JButton("Browse");
       JButton browse2 = new JButton("Browse");
       JButton browse3 = new JButton("Browse");


        labCnst.gridx = 0;
        labCnst.gridy = 0;
        panel.add(title, labCnst);
        labCnst.gridy = 1;
        panel.add(title2, labCnst);
        labCnst.gridy = 2;
        panel.add(title3, labCnst);

        labCnst.gridx = 1;
        labCnst.gridy = 0;
        panel.add(selectionLabel1, labCnst);
        labCnst.gridy = 1;
        panel.add(selectionLabel2, labCnst);
        labCnst.gridy = 2;
        panel.add(selectionLabel3, labCnst);

        labCnst.gridx = 3;
        labCnst.gridy = 0;
        panel.add(browse1, labCnst);
        labCnst.gridy = 1;
        panel.add(browse2, labCnst);
        labCnst.gridy = 2;
        panel.add(browse3, labCnst);


       //labCnst.anchor = GridBagConstraints.LINE_END;


       add(panel);
       pack();

    }


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new GridBagLayoutDemo().setVisible(true);
            }
        });
    }
}

希望你不介意,我在我的回答中借用了你的程序,并(我认为)通过使标签在调整窗口大小时更自然地折叠和展开而进行了改进。我给了你信用。 - Mike Clark
@MikeClark,没关系,我不会的,因为你的回答为我的解释增加了更多的澄清 :) - Sage
Insets。您可以使用插入来创建各种空白。 - Gilbert Le Blanc

1
我使用了John的" "技巧修改了Sage的程序,并添加了一些我自己的GridBagConstraint调味料,使对话框在折叠和展开时更自然地调整大小。
public class GridBagLayoutDemo extends JFrame {

    public GridBagLayoutDemo() throws HeadlessException {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.setLayout(new BorderLayout());

        JPanel panel = new JPanel(new java.awt.GridBagLayout());
        panel.setBorder(new EmptyBorder(10, 10, 10, 10));
        GridBagConstraints labCnst = new GridBagConstraints();

        Dimension preferredSize = new Dimension(140, 1);

        labCnst.insets = new Insets(3, 3, 3, 3);

        JLabel title = new JLabel("My Title");
        JLabel title2 = new JLabel("My Title");
        JLabel title3 = new JLabel("My Title");

        final JLabel selectionLabel1 = new JLabel(" ");
        selectionLabel1.setBorder(new LineBorder(Color.BLACK));
        final JLabel selectionLabel2 = new JLabel(" ");
        selectionLabel2.setBorder(new LineBorder(Color.BLACK));
        final JLabel selectionLabel3 = new JLabel(" ");
        selectionLabel3.setBorder(new LineBorder(Color.BLACK));

        setPreferredWidth(selectionLabel1, 120);
        setPreferredWidth(selectionLabel2, 120);
        setPreferredWidth(selectionLabel3, 120); 

        JButton browse1 = new JButton(new AbstractAction("Browse 1") {
            public void actionPerformed(ActionEvent arg0) {
                selectionLabel1.setText("C:\\Documents and Settings\\jsmith\\My Documents\\Studio 2014\\Projects\\1");
            }
        });
        JButton browse2 = new JButton(new AbstractAction("Browse 2") {
            public void actionPerformed(ActionEvent arg0) {
                selectionLabel2.setText("C:\\Documents and Settings\\jsmith\\My Documents\\Studio 2014\\Projects\\2");
            }
        });
        JButton browse3 = new JButton(new AbstractAction("Browse 3") {
            public void actionPerformed(ActionEvent arg0) {
                selectionLabel3.setText("C:\\Documents and Settings\\jsmith\\My Documents\\Studio 2014\\Projects\\3");
            }
        });

        labCnst.gridx = 0;
        labCnst.gridy = 0;
        panel.add(title, labCnst);
        labCnst.gridy = 1;
        panel.add(title2, labCnst);
        labCnst.gridy = 2;
        panel.add(title3, labCnst);

        labCnst.weightx = 1;
        labCnst.fill = GridBagConstraints.HORIZONTAL;
        labCnst.gridx = 1;
        labCnst.gridy = 0;
        panel.add(selectionLabel1, labCnst);
        labCnst.gridy = 1;
        panel.add(selectionLabel2, labCnst);
        labCnst.gridy = 2;
        panel.add(selectionLabel3, labCnst);

        labCnst.weightx = 0;

        labCnst.gridx = 3;
        labCnst.gridy = 0;
        panel.add(browse1, labCnst);
        labCnst.gridy = 1;
        panel.add(browse2, labCnst);
        labCnst.gridy = 2;
        panel.add(browse3, labCnst);

        add(panel, BorderLayout.CENTER);
        pack();

    }

    private void setPreferredWidth(JComponent c, int w) {
        Dimension d = c.getPreferredSize();
        d.width = w;
        c.setPreferredSize(d);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                GridBagLayoutDemo demo = new GridBagLayoutDemo();
                demo.setLocationRelativeTo(null);
                demo.setVisible(true);
            }
        });
    }
}

有一件事需要提醒,约翰的想法更像是一个避免实际事实的hack投诉。请不要误解,我个人不喜欢在没有解释逻辑推论的情况下推广这样的想法,这种推论对于所有组件都是通用的,而不是针对任何特定类型的组件 :) - Sage

-1

正如John所说,将标签中放置一个单独的空格和/或设置其setMinimumSize()

如果标签打算在UI活动后填充,则最小大小非常有用。当最初未选择任何内容时,可以防止UI压缩为丑陋状态。


所以setMinimumSize()对第一个标签和按钮之间的空间没有影响。我可以将标签初始化为空字符串,长度为我需要的任何长度,但是当我的标签被设置时,如果它的长度不同,则第一个标签和按钮之间的间距可能会改变。我需要它保持恒定。 - restin84

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接