Проблема Swing BoxLayout с JComboBox без использования setXXXSize

вот SSCCE:

import java.awt.Color;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class BoxLayoutTest extends JFrame {

    public BoxLayoutTest(){
        JPanel main = new JPanel();
        main.setLayout(new BoxLayout(main, BoxLayout.Y_AXIS));
        main.setBackground(Color.red);
        this.add(main);
        JPanel northPanel = new JPanel();

        JPanel middle = new JPanel();
        middle.setLayout(new BoxLayout(middle, BoxLayout.X_AXIS));
        middle.add(new JButton("FOO"));
        middle.add(Box.createHorizontalGlue());

        JPanel aPanel = new JPanel();
        aPanel.setBackground(Color.black);

            JComboBox b = new JComboBox();
    //b.setPreferredSize(new Dimension(100,16)); //uncomment this to see the layout I would like to achieve
    //b.setMaximumSize(new Dimension(100,16));
        //middle.add(b); //uncomment this line 

        middle.setBackground(Color.green);
        northPanel.setBackground(Color.blue);

        main.add(northPanel);
        main.add(middle);
        main.add(Box.createVerticalGlue());

        this.setSize(800,600);
        this.setResizable(true);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        new BoxLayoutTest();
    }

}

Я пытаюсь реорганизовать некоторые классы, которые я написал некоторое время назад, когда я не знал, что использование методов setXXXSize для компонентов неправильно. Используя рамку с изменяемым размером, я хочу добиться следующего результата:

  1. NorthPanel должен оставаться наверху и изменять свой размер в соответствии с изменениями размера кадра (кажется, работает нормально)
  2. Зеленая панель, на которую я поместил JButton, должна сохранять максимальный размер JButton и оставаться чуть ниже синей панели выше (это прекрасно работает, если я помещаю JButton только внутри этой панели).

Проблема возникает, если я помещаю JComboBox внутрь зеленой панели (попробуйте раскомментировать строку в SSCCE). Я предполагаю, что для JComboBox не указан максимальный размер, поэтому он растягивается вместе с рамкой. В предыдущей неправильной версии моего кода я использовал методы setxxxSize в JComboBox, чтобы ограничить его размер (попробуйте раскомментировать строку в методах setXXXSize, чтобы увидеть это).

Мой вопрос:

  1. Можно ли добиться того же результата, используя BoxLayout, не вызывая методы setXXXSize()?
  2. Если да, то как?
  3. Есть ли другой LayoutManager, который я могу использовать для получения такого эффекта?

Пожалуйста, направьте меня в правильном направлении


person Heisenbug    schedule 28.09.2011    source источник


Ответы (2)


JComboBox ведет себя неправильно (так же, как JTextField), сообщая о неограниченной максимальной высоте: никогда не должно отображаться более одной строки. Решение то же самое: создать подкласс и вернуть разумную высоту.

        JComboBox b = new JComboBox() {

            /** 
             * @inherited <p>
             */
            @Override
            public Dimension getMaximumSize() {
                Dimension max = super.getMaximumSize();
                max.height = getPreferredSize().height;
                return max;
            }

        };

просто для удовольствия, вот фрагмент с использованием MigLayout (который в настоящее время мой личный фаворит :-)

    // two panels as placeholders
    JPanel northPanel = new JPanel();
    northPanel.setBackground(Color.YELLOW);
    JPanel southPanel = new JPanel();
    southPanel.setBackground(Color.YELLOW);
    // layout with two content columns
    LC layoutContraints = new LC().wrapAfter(2)
            .debug(1000);
    AC columnContraints = new AC()
    // first column pref, followed by greedy gap
            .size("pref").gap("push")
            // second
            .size("pref");
    // three rows, top/bottom growing, middle pref
    AC rowContraints = new AC()
       .grow().gap().size("pref").gap().grow();
    MigLayout layout = new MigLayout(layoutContraints, columnContraints,
            rowContraints);
    JPanel main = new JPanel(layout);
    main.setBackground(Color.WHITE);
    // add top spanning columns and growing
    main.add(northPanel, "spanx, grow");
    main.add(new JButton("FOO"));

    // well-behaved combo: max height == pref height
    JComboBox combo = new JComboBox() {

        @Override
        public Dimension getMaximumSize() {
            Dimension max = super.getMaximumSize();
            max.height = getPreferredSize().height;
            return max;
        }

    };
    // set a prototype to keep it from constantly adjusting
    combo.setPrototypeDisplayValue("somethingaslongasIwant");

    main.add(combo);
    // add top spanning columns and growing
    main.add(southPanel, "spanx, grow");
person kleopatra    schedule 28.09.2011
comment
Спасибо за ответ. Кажется, это ошибка Swing, будет ли она исправлена? - person Heisenbug; 28.09.2011
comment
@Heisenbug - не знаю, спросите команду Swing :-) - person kleopatra; 28.09.2011

Я всегда видел, что использование менеджеров компоновки в JDK не так просто. Либо они слишком просты и негибки, либо с gridbaglayout слишком много проблем. Вместо этого я начал использовать макет формы jgoodies и никогда не оглядывался назад с тех пор. Взгляните на него. Его очень просто и легко использовать. Вот ссылка:

http://www.jgoodies.com/freeware/forms/

Убедитесь, что вы прошли через технический документ.

И теперь у нас также есть Google, предоставляющий нам редактор WYSISWG для макета формы в качестве плагина для eclipse. Это просто сильно облегчает жизнь.

http://code.google.com/javadevtools/wbpro/palettes/swing_palette.html

person sethu    schedule 28.09.2011