Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Какой менеджер компоновки выбрать?.. 
V
    Опции темы
GZep
Дата 29.8.2011, 14:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


участник Винграда
***


Профиль
Группа: Завсегдатай
Сообщений: 1528
Регистрация: 7.7.2006
Где: Москва

Репутация: нет
Всего: 32



Здравствуйте.

Вот такой результат хочу получить: (выделите картинку, чтобы не сливалась с фонов и было видно, что снизу отступ)
user posted image

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

В принципе GridBagLayout справляется, но проблема в том, что элементы появляются динамически и точное число не известно.
Вот такой код работает как надо, но если добавим следующий элемент, то вертикальное выравнивание сломается.
Код

        panel = new JPanel(new GridBagLayout());
        c = new GridBagConstraints();
        c.weightx = 1.0;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.anchor = GridBagConstraints.NORTHEAST;//слева свеху
        
        panel.add(new Label("123456"), c);
        panel.add(new Label("123456"), c);

        c.weighty = 1.0;//обязательно перед последним элементом, но их число динамическое :(
        panel.add(new Label("LAST"), c);

Вопрос: может как-то можно научить GridBagLayout выравнивать всегда наверх или проще написать простенький свой менеджер?

Это сообщение отредактировал(а) GZep - 29.8.2011, 14:02


--------------------
user posted imageuser posted image
PM MAIL WWW ICQ Skype GTalk   Вверх
CHEM_Eugene
Дата 29.8.2011, 14:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 12.2.2008

Репутация: нет
Всего: нет



Возьми BoxLayout

См. там примеры, как раз то, что тебе нужно, по-моему
PM MAIL   Вверх
GZep
Дата 29.8.2011, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


участник Винграда
***


Профиль
Группа: Завсегдатай
Сообщений: 1528
Регистрация: 7.7.2006
Где: Москва

Репутация: нет
Всего: 32



CHEM_Eugene, BoxLayout не подошел, он постоянно все к центральной линии притягивает. Лечится только манипуляциями с размерами и то не всегда. В общем долго с ним возился - не победил.


--------------------
user posted imageuser posted image
PM MAIL WWW ICQ Skype GTalk   Вверх
AntonSaburov
Дата 29.8.2011, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 118



Напишите свой вариант Layout'а - чтобы делал то, что надо. Вот статейка - http://java-course.ru/articles/articles.ph...e=LayoutManager
Там в конце есть вариант.
PM MAIL WWW ICQ   Вверх
GZep
Дата 29.8.2011, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


участник Винграда
***


Профиль
Группа: Завсегдатай
Сообщений: 1528
Регистрация: 7.7.2006
Где: Москва

Репутация: нет
Всего: 32



Спасибо большое, такую статью хорошую увы сам не нашел. Вечером попробую.

Один вопрос: поскольку мне надо разные варианты горизонтальной ориентации - придется реализовывать LayoutManager2? Или LayoutManager тоже подойдет?


--------------------
user posted imageuser posted image
PM MAIL WWW ICQ Skype GTalk   Вверх
COVD
Дата 29.8.2011, 17:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 4
Всего: 43



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

Другой подход - использовать вложенные панели с простыми стандартными лэйаутами. В данном примере можно создать пустые панели и сначала решить задачу их вертикального размещения. Потом внутри каждой панели решать задачу горизонтального размещения.   
PM MAIL   Вверх
GZep
Дата 30.8.2011, 09:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


участник Винграда
***


Профиль
Группа: Завсегдатай
Сообщений: 1528
Регистрация: 7.7.2006
Где: Москва

Репутация: нет
Всего: 32



Цитата(COVD @  29.8.2011,  17:10 Найти цитируемый пост)
Вовсе необязательно пытаться сделать все одним лэйаутом на одной панели. В этом случае обычно возникает необходимость виртуозного владения сложным лэйаутом типа GridBagLayout или написания собственного. 

