Java MigLayout具有绝对单元格坐标和跨距的意外布局

Java MigLayout具有绝对单元格坐标和跨距的意外布局,java,swing,layout-manager,miglayout,Java,Swing,Layout Manager,Miglayout,我有一个JPanel,可以动态添加和删除不同大小的子面板。因此,我使用具有绝对单元坐标的miglayet。在下面的例子中,结果不是我所期望的 我的代码的简化版本说明了问题,如下所示: import java.awt.Color; import java.awt.Dimension; import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JPanel; import net.miginfoco

我有一个JPanel,可以动态添加和删除不同大小的子面板。因此,我使用具有绝对单元坐标的miglayet。在下面的例子中,结果不是我所期望的

我的代码的简化版本说明了问题,如下所示:

import java.awt.Color;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;

public class MigLayoutDemo
{
    private static final int CELL_WIDTH = 60;
    private static final int CELL_HEIGHT = 50;

    public static JPanel createBigPanel()
    {
        JPanel bigSubPanel = new JPanel();
        bigSubPanel.setPreferredSize(new Dimension(3 * CELL_WIDTH, 2 * CELL_HEIGHT));      
        bigSubPanel.setBorder(BorderFactory.createLineBorder(Color.black));       
        bigSubPanel.setBackground(Color.LIGHT_GRAY);
        return bigSubPanel;
    }

    public static JPanel createSmallPanel()
    {
        JPanel smallSubPanel = new JPanel();
        smallSubPanel.setPreferredSize(new Dimension(2 * CELL_WIDTH, CELL_HEIGHT));      
        smallSubPanel.setBorder(BorderFactory.createLineBorder(Color.black));     
        smallSubPanel.setBackground(Color.LIGHT_GRAY);
        return smallSubPanel;
    }

    public static JPanel createCellPanel()
    {
        JPanel cellSubPanel = new JPanel();
        cellSubPanel.setPreferredSize(new Dimension(CELL_WIDTH, CELL_HEIGHT));      
        cellSubPanel.setBackground(Color.LIGHT_GRAY);
        return cellSubPanel;
    }

