Статьи

Иногда в Java одного менеджера макета недостаточно

Чаще всего при разработке приложений Java Swing нам нужно использовать несколько менеджеров компоновки в нескольких вложенных панелях. Обычно это не проблема, и считается нормальной практикой для разработки всего пользовательского интерфейса почти на всех языках, известных человеку.

Однако чаще всего для каждой панели в пользовательском интерфейсе требуется только один менеджер макетов для достижения желаемого эффекта, но наступает момент, когда вам нужно использовать несколько менеджеров макетов для одного и того же контейнера в зависимости от количества компонентов в контейнере.

Одним из таких примеров будет создание центрированной сетки, подобной макету. Чаще всего GridLayout или GridBagLayout может быть достаточно, если количество компонентов фиксировано, но если количество компонентов продолжает изменяться, макет может быть не таким, как хотелось бы. Я столкнулся с подобной проблемой сегодня днем, и вот решение, которое я нашел.

Интерфейс, который я хотел достичь, был похож на быстрый набор Opera, но с переменным количеством наборов. В принципе,

  1. вы начинаете с одного компонента, и это должно быть по центру на панели
  2. добавить еще один компонент, и они оба должны быть по центру
  3. добавьте третий, и все три должны быть сосредоточены в одном ряду
  4. если добавлен четвертый компонент, то у вас должна быть матрица 3 x 2, с тремя элементами в первом ряду и одним во втором
  5. матрица 3 x 2 должна поддерживаться для шести компонентов
  6. для более чем 6 компонентов матрица должна быть 4 x 3, поэтому мы можем взять до 12 компонентов, что будет максимум

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

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

Тогда возник вопрос, какой менеджер верстки дает желаемые результаты? После нескольких минут экспериментов я наконец понял, что GridBagLayout дает мне вид центрированного контента, в котором я нуждаюсь, но иногда это было противоречиво. Поэтому я решил использовать GroupLayout через конструктор netbeans. Так что был применен внешний контейнер.

Затем я попытался найти один менеджер компоновки, который будет эффективно выполнять первое требование. Варианты были FlowLayout и GridLayout. Однако, несмотря на то, что FlowLayout стремится выровнять его содержимое по вертикали, это было достаточно в этом случае, потому что GroupLayout вертикально центрировал содержимое FlowLayout, и это соответствовало требованиям 1 — 3.

Затем для требования 4 снова был выбран GridLayout, но на этот раз он был настроен на матрицу тревог 3, где n — любое количество строк. Это позволяет GridLayout расти должным образом, а также размещать его компоненты сначала горизонтально, а затем вертикально. Это автоматически также выполнило требование 5.

Наконец, когда компоненты становятся больше, чем 6, создается новый GridLayout, который является nx 4, эффективно выравнивая содержимое. Новые компоненты можно добавлять до тех пор, пока не будет достигнуто максимум 12 компонентов, и дальнейшее добавление запрещено.

Вот пример кода для процесса.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
JPanel container = new JPanel();
container.setName("container"); // NOI18N
container.setOpaque(false);
 
JPanel content = new JPanel();
content.setBorder(javax.swing.BorderFactory.createEmptyBorder(50, 50, 50, 50));
content.setName("content"); // NOI18N
content.setOpaque(false);
content.setLayout(new java.awt.GridLayout(0, 3));
 
javax.swing.GroupLayout containerLayout = new javax.swing.GroupLayout(container);
container.setLayout(containerLayout);
containerLayout.setHorizontalGroup(
    containerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    .addGroup(containerLayout.createSequentialGroup()
        .addContainerGap(346, Short.MAX_VALUE)
        .addComponent(content, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addContainerGap(347, Short.MAX_VALUE))
);
containerLayout.setVerticalGroup(
    containerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    .addGroup(containerLayout.createSequentialGroup()
        .addContainerGap(223, Short.MAX_VALUE)
        .addComponent(content, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addContainerGap(224, Short.MAX_VALUE))
);

И затем каждый раз, когда добавляется новый компонент, запускается следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
getContent().removeAll();
 
int gridSize = organisations.size();
 
switch( gridSize ) {
    case 1:
    case 2:
    case 3:
        getContent().setLayout( new FlowLayout(FlowLayout.CENTER) );
        break;
    case 4:
    case 5:
    case 6:
        getContent().setLayout( new GridLayout(0,3) );
        break;
    case 7:
    case 8:
        getContent().setLayout( new GridLayout(0,4) );
        break;
    default:
        getContent().setLayout( new GridLayout(0, 4) );
}
 
for (Organisation org : organisations) {
    getContent().add(createOrgSelectionComponent(org));
}
 
getContent().validate();
getContent().repaint();

А вот скриншот окончательных макетов.

Справка: Иногда на Java одного менеджера по раскладке недостаточно от нашего партнера по JCG Фрэнсиса в блоге «Ice in Code» .

Статьи по Теме :