Ну так имхо лучше свой простенький для одной задачи чем:
Цитата(COVD @  29.8.2011,  17:10 Найти цитируемый пост)
Другой подход - использовать вложенные панели с простыми стандартными лэйаутами. В данном примере можно создать пустые панели и сначала решить задачу их вертикального размещения. Потом внутри каждой панели решать задачу горизонтального размещения.    

потому что количество элементов неизвестно и второй подход затратен и нелогичен.


--------------------
user posted imageuser posted image
PM MAIL WWW ICQ Skype GTalk   Вверх
GZep
Дата 30.8.2011, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


участник Винграда
***


Профиль
Группа: Завсегдатай
Сообщений: 1528
Регистрация: 7.7.2006
Где: Москва

Репутация: нет
Всего: 32



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

Сам отвечу на свой вопрос:
Цитата(GZep @  29.8.2011,  16:33 Найти цитируемый пост)
поскольку мне надо разные варианты горизонтальной ориентации - придется реализовывать LayoutManager2? Или LayoutManager тоже подойдет? 

LayoutManager тоже подходит, потому что мы можем узнать вариант горизонтальной ориентации из component.getAlignmentX().

Сам менеджер:
Код

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.LayoutManager;

/**
 *
 * @author GZep
 */
public class TestLayout implements LayoutManager {

    int hgap,
            vgap;
    
    public TestLayout() {
        this(0, 0);
    }

    public TestLayout(int hgap, int vgap) {
        this.hgap = hgap;
        this.vgap = vgap;
    }
    
    @Override
    public void addLayoutComponent(String name, Component comp) {
    }

    @Override
    public void removeLayoutComponent(Component comp) {
    }

    //Нам нужно подсчитать предпочтительный размер, чтобы например правильно работали скролл бары
    @Override
    public Dimension preferredLayoutSize(Container target) {
        int height = this.vgap;
        for(Component component : target.getComponents()) {
            height += component.getPreferredSize().height + this.vgap;
        }
        return new Dimension(0, height);
    }

    //Минимальный размер. Лично я предпочел не ставить ограничения на него, поэтому - нули.
    //(пустой конструктор Dimension тоже самое, что конструктор с нулями)
    @Override
    public Dimension minimumLayoutSize(Container target) {
        return new Dimension();
    }

    //Самое главное в менеджере -подсчет координат.
    @Override
    public void layoutContainer(Container target) {
        int topMargin = this.vgap,//Верхний отступ - сразу равен верхнему отступу
                leftMargin,//"Левый" отступ - пока просто инициализируем
                targetWidth = target.getWidth();//Ширина контейнера нужна для подсчета координаты элемента по горизонтальной оси

        for (Component component : target.getComponents()) {

            Dimension preferredSize = component.getPreferredSize();//Предпочтительные размеры компонента - нужны для подсчета

            if (component.getAlignmentX() == Component.RIGHT_ALIGNMENT)//Выравниваем элемент справа
                    leftMargin = targetWidth - preferredSize.width - this.hgap;
            else if (component.getAlignmentX() == Component.CENTER_ALIGNMENT)//Выравниваем элемент по центру
                    leftMargin = targetWidth / 2 - preferredSize.width / 2;
            else//Выравниваем элемент слева
                    leftMargin = this.hgap;

            component.setBounds(leftMargin, topMargin, preferredSize.width, preferredSize.height);//Задаем координаты

            topMargin += preferredSize.height + this.vgap;//Верхний отступ увеличиваем для следующих элементов
        }

    }

}


Как работает:
Код

        panel = new JPanel(new TestLayout(10, 5));//отступы: горизонтальные - 10, вертикальные 5.

        JLabel label = new JLabel("left");
        label.setAlignmentX(Component.LEFT_ALIGNMENT);
        panel.add(label );

        label = new Label("right");
        label.setAlignmentX(Component.RIGHT_ALIGNMENT);
        panel.add(label );

        label = new Label("center");
        label.setAlignmentX(Component.CENTER_ALIGNMENT);
        panel.add(label );


