GridBagLayout вес ошибка? - PullRequest
3 голосов
/ 18 июня 2009

Расположение компонентов в проекте, над которым я работаю, не выглядело правильно, я подозреваю, что в Swing есть ошибка. По сути, происходит то, что пропорции weightx и weighty не соблюдаются, когда размечаемые ячейки имеют различные минимальные размеры и / или предпочтительные размеры. Я создал пример программы, чтобы продемонстрировать это, вот источник:

package com.ensoftcorp.product.simmerge.gui.swing.dialogs;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class TestClass {

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            new TestClass();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static final GridBagConstraints GBC_CELL = new GridBagConstraints();
    static final GridBagConstraints GBC_ROWEND = new GridBagConstraints();
    static final GridBagConstraints GBC_FILLROW = new GridBagConstraints();
    static {
        GBC_CELL.anchor = GridBagConstraints.NORTHWEST;
        GBC_CELL.weightx = 0.5;
        GBC_CELL.fill = GridBagConstraints.BOTH;

        GBC_ROWEND.gridwidth = GridBagConstraints.REMAINDER;

        GBC_FILLROW.gridwidth = GridBagConstraints.REMAINDER;
        GBC_FILLROW.weightx = 1.0;
        GBC_FILLROW.fill = GridBagConstraints.BOTH;
    }

    public TestClass() {
        JFrame frame = new JFrame();

        JPanel pnlContent = new JPanel(new GridBagLayout());
        pnlContent.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        /*
         * Layout "ruler" panel
         */
        JPanel pnlRuler = new JPanel(new GridBagLayout());

        pnlRuler.add(createRulerCell(Color.BLACK, Color.WHITE),GBC_CELL);
        pnlRuler.add(createRulerCell(Color.BLACK, Color.WHITE),GBC_CELL);

        pnlRuler.add(Box.createHorizontalGlue(),GBC_ROWEND);

        /*
         * Layout "correct" panel
         */
        JPanel pnlGoodLayout = new JPanel(new GridBagLayout());

        pnlGoodLayout.add(new JButton("JButton1"),GBC_CELL);
        pnlGoodLayout.add(new JButton("JButton2"),GBC_CELL);

        pnlGoodLayout.add(Box.createHorizontalGlue(),GBC_ROWEND);

        pnlGoodLayout.add(new JButton("JButton3"),GBC_CELL);
        pnlGoodLayout.add(new JButton("JButton4"),GBC_CELL);

        pnlGoodLayout.add(Box.createHorizontalGlue(),GBC_ROWEND);

        /*
         * Layout "incorrect" panel
         */
        JPanel pnlBadLayout = new JPanel(new GridBagLayout());

        pnlBadLayout.add(new JButton("JButton1"),GBC_CELL);
        pnlBadLayout.add(new JButton("JButton2"),GBC_CELL);

        pnlBadLayout.add(Box.createHorizontalGlue(),GBC_ROWEND);

        pnlBadLayout.add(new JButton("JButton number 3 is wide"),GBC_CELL);
        pnlBadLayout.add(new JButton("JButton4"),GBC_CELL);

        pnlBadLayout.add(Box.createHorizontalGlue(),GBC_ROWEND);

        /*
         * Add panels to main panel
         */
        pnlContent.add(pnlRuler,GBC_FILLROW);
        pnlContent.add(Box.createVerticalStrut(8),GBC_FILLROW);
        pnlContent.add(pnlGoodLayout,GBC_FILLROW);
        pnlContent.add(Box.createVerticalStrut(8),GBC_FILLROW);
        pnlContent.add(pnlBadLayout,GBC_FILLROW);

        /*
         * Configure frame
         */
        frame.getContentPane().add(pnlContent);
        frame.setTitle("GridBagLayout Weight Bug?");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400,200);
        frame.setVisible(true);
}

    JComponent createRulerCell(Color border, Color background) {
        JPanel glue = new JPanel();
        glue.setBorder(BorderFactory.createLineBorder(border));
        glue.setBackground(background);

        return glue;
    }

}

Пример программы состоит из трех групп ... первая - это своего рода "линейка", показывающая отметку 50%. Вторая и третья группы - это панели, использующие GridBagLayout, где каждая ячейка имеет weightx 0,5. Единственное различие между группами заключается в длине текста кнопки, но вторая группа неравномерно распределяет столбцы, даже если для этого достаточно места.

Тогда у меня такой вопрос: кто-нибудь сталкивался с этой проблемой раньше, и есть ли обходной путь, который они бы порекомендовали?

P.S. - Я использую jdk1.6.0_11, если это имеет значение.

Ответы [ 4 ]

5 голосов
/ 18 июня 2009

из GridBagConstraints.weightx JavaDoc :

Определяет, как распределить дополнительное горизонтальное пространство.

Менеджер макета мешка сетки вычисляет вес столбца, чтобы он равнялся максимальному весу x всех компонентов в столбце. Если результирующий макет меньше по горизонтали, чем область, которую необходимо заполнить, дополнительное пространство распределяется по каждому столбцу пропорционально его весу.

Имея это в виду, я не думаю, что это ошибка, потому что столбец с широкой кнопкой рассчитан на большее пространство. после того, как это и нормальные размеры столбцов кнопки будут вычислены, оставшееся пространство будет распределено.

Обход:

