Swing MigLayout не может увеличивать заполняющую колонку, чтобы заполнить длину контейнера

Я использую MigLayout для очень длинного окна.

введите описание изображения здесь и я хочу "нажать" второй и четвертый столбцы, чтобы заполнить всю длину всего окна, но я не могу этого добиться. Нет опции push в ограничении столбцов, только grow и fill.

Здесь SCCEE, как когда-то предлагал, чье имя я уже забыл:

package com.WindThunderStudio.MigLayoutTest;

import java.awt.Cursor;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

public class MigLayoutTest extends JFrame{
private JFrame mainFrame;
private JPanel panel;

private JLabel lblResumenAuto;
private JLabel lblResumenAutoResult;
private JLabel lblResumenRazonSocial;
private JLabel lblResumenRazonSocialResult;
private JLabel lblResumenPeriodo;
private JLabel lblResumenPeriodoResult;
private JLabel lblResumenFechaHora;
private JLabel lblResumenFechaHoraResult;

public MigLayoutTest(){
    run();
}

public void run(){
    mainFrame = new JFrame();
    mainFrame.setBounds(0, 0, 1250, 500);
    mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    JPanel p = new JPanel();
    p.setSize(mainFrame.getSize());

    p.setLayout(new MigLayout("fill","[max!, grow]","[50:20:30]10[100::]10[20::]10[50!]10[20!]"));
    mainFrame.setContentPane(p);

    panel = new JPanel();
    panel.setLayout(new MigLayout("fillx", "[left, 15%]10[left, grow, 35%]10[left, 15%]10[left, grow, 35%]", "[center]10[center]"));

    lblResumenAuto = new JLabel("MY LABEL 1111111111111");
    lblResumenAutoResult = new JLabel("1111111111111111111111");

    panel.add(lblResumenAuto);
    panel.add(lblResumenAutoResult);

    lblResumenRazonSocial = new JLabel("MY LABEL 2222222222");
    lblResumenRazonSocialResult = new JLabel("2222222222222222222222");

    panel.add(lblResumenRazonSocial);
    panel.add(lblResumenRazonSocialResult,"wrap");

    lblResumenPeriodo = new JLabel("MY LABEL 33333333333333");
    lblResumenPeriodoResult = new JLabel("3333333333333333333333333333333333333333333333333333333");

    panel.add(lblResumenPeriodo);
    panel.add(lblResumenPeriodoResult);
    //poner el texto como html puede tener otra linea, porque es muy largo
    lblResumenFechaHora = new JLabel("<html>MY LABEL <br /> 4444444444444444</html>");
    lblResumenFechaHoraResult = new JLabel("4444444444444444444444444");

    panel.add(lblResumenFechaHora);
    panel.add(lblResumenFechaHoraResult);

    p.add(panel,"cell 0 0");

    getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    setBounds(0, 0, 1250, 500);
    getContentPane().add(mainFrame.getContentPane());

    pack();
    setVisible(true);
    setLocationRelativeTo(null);
    setResizable(true);
}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            MigLayoutTest test = new MigLayoutTest();

        }
    });
}
}

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

Желательно, чтобы зафиксировать столбец 0 и 2 на 15% всей ширины и позволить столбцу 1 и 3 окупить остальные, 35%, причем первые два столбца занимают 50 % размера всей ширины.

Я что-то упустил? Я не хочу указывать ширину каждого столбца, устанавливая pre:min:max, потому что это плохая практика, как было предложено этим сообщением, которая получает много голосов.

panel.setLayout(new MigLayout("fillx", 
                              "[left, 15%]10[left, grow, 35%]10[left, 15%]10[left, grow, 35%]", 
                              "[center]10[center]"));

Но если я установил pref:min:max, он может заполнить всю ширину.

Ответ 1

Сначала код, затем объяснение. Попробуйте следующее:

import java.awt.Cursor;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

public class MigLayoutTest extends JFrame {
  private JPanel panel;

  private JLabel lblResumenAuto;
  private JLabel lblResumenAutoResult;
  private JLabel lblResumenRazonSocial;
  private JLabel lblResumenRazonSocialResult;
  private JLabel lblResumenPeriodo;
  private JLabel lblResumenPeriodoResult;
  private JLabel lblResumenFechaHora;
  private JLabel lblResumenFechaHoraResult;

  public MigLayoutTest() {
    run();
  }

