【问题标题】:Why does GridBagLayout center my components instead of putting it in the corner?为什么 GridBagLayout 将我的组件居中而不是放在角落里?
【发布时间】:2011-11-08 15:57:52
【问题描述】:

到目前为止,我设法尽可能避免使用GridBagLayout(手动代码),但这次我无法避免,我正在阅读 SUN 的教程GridBagLayout 到目前为止,进展并不顺利。我想我误解了一些东西。
例如,我尝试以下代码(类似于 SUN 帖子中的代码):

public class MainFrame extends JFrame { 


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

    /**
     * Create the frame
     */
    public MainFrame() {
        super();
        setBounds(100, 100, 500, 375);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Container mainContainer = getContentPane();

        mainContainer.setLayout(new GridBagLayout());       

        //add label
        JLabel someLabel = new JLabel("Label 1:");
        GridBagConstraints constraints = new GridBagConstraints();

        constraints.gridx = 0;
        constraints.gridy = 0;
        //constraints.anchor = GridBagConstraints.FIRST_LINE_START;
        //constraints.weightx = 0.5;
        mainContainer.add(someLabel, constraints);      

        JTextField someText = new JTextField(30);

        constraints = new GridBagConstraints();

        constraints.gridx = 1;
        constraints.gridy = 0;
        constraints.weightx = 0.5;
        mainContainer.add(someText, constraints);

        //
    }

}

标签和文本字段在框架的中心并排放置。
但我原以为它们会出现在左上角,因为标签的 gridx 和 gridy 为 0。
即使我设置constraints.anchor = GridBagConstraints.FIRST_LINE_START; 仍然是相同的结果。
我错了吗?
来自 SUN 的帖子:

指定组件左上角的行和列。这 最左列的地址为 gridx=0,顶行的地址为 网格=0。