P.S. по-дурацки сделали: component.getAlignmentX() возвращает тип Float и его нельзя использовать в конструкции switch-case...

Это сообщение отредактировал(а) GZep - 3.9.2011, 22:59


--------------------
user posted imageuser posted image
PM MAIL WWW ICQ Skype GTalk   Вверх
Skipy
Дата 30.8.2011, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 4
Всего: 16



И ради этого городить собственный менеджер...

Все элементы кроме последнего кладутся в панель. У всех weighty=0. Панель добавляется в основной контейнер с weighty=0, последний элемент - с weighty=1.

При добавлении элемента последний из ранее добавленных переносится в панель, новый на его место.


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
GZep
Дата 30.8.2011, 22:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


участник Винграда
***


Профиль
Группа: Завсегдатай
Сообщений: 1528
Регистрация: 7.7.2006
Где: Москва

Репутация: нет
Всего: 32



Цитата(Skipy @  30.8.2011,  14:27 Найти цитируемый пост)
И ради этого городить собственный менеджер...

Кстати, менеджер получился ИМХО куда менее громоздкий чем стандартные.

Skipy, можно пример? Я так понимаю, вы имеете ввиду GridBagLayout?

Цитата(Skipy @  30.8.2011,  14:27 Найти цитируемый пост)
И ради этого городить собственный менеджер...

Почитайте топик. Я пытался найти решение стандартными менеджерами, но увы не смог сам и мне не помогли.
Цитата(Skipy @  30.8.2011,  14:27 Найти цитируемый пост)
При добавлении элемента последний из ранее добавленных переносится в панель, новый на его место. 

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



--------------------
user posted imageuser posted image
PM MAIL WWW ICQ Skype GTalk   Вверх
CHEM_Eugene
Дата 31.8.2011, 09:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 73
Регистрация: 12.2.2008

Репутация: нет
Всего: нет



метод setAlignmentX позволяет удивительным образом проделать тоже самое с BoxLayout, не заморачиваясь на собственных реализациях smile
PM MAIL   Вверх
Skipy
Дата 31.8.2011, 10:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 4
Всего: 16



Цитата(GZep @ 30.8.2011,  22:01)
Почитайте топик. Я пытался найти решение стандартными менеджерами, но увы не смог сам и мне не помогли.
Цитата(Skipy @  30.8.2011,  14:27 Найти цитируемый пост)
При добавлении элемента последний из ранее добавленных переносится в панель, новый на его место. 

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

Ну да, ступил. Ничего никуда не надо переносить, стандартными делается.

Код
package ru.skipy;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * LayoutTest
 *
 * @author Eugene Matyushkin aka Skipy
 * @since 31.08.2011
 */
public class LayoutTest extends JFrame {

    private JPanel mainPanel;

    public LayoutTest(){
        mainPanel = new JPanel(new GridBagLayout());
        final JPanel cp = new JPanel(new BorderLayout());
        cp.add(mainPanel, BorderLayout.NORTH);
        JPanel spacer = new JPanel();
        spacer.setBackground(Color.yellow.brighter().brighter());
        cp.add(spacer, BorderLayout.CENTER);
        JButton add = new JButton("Add label");
        cp.add(add, BorderLayout.SOUTH);
        add.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                JLabel lbl = new JLabel("Label #"+mainPanel.getComponentCount());
                lbl.setBorder(BorderFactory.createLineBorder(Color.red));
                int r = (int)(Math.random() * 3);
                int align = (r == 0) ? GridBagConstraints.WEST :
                        (r == 1) ? GridBagConstraints.CENTER : GridBagConstraints.EAST;
                mainPanel.add(lbl, new GridBagConstraints(0, mainPanel.getComponentCount(),
                        1, 1, 1, 0, align, GridBagConstraints.NONE, new Insets(5,5,0,5),0,0 ));
                cp.validate();
            }
        });
        setSize(300, 700);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setContentPane(cp);
    }

    public static void main(String[] args) {
        new LayoutTest().setVisible(true);
    }
}



