Динамически растущий JPanel с BoxLayout (на нулевом макете)

У меня есть JPanel с вертикальным BoxLayout поверх JPanel с нулевым макетом.

Я хотел бы, чтобы JPanel с BoxLayout росла по мере добавления компонентов.

См. этот код:

public static void main (String[] args) {
    JFrame f = new JFrame();
    f.setSize(500,500);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel total = new JPanel();
    total.setLayout(null);
    total.setSize(f.getWidth(),f.getHeight());
    total.setBackground(Color.green);
    JPanel box = new JPanel();
    box.setLocation(100,200);
    box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
    box.add(new JButton("test"));
    box.add(new JLabel("hey"));
    total.add(box);
    f.add(total);
    f.setVisible(true);
}

Вы заметите, что никакие компоненты не отображаются.

Как я могу сделать «коробку» JPanel такой, чтобы размер динамически увеличивался по мере добавления дополнительных компонентов (которые добавляются по вертикали).

ЗАРАНЕЕ: мне нужно, чтобы позиция «коробки» была ровно 100 200, поэтому, пожалуйста, не предлагайте мне не использовать нулевой макет. Я должен использовать нулевой макет. Нулевой макет «всего» не должен влиять на ответ на мой вопрос, который фокусируется на панели «коробка».


person CodeGuy    schedule 12.01.2013    source источник
comment
Что происходит в настоящее время, когда вы добавляете свои компоненты? Я думаю, что на какое-то событие вам нужно добавить компоненты и перекрасить ().   -  person Nickoli Roussakov    schedule 12.01.2013
comment
Если вы запустите код, который я разместил, компоненты не появятся, и вызов перерисовки после добавления компонентов не имеет значения.   -  person CodeGuy    schedule 12.01.2013
comment
Ваш опубликованный код не работает. Нет основного метода.   -  person Hovercraft Full Of Eels    schedule 12.01.2013
comment
Это код основного метода... Просто добавьте его в основной метод. (как будто мне нужно было сказать тебе это...)   -  person CodeGuy    schedule 12.01.2013
comment
Поскольку вы решили выбросить (ИМХО) один из самых мощных API-активов, которые Swing может предложить, вы не выполнили ту работу, за которую он отвечает... установка размера дочерних компонентов.   -  person MadProgrammer    schedule 12.01.2013
comment
связано с вашей проблемой или нет: -1 за настаивание на нулевом макете - это всегда (минимум в 3-м приближении, и это очень близко к 100%) неправильное действие. Вместо этого используйте подходящий LayoutManager, который поддерживает необходимый вам элемент управления (например, MigLayout).   -  person kleopatra    schedule 12.01.2013
comment
простой LayoutManager, который берет на себя размер, позволяя вам контролировать расположение, — это DragLayout Роба   -  person kleopatra    schedule 12.01.2013


Ответы (4)


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

По сути, в вашем примере вы не смогли установить размер дочернего компонента...

JFrame f = new JFrame();
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel total = new JPanel();
total.setLayout(null);
total.setSize(f.getWidth(), f.getHeight());
total.setBackground(Color.green);

JPanel box = new JPanel();
box.setLocation(100, 200);
box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
box.add(new JButton("test"));
box.add(new JLabel("hey"));
box.setSize(100, 100);  // <-- Don't forget this..

total.add(box);
f.add(total);
f.setVisible(true);

Лично я думаю, что ты напрашиваешься на неприятности, но откуда мне знать...

Лучшей идеей может быть использование чего-то вроде EmptyBorder для заполнения...

введите здесь описание изображения

JFrame f = new JFrame();
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel total = new JPanel(new BorderLayout());
total.setSize(f.getWidth(), f.getHeight());
total.setBackground(Color.green);
total.setBorder(new EmptyBorder(100, 200, 100, 200));

JPanel box = new JPanel();
box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
box.add(new JButton("test"));
box.add(new JLabel("hey"));

total.add(box);
f.add(total);
f.setVisible(true);

Обновлен пример диспетчера макетов

Теперь, если все менеджеры компоновки вас подводят, вы можете попробовать написать свой собственный. Это дает вам преимущества, которые вам нужны от менеджера компоновки null, и преимущества интеграции в процесс изменения компонентов Swing без необходимости прибегать к ComponentListeners и ContainerListeners.

введите здесь описание изображения

JPanel total = new JPanel();
total.setLayout(new SuperAwesomeBetterThenYoursLayout());

Менеджер пользовательских макетов

public static class SuperAwesomeBetterThenYoursLayout implements LayoutManager {

    @Override
    public void addLayoutComponent(String name, Component comp) {
    }

    @Override
    public void removeLayoutComponent(Component comp) {
    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        return new Dimension(100, 300);
    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        return new Dimension(100, 300);
    }

    @Override
    public void layoutContainer(Container parent) {
        boolean laidOut = false;
        for (Component child : parent.getComponents()) {
            if (child.isVisible() && !laidOut) {
                child.setLocation(200, 100);
                child.setSize(child.getPreferredSize());
            } else {
                child.setSize(0, 0);
            }
        }
    }

}

Это в основном представляет собой работу, которую вам все равно придется выполнять, но она работает так, как был разработан Swing...