【问题讨论】:

    标签: java swing user-interface gridbaglayout


    【解决方案1】:

    这对我有用:

    public class NewJFrame extends javax.swing.JFrame {
    
        public NewJFrame() {
            initComponents();
        }
    
        @SuppressWarnings("unchecked")
        private void initComponents() {
            java.awt.GridBagConstraints gridBagConstraints;
    
            jPanel2 = new javax.swing.JPanel();
            jComboBox3 = new javax.swing.JComboBox();
            jComboBox4 = new javax.swing.JComboBox();
            jComboBox5 = new javax.swing.JComboBox();
    
            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
            setBackground(new java.awt.Color(255, 204, 51));
            setMinimumSize(new java.awt.Dimension(800, 600));
            getContentPane().setLayout(null);
    
            jPanel2.setLayout(new java.awt.GridBagLayout());
    
            jComboBox3.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
            gridBagConstraints = new java.awt.GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.gridy = 0;
            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
            gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
            gridBagConstraints.weightx = 1.0;
            jPanel2.add(jComboBox3, gridBagConstraints);
    
            jComboBox4.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
            gridBagConstraints = new java.awt.GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.gridy = 1;
            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
            gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
            gridBagConstraints.weightx = 1.0;
            jPanel2.add(jComboBox4, gridBagConstraints);
    
            jComboBox5.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
            gridBagConstraints = new java.awt.GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.gridy = 2;
            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
            gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
            gridBagConstraints.weightx = 1.0;
            gridBagConstraints.weighty = 1.0;
            jPanel2.add(jComboBox5, gridBagConstraints);
    
            getContentPane().add(jPanel2);
            jPanel2.setBounds(30, 40, 150, 260);
    
            pack();
        }
    
        public static void main(String args[]) {
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new NewJFrame().setVisible(true);
                }
            });
        }
    
        private javax.swing.JComboBox jComboBox3;
        private javax.swing.JComboBox jComboBox4;
        private javax.swing.JComboBox jComboBox5;
        private javax.swing.JPanel jPanel2;
    }
    

    【讨论】:

      【解决方案2】:

      constraints.weighty = 1; 添加到JLabel 约束,将constraints.anchor = GridBagConstraints.NORTHWEST; 添加到TextField 约束。

      编辑:

      来自 Oracle 的GridBagLayout guide

      较大的数字表示组件的行或列应该获得更多空间。对于每一列,权重与为该列中的组件指定的最高权重 x 相关,每个多列组件的权重在组件所在的列之间以某种方式拆分。类似地,每一行的权重与为某个组件指定的最高权重相关该行中的组件。额外的空间倾向于朝向最右边的列和底行。

      【讨论】:

      • 如果我也将constraints.weighty=1 设置为标签并锚定到标签FIRST_LINE_START,它会起作用。但是重量中的值1实际上是什么意思?
      • 另外,在他们的代码示例中,这行代码带有注释:c.weighty = 1.0; //request any extra vertical space
      • 对于 JButton5,我看到了。但我不认为这是一个很好的演示文稿。无论如何为什么是 1 而不是 0.8。我不明白这些数字是如何选择的
      • 老实说,我也不知道。我对一切都使用 MiGLayout...miglayout.com
      • 记录一下:“如果生成的布局横向小于它需要填充的区域,则额外的空间将按与其权重的比例分配到每一列。 权重为零的列不会接收额外的空间。” weightxweighty 的实际数值仅在相互关联时才有意义。
      【解决方案3】:

      您需要进一步阅读 Swing 教程中的 weightX/weightY 部分,其中指出:

      除非您为 weightx 或 weighty 指定至少一个非零值,否则所有组件都会在其容器的中心聚集在一起。

      您指定了 weightX,但没有指定 weightY。

      编辑,它比我想象的要复杂。看来您还需要指定:

      constraints.anchor = GridBagConstraints.FIRST_LINE_START;
      

      除了权重之外的两个组件。

      【讨论】:

      • SUN 的引述说 weightx 或 weighty (所以我没想到它需要两者)。无论如何我尝试了 weighty=1 的标签和 weighty=0.5 的文本和 weighty=0.5 的两者但相同的结果
      • weightx 如果用于水平定位。 weighty 用于垂直定位。我使用 1.0 和 FIRST_LINE_START 都对我有用。
      • 是的,现在它可以工作了。但是重量中的值 1 到底是什么意思?我不明白。而且在我看来(由于需要锚点)网格已经存在而不是通过在上面放置组件来构建的。对吗?
      • GridBagLayout 以首选尺寸显示组件。当有额外空间时,weightX/Y 值会提示布局管理器如何分配该空间。 EON 的提示奏效了,因为他添加了第二行组件并要求该行通过使用 weighty = 1.0 来占用所有额外空间。在您的情况下,您只有一行,因此您需要指定其中一个组件占用所有可用的额外空间。
      • 好的,但是我只对标签使用了 weighty。所以标签获得了额外的垂直空间(我猜以一种用户看不到的方式)。但是为什么这也会影响文本字段以及涨了吗?
      【解决方案4】:

      您可以通过使用技巧来实现这一点,在行之后添加一个虚拟组件并将其扩展以填充垂直空间。您也可以重复使用约束,无需创建新对象:

      编辑:好的,忘记诀窍 :( 正确的方法是 Deon Botha 和 BenCole 说,我已经使用锚更新了我的代码

      不要接受这个答案,接受 Deon 的或 Ben 的

      public class MainFrame extends JFrame { 
          public static void main(String args[]) {
              EventQueue.invokeLater(new Runnable() {
                  public void run() {
                      try {
                          MainFrame frame = new MainFrame();
                          frame.setVisible(true);
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
              });
          }
      
      public MainFrame() {
          super();
          setBounds(100, 100, 500, 375);
          setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
          Container mainContainer = getContentPane();
          mainContainer.setLayout(new GridBagLayout());       
      
          JLabel someLabel = new JLabel("Label 1:");
          JTextField someText = new JTextField(30);
      
          GridBagConstraints constraints = new GridBagConstraints();
          constraints.anchor = GridBagConstraints.FIRST_LINE_START;
      
          constraints.gridx = 0;
          constraints.gridy = 0;    
          constraints.weightx = 1.0;
          mainContainer.add(someLabel, constraints);      
      
          constraints.gridx = 1;                       
          constraints.weightx = 1.0;
          constraints.weighty = 1.0;        
          mainContainer.add(someText, constraints);                       
      }
      }
      

      【讨论】:

      • 但是为什么我需要这个虚拟组件呢?组件是否应该被布局管理器放在左上角?那么gridx=gridy=0是什么意思呢?
      • 你是对的,它“应该工作”,但 GridBayLayout 是纯粹的邪恶,实际上它非常好......只是棘手,我不是纯粹主义者,如果它与一个虚拟标签一起工作那为什么不使用呢?
      • 或者你可以设置constraints.weighty = 1.0; constraints.anchor = GridBagConstraints.FIRST_LINE_START;
      【解决方案5】:

      我可能不会直接回答您的问题,但相信我,您应该使用 IDE 对布局进行尝试和错误。我个人建议Netbeans。您可以在那里拖放,然后查看属性。起初,您会在属性检查器中给出一些默认值,因此自动生成的代码更少。但是,一旦您开始使用布局,您就可以看到代码并很好地了解您的工作方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-15
        • 2018-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-24
        相关资源
        最近更新 更多