  public void run() {
    panel = new JPanel();
    panel.setLayout(new MigLayout("debug, fill",
        "[left, 15%]10[left, 35%]10[left, 15%]10[left, 35%]", "[center]10[center]"));

    lblResumenAuto = new JLabel("MY LABEL 1111111111111");
    lblResumenAutoResult = new JLabel("1111111111111111111111");

    panel.add(lblResumenAuto, "sg label");
    panel.add(lblResumenAutoResult, "sg value");

    lblResumenRazonSocial = new JLabel("MY LABEL 2222222222");
    lblResumenRazonSocialResult = new JLabel("2222222222222222222222");

    panel.add(lblResumenRazonSocial, "sg label");
    panel.add(lblResumenRazonSocialResult, "sg value, wrap");

    lblResumenPeriodo = new JLabel("MY LABEL 33333333333333");
    lblResumenPeriodoResult = new JLabel("3333333333333333333333333333333333333333333333333333333");

    panel.add(lblResumenPeriodo, "sg label");
    panel.add(lblResumenPeriodoResult, "sg value");
    // poner el texto como html puede tener otra linea, porque es muy largo
    lblResumenFechaHora = new JLabel("<html>MY LABEL <br /> 4444444444444444</html>");
    lblResumenFechaHoraResult = new JLabel("4444444444444444444444444");

    panel.add(lblResumenFechaHora, "sg label");
    panel.add(lblResumenFechaHoraResult, "sg value");

    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    getContentPane().add(panel);

    pack();
    setVisible(true);
    setLocationRelativeTo(null);
    setResizable(true);
  }

  public static void main(String[] args) {
    MigLayoutTest test = new MigLayoutTest();
  }

}

Объяснение моих изменений:

Теперь, кроме упрощения кода и макета, я использовал "debug" в пределах ограничений макета, чтобы увидеть, что на самом деле происходит с макетом. Я предлагаю использовать его в любое время, когда что-то пойдет не так с макетом - он делает MigLayout рисовать границы компонентов и ячеек, визуализируя потенциальные проблемы.

Я удалил ненужные mainframe и p - если вам действительно нужно это для вложенного макета, попробуйте добавить его, как только вы решите внутренний макет по своему вкусу.

Что касается p и panel - возможно, вам нужны два разных макета, один вложенный в другой, но это фактический источник вашей проблемы. p имел также собственный макет сетки,

p.add(panel,"cell 0 0");

вы помещаете panel в верхнюю левую ячейку p - вот почему panel не был распределен по всему окну, а сидел в верхнем левом углу.

Как вы видите без p, он позитивно позиционируется в середине экрана без постоянного размера, все еще отображая все компоненты, но, что более важно, он имеет 50% размера окна для первого и 50% для последних двух колонны. Это было достигнуто путем предоставления компонентам "группы размеров":

Дает компоненту имя группы размеров. Все компоненты, имя группы размеров получит тот же BoundSize (min/preferred/max). это используется для обеспечения того, чтобы все компоненты группы одинакового размера такой же минимальный/предпочтительный/максимальный размер, который является самым большим компонентом в группа. Можно использовать пустое имя "".

И это также изменяет размеры, как должно!

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

Далее - установка размеров в постоянное значение не имеет смысла, поскольку после pack менеджер компоновки начинает определять все, основываясь на предпочтительных размерах окна и его содержимого. Кроме того, вы никогда не знаете, какой размер является вашим экраном пользователей, поэтому любой постоянный размер может быть одинаково плохим, если его эффективно использовать. Лучше управлять размером через контент и доступную среду выполнения. С вашим кодом на моей машине потребовалось все доступное горизонтальное пространство на моих двух экранах (2 x 1280) и отлично выглядело.

Я также думаю, что вам не нужно запускать фрейм с помощью EventQueue.invokeLater, просто создайте MigLayoutTest и это он.

ИЗМЕНИТЬ после собственного ответа OP

Настройка размера с помощью setBounds(0, 0, 1250, 500) до pack работает некорректно (под этим я подразумеваю, чтобы размер окна был таким). Даже на скриншоте ниже OP собственный ответ не высок на 500 пикселей. Вот что я получаю в Windows 7 с JDK 1.8.0_91:

Снимок экрана

Размер моего экрана - 1280 x 1024, размер окна программы - 914 x 301.

Я бы предложил использовать одно из следующих действий:

Чтобы установить его на постоянный размер 1250 x 500 пикселей, переместите setSize между pack и setVisible:

...
pack();
setSize(1250, 500);

Я бы использовал setSize, setBounds не имеет смысла, так как, вызывая setLocationRelativeTo(null), вы все равно центрируете окно программы на экране, так что начало немедленно отклоняется.

Чтобы максимизировать горизонтальную ориентацию, а высота должна быть 500 пикселей, установите предпочтительный размер основного окна перед pack:

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setPreferredSize(new Dimension(screenSize.width, 500));

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

Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setPreferredSize(new Dimension(screenSize.width, getPreferredSize().height));

Конечно, вы можете сделать окно размером 1250 x 500 большим, установив его предпочтительный размер, а не используя setSize.

Проблема с изменением размера сейчас не такая большая, но она все еще там - сделайте окно более широким, чем узкое. Вы заметите, что panel становится шире, даже если окно сузилось. Проблема в том, что компонент panel не становится достаточно большим, чтобы сначала заполнить один столбец p (BTW вы можете добавить флаг "debug" для каждого MigLayout, а также для panel - он затем набросает все внутренние компоненты также).

Чтобы заполнить родительский контейнер, добавьте его так:

p.add(panel, "cell 0 0, grow");

Теперь это полная ширина p с самого начала, и изменение размера работает как ожидалось.

Относительно запуска JFrame с помощью invokeLater - мы запускаем наши главные окна, как правило, без него, и у них никогда не было проблем, поскольку никаких взаимодействий с Swing не было, пока первый кадр не был виден, но я только что заметил, что это считается лучшей практикой - даже в учебниках Oracle. Похоже, я тоже кое-что узнал: -).