    private static void createAndShowGUI() 
    {
        //Create and set up the window.
        JFrame frame = new JFrame("MigLayoutDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

        // main panel where the sub-panels are placed in
        JPanel mainPanel = new JPanel();
        MigLayout mg = new MigLayout("debug, gap 0 0");        
        mainPanel.setLayout(mg);

        mainPanel.add(createBigPanel(), "cell 0 0 3 2"); // [col row [span x [span y]]] 
        mainPanel.add(createBigPanel(), "cell 3 0 3 2");
        mainPanel.add(createSmallPanel(), "cell 6 0 2 1, align left top");
        mainPanel.add(createSmallPanel(), "cell 6 1 2 1, align left top");

        mainPanel.add(createSmallPanel(), "cell 0 2 2 1, align left top");
        mainPanel.add(createBigPanel(), "cell 2 2 3 2");       
        // problem occurs
        mainPanel.add(createBigPanel(), "cell 5 2 3 2");

//        mainPanel.add(createCellPanel(), "cell 0 4 1 1");
//        mainPanel.add(createCellPanel(), "cell 1 4 1 1");
//        mainPanel.add(createCellPanel(), "cell 2 4 1 1");
//        mainPanel.add(createCellPanel(), "cell 3 4 1 1");
//        mainPanel.add(createCellPanel(), "cell 4 4 1 1");
//        mainPanel.add(createCellPanel(), "cell 5 4 1 1");
//        mainPanel.add(createCellPanel(), "cell 6 4 1 1");
//        mainPanel.add(createCellPanel(), "cell 7 4 1 1");

        frame.getContentPane().add(mainPanel);
        frame.setResizable(false);
        frame.pack();
    }


    public static void main(String[] args)
    {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
如果我删除代码行
mainPanel.add(createBigPanel(),“cell 5 2 3 2”)一切都如我所料。但是,当我在第5列和第2行中添加面板时,面板似乎被放置在第5列和第6列之间的额外列中

如果我还添加代码行

mainPanel.add(createCellPanel(), "cell 0 4 1 1");
mainPanel.add(createCellPanel(), "cell 1 4 1 1");
mainPanel.add(createCellPanel(), "cell 2 4 1 1");
mainPanel.add(createCellPanel(), "cell 3 4 1 1");
mainPanel.add(createCellPanel(), "cell 4 4 1 1");
mainPanel.add(createCellPanel(), "cell 5 4 1 1");
mainPanel.add(createCellPanel(), "cell 6 4 1 1");
mainPanel.add(createCellPanel(), "cell 7 4 1 1");
问题似乎已“修复”,所有内容都放在正确的列和行中

我怀疑我的问题与细胞的跨度有关。 我是否缺少一些布局约束或参数?或者它是MigLayout库中的一个bug


我目前正在java 7中使用MigLayout V4.0。我还使用V5.0快照测试了我的代码,但结果是一样的。

该示例按预期工作。看起来只有一个附加列。 面板2和面板7是左对齐的,因此看起来好像还有另一列。 将
约束置于面板2和面板2的中心将显示面板
我们只是左对齐,没有创建其他列

那么,当你添加8个小面板时,为什么它突然起作用呢?MIG布局的

不知道如果被要求跨越三个区域,它应该占据多少空间
列——直到这三列存在。因此,通过添加这些小面板
告诉经理您对
spanx 2
spanx 3
约束的期望。 (在本例中,这些是
单元格
约束的第三个参数。)

还请注意,最好使用
w
h
约束,而不是 通过
setPreferredSize()
方法指定大小

我已经创建了一个修改过的示例,在该示例中,我使用标签而不是面板 更好的视觉理解:

package com.zetcode;

import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;


public class MigLayoutDemo2 extends JFrame {

    public MigLayoutDemo2() {

        initUI();
    }

    private void initUI() {

        JPanel pnl = new JPanel(new MigLayout("gap 0"));

        pnl.add(createLabel("One"), "cell 0 0 3 2, w 180, h 100"); 
        pnl.add(createLabel("Two"), "cell 3 0 3 2, w 180, h 100, center");
        pnl.add(createLabel("Three"), "cell 6 0 2 1, align left top, w 120, h 50");
        pnl.add(createLabel("Four"), "cell 6 1 2 1, align left top, w 120, h 50");
        pnl.add(createLabel("Five"), "cell 0 2 2 1, align left top, w 120, h 50");
        pnl.add(createLabel("Six"), "cell 2 2 3 2, w 180, h 100");       
        pnl.add(createLabel("Seven"), "cell 5 2 3 2, center, w 180, h 100");

//        pnl.add(createLabel("A"), "cell 0 4 1 1, w 60, h 50");
//        pnl.add(createLabel("A"), "cell 1 4 1 1, w 60, h 50");
//        pnl.add(createLabel("A"), "cell 2 4 1 1, w 60, h 50");
//        pnl.add(createLabel("A"), "cell 3 4 1 1, w 60, h 50");
//        pnl.add(createLabel("A"), "cell 4 4 1 1, w 60, h 50");
//        pnl.add(createLabel("A"), "cell 5 4 1 1, w 60, h 50");
//        pnl.add(createLabel("A"), "cell 6 4 1 1, w 60, h 50");
//        pnl.add(createLabel("A"), "cell 7 4 1 1, w 60, h 50");        

        add(pnl);
        pack();

        setTitle("MigLayout example");
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
    }

    private JLabel createLabel(String text) {

        JLabel lbl = new JLabel(text, JLabel.CENTER);
        lbl.setBorder(BorderFactory.createEtchedBorder());

        return lbl;

    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MigLayoutDemo2 ex = new MigLayoutDemo2();
                ex.setVisible(true);
            }
        });       
    }
}
在以下示例中,标签2和7居中。如果 左对齐,看起来标签7位于单独的列中 但事实并非如此

通过在末尾添加8个小面板,我们告诉经理 布局应该是什么样子的:

编辑1

根据评论的解决方案。我采取了另一种方法。我达到了要求 带拆分单元格的布局:

package com.zetcode;

import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;


public class MigLayoutDemo3 extends JFrame {

    public MigLayoutDemo3() {

        initUI();
    }

    private void initUI() {

        JPanel pnl = new JPanel(new MigLayout("gap 0 0"));

        pnl.add(createLabel("One"), "gapright 0, w 180, h 100, split 2"); 
        pnl.add(createLabel("Two"), "w 180, h 100");
        pnl.add(createLabel("Three"), "split 2, flowy, w 120, h 50, gapbottom 0");
        pnl.add(createLabel("Four"), "w 120, h 50, wrap");
        pnl.add(createLabel("Five"), "top, gapright 0, split 3, span 3, w 120, h 50");
        pnl.add(createLabel("Six"), "gapright 0, w 180, h 100");       
        pnl.add(createLabel("Seven"), "w 180, h 100");

        add(pnl);
        pack();

        setTitle("MigLayout example");
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
    }

    private JLabel createLabel(String text) {

        JLabel lbl = new JLabel(text, JLabel.CENTER);
        lbl.setBorder(BorderFactory.createEtchedBorder());

        return lbl;

    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MigLayoutDemo3 ex = new MigLayoutDemo3();
                ex.setVisible(true);
            }
        });       
    }
}
还有其他解决办法


对我有效的解决方案是在MIG布局中使用绝对定位,即组件约束,形式为
pos x y[x2][y2]

import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;


public class MigLayoutDemo4 extends JFrame {

    private static final int CELL_WIDTH = 60;
    private static final int CELL_HEIGHT = 50;

    public MigLayoutDemo4() {

        initUI();
    }

    private void initUI() {

        JPanel pnl = new JPanel(new MigLayout("gap 0 0"));


        pnl.add(createLabel("One"), "pos 0 0"); 
        pnl.add(createLabel("Two"), "pos "+(CELL_WIDTH * 3)+" "+(CELL_HEIGHT * 0));
        pnl.add(createLabel("Three"), "pos "+(CELL_WIDTH * 6)+" "+(CELL_HEIGHT * 0));
        pnl.add(createLabel("Four"), "pos "+(CELL_WIDTH * 6)+" "+(CELL_HEIGHT * 1));
        pnl.add(createLabel("Five"), "pos "+(CELL_WIDTH * 0)+" "+(CELL_HEIGHT * 2));
        pnl.add(createLabel("Six"),"pos "+(CELL_WIDTH * 2)+" "+(CELL_HEIGHT * 2));       
        pnl.add(createLabel("Seven"), "pos "+(CELL_WIDTH * 5)+" "+(CELL_HEIGHT * 2));

        add(pnl);
        pack();

        setTitle("MigLayout example");
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
    }

    private JLabel createLabel(String text) {

        JLabel lbl = new JLabel(text, JLabel.CENTER);
        lbl.setBorder(BorderFactory.createEtchedBorder());

        return lbl;

    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MigLayoutDemo3 ex = new MigLayoutDemo3();
                ex.setVisible(true);
            }
        });       
    }
}

我不明白的是,为什么柱子会变得比需要的更大。因为标签7正好适合第6-8列中的空间(与添加之前一样)。你能不能建议一种方法,在不添加8个小面板的情况下,获得与上一张图片相同的结果?我试图将每个列的大小定义为列约束,但结果是面板的宽度始终为8*60。我需要的是一个始终具有所需最小尺寸的面板。感谢您的建议和提示。您的解决方案工作正常。不幸的是,考虑到我想在主面板中动态添加和删除子面板,它没有那么灵活。