Контейнер не изменяет свой размер после вызова validate - PullRequest
3 голосов
/ 05 января 2012

После ручной замены компонентов через add и remove, я вызываю validate() для контейнера.Согласно документации,

Метод проверки используется для того, чтобы контейнер снова планировал свои подкомпоненты .Он должен вызываться, когда подкомпоненты этого контейнера изменены (добавлены или удалены из контейнера, или изменена информация, связанная с макетом) после того, как контейнер был отображен.снова его подкомпоненты"заставляют меня думать, что контейнер изменится соответствующим образом, но это не так.Вместо этого после вызова validate() мне нужно также вызвать pack(), чтобы просмотреть все его подкомпоненты.

Почему это так?Я что-то не так делаю?

Ответы [ 3 ]

7 голосов
/ 05 января 2012

Я думаю, что вы сами ответили на свой вопрос, надеюсь, вам поможет эта демоверсия

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;

public class AddComponentsAtRuntime {

    private JFrame f;
    private JPanel panel;
    private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;

    public AddComponentsAtRuntime() {
        JButton b = new JButton();
        b.setBackground(Color.red);
        b.setBorder(new LineBorder(Color.black, 2));
        b.setPreferredSize(new Dimension(600, 10));
        panel = new JPanel(new GridLayout(0, 1));
        panel.add(b);
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panel, "Center");
        f.add(getCheckBoxPanel(), "South");
        f.setLocation(200, 200);
        f.pack();
        f.setVisible(true);
    }

    private JPanel getCheckBoxPanel() {
        checkValidate = new JCheckBox("validate");
        checkValidate.setSelected(false);
        checkReValidate = new JCheckBox("revalidate");
        checkReValidate.setSelected(false);
        checkRepaint = new JCheckBox("repaint");
        checkRepaint.setSelected(false);
        checkPack = new JCheckBox("pack");
        checkPack.setSelected(false);
        JButton addComp = new JButton("Add New One");
        addComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JButton b = new JButton();
                b.setBackground(Color.red);
                b.setBorder(new LineBorder(Color.black, 2));
                b.setPreferredSize(new Dimension(600, 10));
                panel.add(b);
                makeChange();
                System.out.println(" Components Count after Adds :" + panel.getComponentCount());
            }
        });
        JButton removeComp = new JButton("Remove One");
        removeComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int count = panel.getComponentCount();
                if (count > 0) {
                    panel.remove(0);
                }
                makeChange();
                System.out.println(" Components Count after Removes :" + panel.getComponentCount());
            }
        });
        JPanel panel2 = new JPanel();
        panel2.add(checkValidate);
        panel2.add(checkReValidate);
        panel2.add(checkRepaint);
        panel2.add(checkPack);
        panel2.add(addComp);
        panel2.add(removeComp);
        return panel2;
    }

    private void makeChange() {
        if (checkValidate.isSelected()) {
            panel.validate();
        }
        if (checkReValidate.isSelected()) {
            panel.revalidate();
        }
        if (checkRepaint.isSelected()) {
            panel.repaint();
        }
        if (checkPack.isSelected()) {
            f.pack();
        }
    }

    public static void main(String[] args) {
        AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
    }
}
6 голосов
/ 05 января 2012

(может быть из-за этой неоднозначности описание изменено в последний javaDoc )

JavaDoc 7 - это НЕ , говоря,

Метод validate используется для того, чтобы контейнер снова планировал свои подкомпоненты снова ..

так что это только прокладка компонентов, тогда как вам снова нужно pack().

Обратите внимание, что pack () ясно говорит,

Заставляет размер этого окна соответствовать предпочтительному размеру и расположению его подкомпонентов.

2 голосов
/ 05 января 2012

Фундаментальное, но тонкое предположение здесь: расположение и размер непосредственно связаны, 1 к 1 . Это не так, , и это распространенное предположение в программировании на Swing. Размер является результатом компоновки и ограничений по размеру .

Расположение:

  • В указанных вами ограниченных пространствах
  • И учитывая компоненты, которые я должен вписать в это пространство
  • Позиционирование этих компонентов относительно друг друга с учетом указанной стратегии (BoxLayout, BorderLayout и т. Д.)

Если LayoutManager может соответствовать компонентам, которые вы ему предоставили, без изменения общего размера контейнера, не изменит размера контейнера. С другой стороны, вызов pack является явным запросом к минимизации используемого пространства . Это основная причина, по которой вы видите результаты.

Некоторые вещи, которые вы можете попробовать:

  • Убедитесь, что вы устанавливаете максимальный размер для ваших компонентов / контейнеров, что налагает ограничения на размер компонентов при повторном выполнении макета
  • Всегда звоните pack () по привычке
  • Попробуйте некоторые предложения, касающиеся общих проблем с макетом

С Swing сложно, потому что вы должны понимать конвейер рисования, менеджеры компоновки и некоторые детали оконной системы. Когда дело доходит до документации Swing (и всех методов и нескольких различных способов сделать что-либо одно), я стараюсь читать документацию с подходом «ничего не брать», имея в виду: «Какова минимально возможная вещь, которую этот метод документация подразумевает, что это может произойти ", и если вы не наблюдаете дополнительное поведение, не обманывайте себя, думая, что оно делает больше, чем это.

Наконец, я хотел бы добавить, что работа LayoutManager в целом заключается не в определении размеров контейнеров, а в том, чтобы размещать компоненты в некотором отношении друг к другу, в соответствии со стратегией (это обсуждается в дополнительные подробности здесь ). Идея заключается в том, что с помощью соответствующего LayoutManager вы задаете базовый макет стратегии , и в результате этого при изменении размера окна LayoutManager будет разумно перемещать компоненты так, чтобы ваш пользовательский интерфейс продолжал следовать этой общей стратегии. , Таким образом, макеты в основном должны быть независимыми от общего размера пространства, в котором они работают, поэтому они стараются не делать предположений о том, какое пространство доступно - вместо этого они берут размер, который им дают, и попытаться сделать то, что имеет смысл. Если вы явно не наложите ограничения на размер ваших компонентов, вы не сможете гарантировать, какого размера они будут.

Это означает, что, если LayoutManager не считает, что ему нужно изменить размер чего-либо, чтобы соответствовать общей стратегии, в основном он не изменит его . С другой стороны, вызов pack - это явный запрос собрать вещи вместе и удалить дополнительное пространство.

...