Почему BoxLayout не позволяет мне изменять ширину JButton, но позволяет мне изменять высоту? - PullRequest
18 голосов
/ 12 сентября 2010

Я пытаюсь настроить макет моего JDialog так, чтобы он соответствовал определенному виду, который имеет программа, в которой я портирую на Java. Ранее я использовал несколько LayoutManager с большим успехом, но по некоторым причинам Я не могу заставить это работать вообще. Моя цель состоит в том, чтобы правая (восточная) сторона JDialog содержала кнопки «Найти далее» и «Отмена» в порядке сверху вниз, а затем любой дополнительный пробел внизу, чтобы две кнопки всегда были вверху. JDialog, но по какой-то причине BoxLayout постоянно игнорирует любые попытки изменить (вот где я потерян) ширину JButton. Кодекс следует.

JButton findNext = new JButton("Find Next");
JButton cancel = new JButton("Cancel");
cancel.setPreferredSize(new Dimension((int)findNext.getPreferredSize().getWidth(),  
    (int)cancel.getPreferredSize().getHeight()));

JPanel example = new JPanel();  
example.setLayout(new BoxLayout(example, BoxLayout.Y_AXIS));  
example.add(findNext);
example.add(cancel);  
example.add(Box.createGlue());  

Что бы я ни пытался, cancel всегда сохраняет свой нормальный размер. Я попытался setMinimumSize() и setMaximumSize() с теми же параметрами, что и setPreferredSize, но не повезло. Я даже попробовал cancel.setPreferredSize(new Dimension(500, 500));, и высота кнопок была единственной измененной настройкой, она по-прежнему сохраняла заданную по умолчанию ширину.

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

example image

Ответы [ 6 ]

45 голосов
/ 12 мая 2011

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

В Swing есть три метода, связанных с определением размеров компонентов: setPreferredSize (), setMinimumSize () и setMaximumSize ().Тем не менее, важным моментом является то, что от конкретного менеджера макета зависит, соблюдает ли он какой-либо из этих методов или нет.

Для BoxLayout (макет, используемый оригинальным постером):

  • setMinimumSize () - BoxLayout соблюдает это
  • setMaximumSize () - BoxLayout соблюдает это
  • setPreferredSize () - если используется X_AXIS, ширина - этоуважается, если используется Y_AXIS, высота учитывается

ОП использует Y_AXIS BoxLayout, поэтому изменяется только его высота.

Обновление: Я собрал страницу с этой же информацией для всех менеджеров макетов.Надеюсь, это поможет некоторым поисковикам: http://thebadprogrammer.com/swing-layout-manager-sizing/

6 голосов
/ 12 сентября 2010

Возможно, вы не захотите Box.createGlue(), который " увеличивается по мере необходимости , чтобы поглотить любое дополнительное пространство в своем контейнере".Вместо этого используйте Box.createVerticalStrut() между кнопками, как показано ниже и в ControlPanel этой симуляции .

example.setLayout(new BoxLayout(example, BoxLayout.Y_AXIS));
example.add(findNext);
Box.createVerticalStrut(10);
example.add(cancel);

Приложение:

добавление в setMaximumSize() сделало его работу.

Это ожидаемое поведение для компонентов, имеющих одинаковую максимальную ширину по вертикали BoxLayout, как описано в Особенности компоновки коробки .Предпочтительной шириной контейнера становится ширина (одинаково широких) дочерних элементов, и выравнивание по X становится несущественным.

example.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JButton findNext = new JButton("Find Next");
JButton cancel = new JButton("Cancel");
Dimension d = findNext.getMaximumSize();
cancel.setMaximumSize(new Dimension(d));
example.add(findNext);
example.add(cancel);
3 голосов
/ 12 сентября 2010

Как уже упоминалось в комментариях к вопросу, вы смогли исправить это, переключившись на setMaximumSize(). Однако, как вы заметили, setPreferredSize() не работает. Итак, что с этим?

Во многих случаях Swing, свойства, используемые для определения фактического размера компонента при использовании BoxLayout, являются несколько случайными (на мой взгляд). При определении способа рендеринга компонентов Swing вызывает layoutComponent() в менеджере макета, который выясняет, где все расположить.

Реализация

BoxLayout layoutComponent() включает вызов метода, который создает SizeRequirements объекты для ширины и высоты каждого из компонентов, которые вы добавляете к JPanel, на основе по их getMinimum/Preferred/MaximumSize() методам.

Позже он вызывает SizeRequirements.calculateAlignedPositions() для определения правильных значений ширины для каждого компонента, поскольку ваша ориентация равна BoxLayout.Y_AXIS (высоты рассчитываются с использованием другого метода). Принимая фрагменты из источника, соответствующая реализация этого метода выглядит следующим образом:

for (int i = 0; i < children.length; i++) {
    SizeRequirements req = children[i];
    //...
    int maxAscent = (int)(req.maximum * alignment);
    int maxDescent = req.maximum - maxAscent;
    //...
    int descent = Math.min(totalDescent, maxDescent);
    //...
    spans[i] = (int)Math.min((long) ascent + (long)descent, Integer.MAX_VALUE);
}

Обратите внимание, что totalDescent - это доступная ширина, поэтому descent всегда устанавливается на maxDescent, что основано на SizeRequirements.maximum, который был взят из JButton.getMaximumSize(). Значение spans[i] затем используется позже при вызове JButton.setBounds() в качестве ширины. Как вы заметите, getPreferredSize() здесь никогда не участвовал, поэтому его настройка в этом случае не имеет значения.

0 голосов
/ 05 мая 2017

Если вы поместите свои кнопки на панель GridLayout, они будут одинаковой ширины.

0 голосов
/ 09 марта 2013
button.setMaximumSize(getMaximumSize());
0 голосов
/ 12 сентября 2010

Обычно, если вы хотите определить размер компонента в Swing, вам нужно вызвать setMinimumSize(), setMaximumSize() и SetPrefferedSize() с тем же значением.

...