person MadProgrammer    schedule 12.01.2013
comment
+1 Отличный пример MadProgrammer! Создание менеджера пользовательских макетов немного сложнее, но вы сделали это очень просто, хорошая работа. - person John; 12.01.2013

Предложения:

  • Не используйте нулевой макет почти никогда.
  • Почему бы не дать общее количество JPanel BorderLayout?
  • Затем добавьте BoxLayout с помощью JPanel в позицию BorderLayout.NORTH (или также известную как BorderLayout.PAGE_START).

Изменить
Вы заявляете,

ЗАРАНЕЕ: мне нужно, чтобы позиция «коробки» была ровно 100 200, поэтому, пожалуйста, не предлагайте мне не использовать нулевой макет. Я должен использовать нулевой макет. Нулевой макет «всего» не должен влиять на ответ на мой вопрос, который фокусируется на панели «коробка».

Я думаю, что вы в очередной раз накладываете ненужные ограничения на свою программу. Вы можете легко разместить свою «коробку» на 100, 200, поместив вокруг нее пустую рамку такого размера или другими способами. Но ответ не в том, чтобы отказаться от использования нулевого макета.

person Hovercraft Full Of Eels    schedule 12.01.2013
comment
Мне нужно, чтобы панель коробки находилась именно в этом положении, поэтому я должен использовать нулевой макет. Но... нулевой макет не должен влиять на ответ на мой вопрос. - person CodeGuy; 12.01.2013
comment
@CodeGuy: но вы можете поместить свою коробку в положение, используя границы и что-то еще, и да, нулевой макет оказывает прямое влияние на вашу способность решить вашу проблему. - person Hovercraft Full Of Eels; 12.01.2013
comment
Думайте о вопросе независимо от проблемы нулевого макета. Подумайте об этом вопросе: как создать динамическую панель JPanel с вертикальным расположением блоков, размер которых увеличивается по мере добавления дополнительных компонентов. - person CodeGuy; 12.01.2013
comment
@CodeGuy причина, по которой Hovercraft пытается заставить вас не использовать нулевой макет, заключается в том, что это часто может привести к «ненадежному» поведению, JPanel не был разработан для инициализации с помощью нулевого менеджера макетов. Возможно, вы могли увидеть симптомы, относящиеся к нулевому макету, а не к вашему фактическому вопросу. - person John; 12.01.2013
comment
@CodeGuy Когда вы добавляете компоненты в контейнер, контейнер становится недействительным, в результате чего диспетчер компоновки вызывается и просит его разместить его содержимое. Частично это будет определять предпочтительные, минимальные и максимальные требования к компоновке контейнера. Удалив диспетчер компоновки контейнеров более высокого уровня, вы нарушили этот процесс, а это означает, что, пока контейнер пытается расти, вы не позволяете ему этого. Это проблема... - person MadProgrammer; 12.01.2013
comment
@CodeGuy Подумайте об этом вопросе: как создать динамическую JPanel с вертикальным расположением блоков, размер которого увеличивается по мере добавления дополнительных компонентов, и это именно то, за что отвечает LayoutManager . Если вы хотите тратить свое время на повторное изобретение велосипеда, пожимайте плечами, оставайтесь наедине с собой: другие могут быть не столь увлечены тратой времени и сил... есть более интересные задачи для решения ;-) - person kleopatra; 12.01.2013

В общем, что бы я изменил:

public static void main (String[] args) {
    JFrame f = new JFrame();
    //f.setSize(500,500);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel total = new JPanel();
    //total.setLayout(null); //<-- this is usually a bad idea, but you can keep it
    //                                if you want to specify an EXACT location
    //                                for your JPanel
    total.setPreferredSize(500, 500);
    total.setBackground(Color.green);
    JPanel box = new JPanel();
    //box.setLocation(100,200);
    box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
    box.add(new JButton("test"));
    box.add(new JLabel("hey"));
    total.add(box);
    f.add(total);
    f.pack();
    f.setVisible(true);
}

Когда у вас есть эта основа, все, что вам нужно сделать для динамического изменения размера JPanel, это:

panel.setSize(width, heightOfComponentWithin * numberOfComponents);
container.repaint(); //<-- Im not sure if you also have to call panel.repaint(),
//                           you probably don't have to.

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

person John    schedule 12.01.2013
comment
(Вам нужно прочитать ответ HoverCrafts и комментарии, чтобы понять, что, хотя ваше предложение отличное, ОП обычно не нравится - извините - +1 от меня, хотя;)) - person MadProgrammer; 12.01.2013
comment
наряду с отсутствием ручного определения размера/определения местоположения (на чем настаивает OP, а не по вашей вине :-) не использовать setXXSize ;-) - person kleopatra; 12.01.2013

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

person Rudy Setiady    schedule 12.01.2013
comment
Вы правы, но лично я бы изо всех сил старался предложить что-то другое, кроме этого - ИМХО... - person MadProgrammer; 12.01.2013
comment
чтобы подчеркнуть комментарий @MadProgrammer: если вам нужно вручную определить местоположение/размер чего-либо, кроме контейнера верхнего уровня ... вы делаете что-то не так. - person kleopatra; 12.01.2013