--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
GZep
Дата 31.8.2011, 13:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


участник Винграда
***


Профиль
Группа: Завсегдатай
Сообщений: 1528
Регистрация: 7.7.2006
Где: Москва

Репутация: нет
Всего: 32



Skipy, спасибо понял вашу связку 2 менеджеров. Итого 2 работающих варианта. Какой выбрать?

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

При варианте со связкой 2-х менеджеров имеем свои минусы (постараюсь объективно):
  • это все же костыль, ни один стандартный менеджер не справляется с такой задачей, только в связке.
  • GridBagLayout помимо того, что сам большой, еще и требует инициализации класса-помощника - GridBagConstraints. (это важно если элементов много)

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


--------------------
user posted imageuser posted image
PM MAIL WWW ICQ Skype GTalk   Вверх
Skipy
Дата 31.8.2011, 13:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 4
Всего: 16



1. Связка менеджеров - это норма. У меня иногда в формах до 10 вложенных контейнеров, и менеджеров, соответственно, 10. И совершенно необязательно одинаковые.

2. И что? Вы о памяти беспокоитесь? Не бойтесь, 10-20 кб погоды не сделают. 

P.S. Универсальные менеджеры хороши именно тем, что они универсальны. Менеджер, сделанный под конкретную задачу, во-первых, сложно переиспользовать, во-вторых, необходимо поддерживать. Изменились условия - и Вы будете переписывать код. А я в худшем случае поменяю пару параметров. Предлагаю подумать, что Вам надо изменить, чтобы элементы были прижаты не к верху, а к низу, в том же порядке. И что надо изменить мне (один параметр в одном методе).


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
GZep
Дата 31.8.2011, 19:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


участник Винграда
***


Профиль
Группа: Завсегдатай
Сообщений: 1528
Регистрация: 7.7.2006
Где: Москва

Репутация: нет
Всего: 32



Цитата(Skipy @  31.8.2011,  13:34 Найти цитируемый пост)
Связка менеджеров - это норма.

Тут наверное субъективно больше... но, например, в HTML не приветствуется глубокая вложенность. Вижу тут аналогию.
Цитата(Skipy @  31.8.2011,  13:34 Найти цитируемый пост)
Менеджер, сделанный под конкретную задачу, во-первых, сложно переиспользовать

Но ведь этот минус не засчитывается. К нему просто таких требований нету.
Цитата(Skipy @  31.8.2011,  13:34 Найти цитируемый пост)
во-вторых, необходимо поддерживать. Изменились условия - и Вы будете переписывать код

Вот резонный аргумент! Действительно, кастомизация переезжает на уровень редактирования кода самого менеджера - это плохо.
Цитата(Skipy @  31.8.2011,  13:34 Найти цитируемый пост)
И что? Вы о памяти беспокоитесь? Не бойтесь, 10-20 кб погоды не сделают. 

Согласен.

А вот еще один плюс нарисовался для собственного варианта - код инициализации. Вот он (продублирую, он был выше):
Код

panel = new JPanel(new TestLayout());
JLabel label = new JLabel("left");
label.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(label);

Согласитесь, тут код выглядит гораздо лучше чем тот же GridBagLayout + GridBagConstraints, не говоря уже о слое с BorderLayout.
Честно говоря больше всего нравится как реализована компановка в https://github.com/jacek99/javabuilders (используется Yaml разметка).


--------------------
user posted imageuser posted image
PM MAIL WWW ICQ Skype GTalk   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   jk1
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, jk1.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: GUI и Java FX приложения | Следующая тема »


 




[ Время генерации скрипта: 0.0585 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.