当前位置: 首页 > 知识库问答 >
问题:

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

燕实
2023-03-14

我有一个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();
            }
        });
    }
}

如果我删除代码行main Panel.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约束或参数?或者它是MigLayout库中的一个bug?

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

共有2个答案

傅雪松
2023-03-14

对我有效的解决方案是在MigLayout中使用绝对定位,即组件约束的形式为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);
            }
        });       
    }
}
邓赤岩
2023-03-14

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

那么,为什么当你添加这8个小面板时,它突然起作用了呢?MigLayout不知道如果要求它跨越比如说三列,它应该占据多少空间——直到这三列存在。因此,通过html" target="_blank">添加这些小面板,您可以告诉经理您对spanx 2spanx 3约束的期望。(在我们的例子中,这些是cell约束的第三个参数。)

还请注意,最好使用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);
            }
        });       
    }
}

也可能有其他解决方案。

 类似资料:
  • 问题内容: 有没有一种方法可以使网格布局中的单个元素占据一个网格中的多个位置。示例:我想创建一个占据整个网格行的文本框,有什么方法可以做到这一点? 问题答案: 请改用GridBagLayout。

  • 对于我的表视图单元格的动态高度,我从此链接中引用。在 UITableView 中使用自动布局进行动态单元格布局 这是我的表视图数据源和委托方法的代码 我有 2 个问题: > 我的问题是我在线路附近收到错误 在和。 为什么我必须在单元格中同时写入标签文本“和? 另外,我是否缺少实现单元动态高度所需的任何内容?

  • 我使用自动布局的动态高度表格单元格,在表格单元格内部,有1个动态高度UILabel和1个动态UIView,其中包括多个UIImageView。 这是布局:情节提要屏幕截图 TableCell: 但我犯了这个错误: 请帮助我,我错过了什么。提前谢谢你。

  • 问题内容: 我在长度为4+的div内有一系列文章,没有任何四舍五入的行标记。我需要将其表示为每行3个文章(列)的表格,大概用display: grid。每篇文章都有一个页眉,一个节和一个页脚。 如何 在每行文章的内部为每个页眉实现相等的高度,为每个部分提供相等的高度以及与文章底部对齐的相等高度的页脚?可能吗 我应该使用display: table吗? PS我需要根据屏幕宽度动态更改每行的文章数。谢

  • 我正在使用libgdx创建一个Android游戏,在这个游戏中,玩家可以触摸屏幕的特定部分,在道路上左右移动汽车。我最初制作的游戏高度和宽度分别为480 x 800,但当设备分辨率或多或少时,我制作的更多,触摸坐标不在同一个地方。如果一种根据正在玩游戏的设备来缩放我的坐标的方法。我用来计算触摸点的功能如下: 如果设备大于或小于480 x 800,如何相应地调整inbounds()比例中的坐标。

  • 本文向大家介绍百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换,包括了百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换的使用技巧和注意事项,需要的朋友参考一下 在项目中面对不同的坐标体系,在地图上显示多多少少都会有点偏差,下面是使用javascript写的转换方法,具体代码如下所示: