Swing MigLayout无法增长填充列以填充容器长度

时间:2016-07-29 12:48:02

标签: java swing miglayout

我正在使用MigLayout一个很长的窗口。

enter image description here 我希望“推”第二和第四列来填充整个窗口的所有长度,但我无法实现它。列约束中没有push选项,只有growfill

这是一个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();

        }
    });
}
}

如果运行代码,您可以注意到列的宽度随着包含文本长度的变化而增加。但它永远不会填满其容器的整个宽度。

最理想的是,按照整个宽度的15%修正第0列和第2列,让列13将其余部分35%复制,前两列占整个宽度的50%。

我在这里遗漏了什么吗?我不想指定每列的宽度,设置pre:min:max,因为这是不好的做法,正如this post所建议的那样,它会得到很多投票。

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

但是,如果我设置pref:min:max,它可以填充整个宽度。

2 个答案:

答案 0 :(得分:2)

首先是代码,然后是解释。试试这个:

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绘制组件和单元格的边界,从而可视化潜在的问题。

我删除了不必要的mainframep - 如果您真的需要它用于嵌套布局,请尝试在您根据自己的喜好解决内部布局后添加它。

至于ppanel - 您可能需要两个不同的布局,一个嵌套在另一个布局中,但这是您问题的实际来源。 p也有自己的网格布局,

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

您将panel放在p的左上角单元格中 - 这就是panel未分布在整个窗口但位于左上角的原因。

如你所见,没有p它在屏幕中间位置很好,没有任何大小不变,仍显示所有组件,但更重要的是,它有50%的窗口大小为第一个,50%为最后两列。这是通过给组件“尺寸组”来实现的:

  

为组件提供大小组名称。共享的所有组件   大小组名称将获得相同的BoundSize(min / preferred / max)。它是   用于确保相同大小组中的所有组件都获得   相同的最小/最佳/最大尺寸是最大的组件   群组。一个空名&#34;&#34;可以使用。

它也会像它应该调整大小!

嵌套布局也可能是另一个问题的根源 - 不知道你是否没有注意到它或者它只是没有出现在你的机器上,但如果我试图调整你的窗口大小{{{即使我收缩了窗户,也越来越宽(从不变窄)。在某些时候,它比窗口本身更宽,甚至在每次调整大小时都会进一步增长。

接下来 - 将维度设置为常量值没有意义,因为在panel之后,布局管理器会根据窗口的首选大小及其内容开始调整所有内容的大小。此外,您永远不知道用户屏幕的大小,因此如果有效使用,任何常量大小都可能同样糟糕。最好通过内容和可用的运行时环境来扩大规模。使用我的机器上的代码,它占用了我的两个屏幕(2 x 1280)的所有可用水平空间,看起来并不漂亮。

我还认为您不需要使用pack启动框架,只需创建一个EventQueue.invokeLater就可以了。

在OP自己的回答后编辑

MigLayoutTest之前使用setBounds(0, 0, 1250, 500)设置大小无法正常工作(我的意思是将窗口设置为该大小)。即使在OP自己的答案下面的屏幕截图中,它也不是500px高。以下是我在运行JDK 1.8.0_91的Windows 7上获得的内容:

Screenshot

我的屏幕尺寸为1280 x 1024,程序窗口的大小为914 x 301.

我建议使用以下其中一项:

要将其设置为1250 x 500像素的常量,请在packsetSize之间移动pack

setVisible

我使用... pack(); setSize(1250, 500); setSize没有任何意义,因为通过调用setBounds无论如何都要将程序窗口置于屏幕中心,所以原产地立即被解雇。

要水平最大化并让高度为500像素,请设置主窗口setLocationRelativeTo(null)之前的首选尺寸:

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的一列(顺便说一下,您可以为每个MigLayout添加&#39; debug&#39;标志,也是p的那个 - 然后它将概述所有内部组件)。

要填充父容器,请按以下方式添加:

panel

现在它从一开始就是p.add(panel, "cell 0 0, grow"); 的全宽,并且调整大小按预期工作。

关于使用p启动JFrame - 我们通常在没有它的情况下启动主窗口并且从未遇到过问题,因为在第一帧可见之前没有与Swing的交互,但我只是注意到它被认为是最佳实践 - 即使在Oracle的教程中也是如此。看起来我也在这里学到了一些东西: - )。

框架窗口的比较,包括和不添加&#34;增长&#34;

测试场景:启动应用程序并将其调整为更宽。

Using exactly the code in OP's own answer

Using <code>p.add(panel,"cell 0 0, grow");</code>

正如您在第一个屏幕截图中看到的,组件大小小于列宽 - 看起来组件在调整大小时位于列大小后面。在第二个屏幕截图中,组件宽度始终与列宽保持相同。正如我之前所说,原因可能是Java和/或操作系统组合,我不知道。但显然它的行为有所不同,而且在我的机器上并不是最佳的。

答案 1 :(得分:0)

感谢@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();

        }
    });
}
}

窗口看起来像:

enter image description here

一些注意事项:

  1. debug技巧非常有用,并促使我再次阅读DOC。但是,我希望它可以在“快速入门”页面中获得更多关注和重要性。

  2. 不必要的嵌套是一个问题,Tomasz让我审查层次结构,太棒了!我更改了嵌套部分以使其更清晰。但这无关紧要。

  3. sizeGroup部分是个好主意,我决定尽可能在未来的开发中使用它,但这与我的情况无关。我没有使用它就解决了。

  4. 在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!]"));

  5. 如果我理解的话,面板的第一行只有一列。

    在Tomasz编辑之后编辑

    我肯定比你学到的更多:)我试图摆脱setBounds()部分并将add(panel, "cell 0 0")改为add(panel, "grow"),但我看不出太大的区别,我错过了这里有什么? 然而"grow"几乎总是更好的选择和期望。

    这里有2个GIF显示我得到了:( ScreenToGif,一个轻量级但功能强大的工具,对展示特别有用)

    enter image description here

    enter image description here