Сравнение окна кадра с добавлением и без добавления с выражением

Тестовый сценарий: запустите приложение и измените его размер.

Используя именно код в собственном ответе OP

Использование <code> p.add(панель,

Как вы видите на первом снимке экрана размер компонента меньше ширины столбца - похоже, что компонент находился за размером столбца при изменении размера. На втором скриншоте ширина компонента остается такой же, как ширина столбца. Как я сказал ранее, причиной может быть сочетание Java и/или операционной системы, я не знаю. Но, очевидно, это ведет себя по-другому и на моей машине менее оптимальной.

Ответ 2

Благодаря @Tomasz Stanczak, я решил это окончательно. Тем не менее, я нашел часть того, что он сказал, уместно, а другие нет. Для будущих читателей, которые могут это увидеть, я должен сделать это более ясным.

Конечный рабочий код:

import java.awt.Cursor;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import net.miginfocom.swing.MigLayout;

public class MigLayoutMySCCEE extends JFrame{
private JFrame mainFrame;
private JPanel panel;

private JLabel lblResumenAuto;
private JLabel lblResumenAutoResult;
private JLabel lblResumenRazonSocial;
private JLabel lblResumenRazonSocialResult;
private JLabel lblResumenPeriodo;
private JLabel lblResumenPeriodoResult;
private JLabel lblResumenFechaHora;
private JLabel lblResumenFechaHoraResult;

public MigLayoutMySCCEE(){
    run();
}

public void run(){
    JPanel p = new JPanel();
    p.setLayout(new MigLayout("debug, fill","[grow]","[50:20:30]10[100::]10[20::]10[50!]10[20!]"));

    panel = new JPanel();
    panel.setLayout(new MigLayout("fillx", "[left, 15%]10[left, grow, 35%]10[left, 15%]10[left, grow, 35%]", "[center]10[center]"));

    lblResumenAuto = new JLabel("MY LABEL 1111111111111");
    lblResumenAutoResult = new JLabel("1111111111111111111111");

    panel.add(lblResumenAuto);
    panel.add(lblResumenAutoResult);

    lblResumenRazonSocial = new JLabel("MY LABEL 2222222222");
    lblResumenRazonSocialResult = new JLabel("2222222222222222222222");

    panel.add(lblResumenRazonSocial);
    panel.add(lblResumenRazonSocialResult,"wrap");

    lblResumenPeriodo = new JLabel("MY LABEL 33333333333333");
    lblResumenPeriodoResult = new JLabel("3333333333333333333333333333333333333333333333333333333");

    panel.add(lblResumenPeriodo);
    panel.add(lblResumenPeriodoResult);
    //poner el texto como html puede tener otra linea, porque es muy largo
    lblResumenFechaHora = new JLabel("<html>MY LABEL <br /> 4444444444444444</html>");
    lblResumenFechaHoraResult = new JLabel("4444444444444444444444444");

    panel.add(lblResumenFechaHora);
    panel.add(lblResumenFechaHoraResult);

    p.add(panel,"cell 0 0");

    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    setBounds(0, 0, 1250, 500);
    getContentPane().add(p);

    pack();
    setVisible(true);
    setLocationRelativeTo(null);
    setResizable(true);
}

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            MigLayoutMySCCEE test = new MigLayoutMySCCEE();

        }
    });
}
}

И окно выглядит так:

введите описание изображения здесь

Некоторые примечания:

  • Тройка debug очень полезна и призывает меня снова прочитать DOC. Однако я хочу, чтобы он мог получить больше внимания и значимости на странице быстрого запуска.

  • Неправильное вложение - проблема, и Томаш заставляет меня пересмотреть иерархию, отлично! Я изменил часть вложенности, чтобы сделать ее более ясной. Но это не имеет значения.

  • Часть sizeGroup - отличная идея, и я решил как можно больше использовать ее в будущем развитии, но это не имеет отношения к моему делу. Я решил это, не используя его.

  • Я нашел более широкую и более широкую проблему после наконечника Tomasz, но это связано с [max!] в сочетании с добавлением панели в первую ячейку макета сетки, а не вложением фрейма/панели. Я удалил [max!] и изменил его на [grow], и ширина больше не расширяется. Я не касался части p.add(panel, "cell 0 0"). Как наблюдалось и по определению,

    p.setLayout(new MigLayout("debug, fill","[grow]","[50:20:30]10[100::]10[20::]10[50!]10[20!]"));

первая строка панели имеет только один столбец, если я хорошо понимаю.

EDIT после редактирования Tomasz

Я, конечно, узнал больше, чем вы. Я попытался избавиться от части setBounds() и изменить add(panel, "cell 0 0") на add(panel, "grow"), но я не вижу большой разницы, я что-то упустил? Тем не менее "grow" почти всегда лучший выбор и желательный.

Вот два GIF, показывающих, что я получил: (ScreenToGif, легкий, но мощный инструмент, особенно полезный для витрины)

введите описание изображения здесь

введите описание изображения здесь