Как заставить GridBagLayout соблюдать минимальный размер кнопки или панели?

В следующем коде GridBagLayout я ожидаю, что указанный минимальный размер JButton btn2 будет соблюдаться, когда размер JFrame будет уменьшен. Но когда я делаю JFrame меньше, btn2 становится меньше своего минимального размера и затем исчезает.

Может ли кто-нибудь указать мне правильное направление того, что я делаю неправильно? Может быть, я должен установить минимальный размер JPanel, который содержит кнопки?

Любая помощь приветствуется, спасибо!

    JFrame frame = new JFrame();
    frame.setSize(400,300);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    JPanel panel = new JPanel();
    panel.setMinimumSize(new Dimension(400,300));
    panel.setBackground(Color.RED);

    panel.setLayout(new GridBagLayout());
    GridBagConstraints gbc = null;

    JButton btn1 = new JButton("btn1");
    btn1.setPreferredSize(new Dimension(150,50));
    btn1.setMinimumSize(new Dimension(150,50));
    gbc = new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, 
            GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
            new Insets(0,0,0,0), 0, 0);
    panel.add(btn1, gbc);

    JButton btn2 = new JButton("btn2");
    btn2.setPreferredSize(new Dimension(150,150));
    btn2.setMinimumSize(new Dimension(150,150));
    gbc = new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, 
            GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
            new Insets(0,0,100,100), 0, 0);
    panel.add(btn2, gbc);

    frame.getContentPane().add(panel);
    frame.setVisible(true);

2 ответа

Решение

Может быть, я должен установить минимальный размер JPanel, который содержит кнопки?

AFAIR GBL был известен тем, что игнорировал подсказки по размерам. Нет, поправка на это. Чтобы получить разумное изменение размеров компонентов в GBL, используйте GridBagConstraints с соответствующими значениями. Остерегайтесь, однако, поведения макета, чтобы не отображать какой-либо компонент, который был бы вынужден меньше его минимального размера.

я мог бы pack() затем установите минимальный размер кадра. Вот как это может выглядеть, изменив последнюю строку на..

frame.pack();
frame.setVisible(true);
frame.setMinimumSize(frame.getSize());

Учитывая расположение, хотя, я бы склонен поставить btn1 в PAGE_START из BorderLayout панели, которая затем добавляется к LINE_START другого BL. btn2 пошел бы в CENTER внешнего BL.

В дополнение к ответу Эндрю Томпсона:

  • GBL НЕ соблюдает минимальный размер, установленный для компонента, если предпочтительный размер компонента может и будет соблюдаться.
  • GBL уважает минимальный размер, установленный для компонента, когда предпочтительный размер компонента не может быть соблюден, то есть: компонент предпочитает иметь размер (w, h), но GBL видит, что это невозможно из-за недостатка места, и поэтому он возвращается к объявленному минимальному размеру компонента.

Поэтому очень возможно заставить ваш компонент внезапно стать больше, чем это было раньше, когда вы уменьшали размер содержащего фрейма. Вам нужно только установить минимальный размер, который больше, чем предпочтительный размер. Таким образом, вы делаете рамку меньше, и вдруг ваш компонент становится больше. Это... странно, но возможно:) Все приветствуют GBL.

Вот пример панели, которая реализует это поведение (GBC - более простой в использовании класс, чем исходные GridBagConstraints):

private static JPanel getPanel() {

    JPanel panel = new JPanel(new GridBagLayout());

    final JTextField textField = new JTextField("test");
    final String text = "text";
    final JLabel label = new JLabel(text);
    final JButton button = new JButton(new AbstractAction("Enlarge label!") {
        private String actText = text; 
        @Override
        public void actionPerformed(ActionEvent arg0) {
            actText = actText + text;
            label.setText(actText);
        }
    });

    GBC g;

    g = new GBC().locate(0, 0).weight(0.0, 0.0).align(GBC.WEST, GBC.HORIZONTAL, null);
    textField.setMinimumSize(new Dimension(200,20));
    panel.add(textField, g);

    g = new GBC().locate(1, 0).weight(1.0, 0.0);
    panel.add(label, g);

    g = new GBC().locate(0, 1).weight(1.0, 1.0).span(2, 1);
    panel.add(button, g);


    return panel;
}

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

Если вы действительно хотите использовать свой компонент фиксированного размера в GBL, переопределите его метод getPreferredSize() и верните желаемый размер. Но я предпочитаю игнорировать эти методы.

Другие вопросы по тегам