Чтобы обойти это, вы можете установить GBC_CELL.gridx и GBC_CELL.gridy перед добавлением каждой из ваших кнопок, а перед кнопкой, которая разделяет строку с большой кнопкой, вы можете установить

GBC_CELL.ipadx=100;

и затем установите его на 0 перед добавлением широкой кнопки (# 3). это должно выровнять ваши кнопки в большей части сетки.

2 голосов
/ 25 июля 2011

Это может помочь (источник) :

Если более одного столбца имеет ненулевой вес, избыточное пространство распределены среди столбцов ненулевого веса с использованием значений веса. В частности, если избыточное пространство составляет P пикселей, а вес столбца для столбца ^ i есть вес ^ i, тогда столбец ^ i получится точно (вес ^ i * P) / (Сумма-из-всех-колонок-весов). Например, если столбец 1 имеет вес 1 и столбец 2 имеет вес 2, а избыточное пространство составляет 90 пикселей, столбец 1 получит 30 дополнительных пикселей, а столбец 2 - 60 дополнительных пикселей. Ряды с ненулевым весом ведут себя аналогично.

2 голосов
/ 18 июня 2009

Используйте встроенную GroupLayout . У вас больше контроля, чем у GridBagLayout.

0 голосов
/ 27 января 2016

Я нашел простой обходной путь. Явно установите атрибут preferredSize.width каждого JButton в preferredSize.width=0.

Это способ сделать это:

private JButton createButton(String text) {
    JButton button = new JButton(text);
    button.setPreferredSize(new Dimension(0, button.getPreferredSize().height));
    return button;
}

Вот ваш модифицированный пример (я пометил изменения комментарием // <==============):

public class TestClass {

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            new TestClass();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static final GridBagConstraints GBC_CELL = new GridBagConstraints();
    static final GridBagConstraints GBC_ROWEND = new GridBagConstraints();
    static final GridBagConstraints GBC_FILLROW = new GridBagConstraints();
    static {
        GBC_CELL.anchor = GridBagConstraints.NORTHWEST;
        GBC_CELL.weightx = 0.5;
        GBC_CELL.fill = GridBagConstraints.BOTH;

        GBC_ROWEND.gridwidth = GridBagConstraints.REMAINDER;

        GBC_FILLROW.gridwidth = GridBagConstraints.REMAINDER;
        GBC_FILLROW.weightx = 1.0;
        GBC_FILLROW.fill = GridBagConstraints.BOTH;
    }

    public TestClass() {
        JFrame frame = new JFrame();

        JPanel pnlContent = new JPanel(new GridBagLayout());
        pnlContent.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        /*
         * Layout "ruler" panel
         */
        JPanel pnlRuler = new JPanel(new GridBagLayout());

        pnlRuler.add(createRulerCell(Color.BLACK, Color.WHITE),GBC_CELL);
        pnlRuler.add(createRulerCell(Color.BLACK, Color.WHITE),GBC_CELL);

        pnlRuler.add(Box.createHorizontalGlue(),GBC_ROWEND);

        /*
         * Layout "correct" panel
         */
        JPanel pnlGoodLayout = new JPanel(new GridBagLayout());

        pnlGoodLayout.add(createButton("JButton1"),GBC_CELL); // <==============
        pnlGoodLayout.add(createButton("JButton2"),GBC_CELL); // <==============

        pnlGoodLayout.add(Box.createHorizontalGlue(),GBC_ROWEND);

        pnlGoodLayout.add(createButton("JButton3"),GBC_CELL); // <==============
        pnlGoodLayout.add(createButton("JButton4"),GBC_CELL); // <==============

        pnlGoodLayout.add(Box.createHorizontalGlue(),GBC_ROWEND);

        /*
         * Layout "incorrect" panel
         */
        JPanel pnlBadLayout = new JPanel(new GridBagLayout());

        pnlBadLayout.add(createButton("JButton1"),GBC_CELL); // <==============
        pnlBadLayout.add(createButton("JButton2"),GBC_CELL); // <==============

        pnlBadLayout.add(Box.createHorizontalGlue(),GBC_ROWEND);

        pnlBadLayout.add(createButton("JButton number 3 is wide"),GBC_CELL); // <==============
        pnlBadLayout.add(createButton("JButton4"),GBC_CELL); // <==============

        pnlBadLayout.add(Box.createHorizontalGlue(),GBC_ROWEND);

        /*
         * Add panels to main panel
         */
        pnlContent.add(pnlRuler,GBC_FILLROW);
        pnlContent.add(Box.createVerticalStrut(8),GBC_FILLROW);
        pnlContent.add(pnlGoodLayout,GBC_FILLROW);
        pnlContent.add(Box.createVerticalStrut(8),GBC_FILLROW);
        pnlContent.add(pnlBadLayout,GBC_FILLROW);

        /*
         * Configure frame
         */
        frame.getContentPane().add(pnlContent);
        frame.setTitle("GridBagLayout Weight Bug?");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400,200);
        frame.setVisible(true);
    }

    JComponent createRulerCell(Color border, Color background) {
        JPanel glue = new JPanel();
        glue.setBorder(BorderFactory.createLineBorder(border));
        glue.setBackground(background);

        return glue;
    }

    private JButton createButton(String text) {
        JButton button = new JButton(text);
        button.setPreferredSize(new Dimension(0, button.getPreferredSize().height));
        return button;
    }

}

И вот как выглядит результат. Увидеть? Теперь пространство распределено равномерно:

enter image description here

enter image description here

...