public class MyFrame extends JFrame
{
public MyFrame(String title)
{

    setSize(200, 200);
    setTitle(Integer.toString(super.getSize().width));
    setLayout(new FlowLayout());
    for (int i = 0; i < 5; ++i)
    {
        JButton b = new JButton();
        b.setSize(90,50);
        b.setText(Integer.toString(b.getSize().width));
        this.add(b);![alt text][1]
    }
    this.setVisible(true);
}
}

Почему при ширине кнопки 90 я получаю окно, в котором три кнопки в одном ряду вместо двух?

2
There is nothing we can do 29 Мар 2010 в 17:47

2 ответа

Лучший ответ

FlowLayout разместит Component слева направо (или справа налево), обернув их, если необходимо. Если вы хотите явно установить размер каждого JButton, вам следует использовать setPreferredSize , а не setSize, поскольку менеджеры по компоновке обычно используют минимальный, предпочтительный и максимальный размеры при выполнении макет.

Свойства размера довольно сбивают с толку - есть интересная статья здесь. В частности, обратите внимание:

Всегда ли соблюдаются свойства размера?

Некоторые менеджеры по расположению, такие как GridLayout, полностью игнорировать размер свойства .

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

5
Adamski 29 Мар 2010 в 17:57
Но почему 3? Если рамка 200, я думал, что там будет место только для двух кнопок?
 – 
There is nothing we can do
29 Мар 2010 в 17:50
Извините - поправлю свой ответ.
 – 
Adamski
29 Мар 2010 в 17:54
Итак, в основном ответ ...?
 – 
There is nothing we can do
29 Мар 2010 в 18:16
Нет, ответ в том, что FlowLayout будет уважать предпочтительный размер, поэтому вы должны его использовать. Он игнорирует вызов setSize и просто определяет размер каждой JButton в соответствии с его предпочтительным размером, который продиктован текстом внутри кнопки (потому что вы не установили его явно).
 – 
Adamski
29 Мар 2010 в 18:34

Во-первых, вы неправильно используете JFrame: вы не добавляете компоненты непосредственно в фрейм, вы добавляете их в JPanel, который затем передаете во фрейм с помощью setContentPane() .

Также: не очень элегантно напрямую создавать подклассы JFrame только для добавления компонентов. Вместо этого создайте рамку как отдельный объект.

-2
Anon 29 Мар 2010 в 17:52
Это не отвечает на вопрос ОП. Также нет ничего плохого в написании frame.add (Component). Из документа JFrame: «Для удобства add и его варианты, remove и setLayout были переопределены для пересылки в contentPane по мере необходимости. Это означает, что вы можете написать: frame.add (child);». Наконец, я не считаю плохой практикой создавать подкласс JFrame для фрейма приложения верхнего уровня (точно так же, как вы бы подклассифицировали JPanel). В противном случае вы просто получите тонну кода Swing в своем классе Main.
 – 
Adamski
29 Мар 2010 в 18:03
- Я бы тоже не стал подклассом JPanel. Во-первых, это нарушает принцип замены Лискова. Также нет никаких причин помещать этот код в ваш основной класс: ваши классы могут управлять своими фреймами / панелями, они просто не должны создавать подклассы JFrame / JPanel.
 – 
Anon
29 Мар 2010 в 18:15
Почему это нарушает принцип? JPanel - это просто пустой компонент, и, следовательно, если я подклассифицирую его как MyPanel, а затем заменяю его использованием MyPanel, мое приложение каким-либо образом неверно? Все методы JPanel по-прежнему будут вести себя так, как ожидалось. По этому признаку JFileChooser и JColorChooser также нарушили принцип, потому что они являются подклассом JComponent.
 – 
Adamski
29 Мар 2010 в 18:43
- возьмите свой подкласс и передайте его какому-то коду, который ожидает пустую панель. Это заменяемое?
 – 
Anon
29 Мар 2010 в 18:47
Это почти то же самое, что расширение Thread, а не реализация Runnable. Вы не меняете функциональность JPanel, вы просто добавляете в нее компоненты.
 – 
Anon
29 Мар 2010 в 18:49