Почему эти три панели, использующие GridBagLayout, по-разному используют дополнительное пространство, и как сделать их однородными

У меня есть приложение, которое имеет несколько панелей; Я хотел бы иметь возможность использовать разные менеджеры компоновки для разных панелей, но хотел бы, чтобы они вели себя одинаково, поскольку размер окна изменяется пользователем.

    package example;

    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;

    import javax.swing.BoxLayout;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.JTextField;

    public class TP1 extends JFrame
    {
        public static void main(String[] args)
        {
            TP1 tp1 = new TP1();
            tp1.go();
        }

        public void go()
        {
            setDefaultCloseOperation(EXIT_ON_CLOSE);

            // create a panel with some labels on it
            JPanel innerFirst = new JPanel();
            innerFirst.setLayout(new BoxLayout(innerFirst, BoxLayout.PAGE_AXIS));
            innerFirst.add(new JLabel("one"));
            innerFirst.add(new JLabel("two"));
            innerFirst.add(new JLabel("three"));
            innerFirst.add(new JLabel("four"));

            // put that panel in a scroll pane
            JScrollPane firstSP = new JScrollPane(innerFirst);

            // make another panel and put our scrolled panel in it
            JPanel outerFirst = new JPanel(); 
            outerFirst.setLayout(new BoxLayout(outerFirst, BoxLayout.PAGE_AXIS));
            outerFirst.add(firstSP); 

            // create a GridBagLayout panel with some text fields on it
            JPanel innerSecond = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = .25;
            gbc.anchor = GridBagConstraints.LINE_START;
            innerSecond.add(new JTextField(8), gbc);
            gbc.gridx = 0;
            gbc.gridy = 1;
            innerSecond.add(new JTextField(10), gbc);
            gbc.gridx =0;
            gbc.gridy = 2;
            innerSecond.add(new JTextField(12), gbc);

            // put that panel in a scroll pane
            JScrollPane secondSP = new JScrollPane(innerSecond);

            // make another panel and put our second scrolled panel in it
            JPanel outerSecond = new JPanel(); 
            outerSecond.setLayout(new BoxLayout(outerSecond, BoxLayout.LINE_AXIS));
            outerSecond.add(secondSP); 

            JPanel innerThird = new JPanel(new GridBagLayout());
            GridBagConstraints gbc3 = new GridBagConstraints();
            gbc3.anchor = GridBagConstraints.LINE_END;
            gbc.weightx = .25;
            gbc3.gridx = 0;
            gbc3.gridy = 0;
            innerThird.add(new JLabel("1st label"), gbc3);
            gbc3.gridy = 1;
            innerThird.add(new JLabel("second label"), gbc3);
            gbc3.gridy = 2;
            innerThird.add(new JLabel("IIIrd label"), gbc3);

            gbc3.anchor = GridBagConstraints.LINE_START;
            gbc3.gridx = 1;
            gbc3.gridy = 0;
            innerThird.add(new JTextField(8), gbc3);
            gbc3.gridy = 1;
            innerThird.add(new JTextField(12), gbc3);
            gbc3.gridy = 2;
            innerThird.add(new JTextField(14), gbc3);

            JScrollPane thirdSP = new JScrollPane(innerThird);
            JPanel outerThird = new JPanel();
            outerThird.setLayout(new BoxLayout(outerThird, BoxLayout.LINE_AXIS));
            outerThird.add(thirdSP);

            // put the scrolled panes onto a tabbed pane
            JTabbedPane tp = new JTabbedPane();
            tp.add("text fields", outerSecond);
            tp.add("labels", outerFirst);
            tp.add("mixed", outerThird);

            // add the tabbed pane to the frame
            this.add(tp);

            // pack it and ship it.
            pack();
            setVisible(true);
        }
    }

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

Это не приемлемо для приложения; Мне нужно как-то заставить все панели вести себя одинаково. Мне нужно, чтобы у всех них были полосы прокрутки, и я бы хотел, чтобы все они оставались в верхнем левом углу, если окно сделано больше, чем внутренняя панель.

Еще одно требование: мои вкладки заняты чем-то, что расширяет JPanel, мне уже говорили, что я не могу поместить JScrollPane прямо во вкладку, но для своего приложения я тоже не хочу этого делать. Это просто делает другие вещи более сложными, чем они должны быть.

В дополнение к желанию, чтобы все дополнительное пространство было расположено снизу и справа, мне бы очень хотелось понять, ПОЧЕМУ эти три ситуации ведут себя по-разному. Я все еще верю, что нам всем было бы лучше, если бы мы понимали принципы, лежащие в основе того, что мы делаем, вместо того, чтобы просто копировать примеры вправо и влево и делать вещи методом проб и ошибок, пока они не сработают.

(Между прочим, у меня есть панель GroupLayout, которая, кажется, тяготеет к верхнему левому углу, но не думала, что это было необходимо для моего вопроса, и это 100 строк кода как есть.)

2 ответа

Решение

Похоже, для того, чтобы понять, почему это происходит в вашем коде, вам нужно понять определенные термины. Например, PAGE_AXIS, LINE_AXIS, LINE_END, LINE_START и так далее. Поскольку вы предоставляете их в качестве ограничений, это то, что описывает ориентацию компонентов, добавляемых в контейнер, и их начальную точку, как вы пишете:

innerFirst.setLayout(new BoxLayout(innerFirst, BoxLayout.PAGE_AXIS));

Здесь вы говорите своему BoxLayout начать добавление компонентов с того места, которое относится к началу страницы. (Когда вы запускаете блокнот, курсор помещается в PAGE_AXIS в новом документе). Но когда вы пишете это:

JPanel innerSecond = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = .25;
gbc.anchor = GridBagConstraints.LINE_START;

Здесь термин якорь используется, когда компонент меньше, чем его область отображения. Он определяет, где в области отображения разместить компонент. Но здесь, так как вы упомянули, что это имеет значение LINE_START что значит:

Place the component centered along the edge of its display area where lines of text 
would normally begin for the current ComponentOrientation. Equal to WEST for horizontal,
left-to-right orientations and EAST for horizontal, right-to-left orientations.

Вот почему три JTextFields вы создали, вы видите их в центре на левой стороне.

Я все еще верю, что нам всем было бы лучше, если бы мы поняли принципы того, что мы делаем,

См . Визуальное руководство по менеджерам по расположению для рабочих примеров и объяснений различных менеджеров по расположению. Вам нужно узнать, как различные ограничения используются для конкретного менеджера компоновки.

Другие вопросы по тегам