摆动:没有MigLayout的垂直堆叠组件

问题描述

| 我终于得到了我想要的垂直堆叠组件的行为,这些组件的首选高度随时间变化。但是我需要使用MigLayout。 有没有MigLayout的方法吗? (它是针对图书馆的,除非有必要,否则我不想强制依赖) 这是我正在寻找的行为(我的测试程序可以实现): 在垂直顺序中,有一个调整大小的按钮,即“空白空间”(嗯,一个JLabel标记为这样),一个红色矩形和一个绿色正方形。调整大小按钮的高度固定。红场具有随机大小,可以在任意时间更改。绿色正方形设置其首选高度以匹配其宽度,我想扩展其宽度以填充容器。空空间会水平和垂直扩展,以填充容器中的剩余空间。 什么可以代替MigLayout工作?
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;

public class AutoResizeDemo extends JPanel
{   
    static private class ResizingPanel extends JPanel
    {
        final private Color color;

        private Dimension dpref = new Dimension(100,100);

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int w = getWidth();
            int h = getHeight();
            g.setColor(this.color);
            g.fillRect(0,w,h);
            g.setColor(Color.BLACK);
            g.drawRect(0,w-1,h-1); 
            String s = this.dpref.width+\"x\"+this.dpref.height;
            FontMetrics fm = g.getFontMetrics();
            g.drawString(s,fm.getHeight());
        }

        public ResizingPanel(Color color,boolean isSquare)
        {
            this.color = color;
            if (isSquare)
            {
                addComponentListener(new ComponentAdapter() {
                    @Override public void componentResized(ComponentEvent e) {
                        doResize(getWidth(),getWidth());
                    }               
                });
            }
        }

        @Override public Dimension getPreferredSize() {
            return this.dpref;
        } 

        public void doResize(int w,int h)
        {
            this.dpref = new Dimension(w,h);
            revalidate();
        }
    }

    public AutoResizeDemo()
    {
        super(new MigLayout(\"\",\"[grow]\",\"\"));
        setPreferredSize(new Dimension(200,800));

        final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED,false);
        ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN,true);
        JPanel buttonPanel = new JPanel(new FlowLayout());

        final Random rand = new Random();
        addButton(buttonPanel,\"resize\",new Runnable() {
            @Override public void run() {
                resizingPanelRandom.doResize(
                        rand.nextInt(100)+100,rand.nextInt(100)+100
                        );
            }           
        });
        add(buttonPanel,\"wrap\");
        JLabel spaceLabel = new JLabel(\"empty space\");
        spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        add(spaceLabel,\"push,grow,wrap\");
        add(resizingPanelRandom,\"wrap\");
        add(resizingPanelSquare,\"pushx,growx,wrap\");
    }

    private void addButton(JPanel panel,String title,final Runnable r) {
        JButton button = new JButton(title);
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                r.run();
            }           
        });
        panel.add(button);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame(AutoResizeDemo.class.getSimpleName());
        frame.setContentPane(new AutoResizeDemo());
        frame.pack();
        frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

    }

}
    

解决方法

        您可以使用
SpringLayout
解决此问题,方法是将所有组件连接在一起并连接到其容器的边缘。 按键面板 按钮面板的左侧和顶部到容器面板的左侧和顶部 绿色面板 容器面板的左侧,右侧和底部,左侧,右侧和底部 红色面板 容器面板的左到左和绿色面板的底部到顶部 空间标签 按钮面板的顶部至南部,容器面板的左侧,右侧,左侧和右侧,红色面板的底部至顶部 编辑:我爱SpringLayout,没有什么不能做的。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SpringLayout;

public class AutoResizeDemo2 extends JPanel {
  static private class ResizingPanel extends JPanel {
    final private Color color;

    private Dimension dpref = new Dimension(100,100);

    @Override
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      int w = getWidth();
      int h = getHeight();
      g.setColor(this.color);
      g.fillRect(0,w,h);
      g.setColor(Color.BLACK);
      g.drawRect(0,w - 1,h - 1);
      String s = this.dpref.width + \"x\" + this.dpref.height;
      FontMetrics fm = g.getFontMetrics();
      g.drawString(s,fm.getHeight());
    }

    public ResizingPanel(Color color,boolean isSquare) {
      this.color = color;
      if (isSquare) {
        addComponentListener(new ComponentAdapter() {
          @Override
          public void componentResized(ComponentEvent e) {
            doResize(getWidth(),getWidth());
          }
        });
      }
    }

    @Override
    public Dimension getPreferredSize() {
      return this.dpref;
    }

    public void doResize(int w,int h) {
      this.dpref = new Dimension(w,h);
      revalidate();
    }
  }

  public AutoResizeDemo2() {

    SpringLayout layout = new SpringLayout();
    setLayout(layout);

    setPreferredSize(new Dimension(200,800));

    final ResizingPanel resizingPanelRandom = new ResizingPanel(Color.RED,false);
    ResizingPanel resizingPanelSquare = new ResizingPanel(Color.GREEN,true);
    JPanel buttonPanel = new JPanel(new FlowLayout());

    final Random rand = new Random();
    addButton(buttonPanel,\"resize\",new Runnable() {
      @Override
      public void run() {
        resizingPanelRandom.doResize(rand.nextInt(100) + 100,rand.nextInt(100) + 100);
      }
    });
    add(buttonPanel);
    layout.putConstraint(SpringLayout.NORTH,buttonPanel,5,SpringLayout.NORTH,this);
    layout.putConstraint(SpringLayout.WEST,SpringLayout.WEST,this);

    JLabel spaceLabel = new JLabel(\"empty space\");
    spaceLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK));

    add(resizingPanelSquare);
    layout.putConstraint(SpringLayout.SOUTH,resizingPanelSquare,-5,SpringLayout.SOUTH,this);
    layout.putConstraint(SpringLayout.EAST,SpringLayout.EAST,this);

    add(resizingPanelRandom);
    layout.putConstraint(SpringLayout.SOUTH,resizingPanelRandom,resizingPanelSquare);
    layout.putConstraint(SpringLayout.WEST,this);

    add(spaceLabel);
    layout.putConstraint(SpringLayout.NORTH,spaceLabel,buttonPanel);
    layout.putConstraint(SpringLayout.WEST,this);
    layout.putConstraint(SpringLayout.SOUTH,resizingPanelRandom);
  }

  private void addButton(JPanel panel,String title,final Runnable r) {
    JButton button = new JButton(title);
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        r.run();
      }
    });
    panel.add(button);
  }

  public static void main(String[] args) {
    JFrame frame = new JFrame(AutoResizeDemo2.class.getSimpleName());
    frame.setContentPane(new AutoResizeDemo2());
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

  }

}
    ,        使用BoxLayout。 您可以将Box.createVerticalGlue()用于空白空间。 BoxLayout遵循组件的最大大小,因此您可能需要重写getMaximumSize()方法以返回红色和绿色框的首选大小。 对于绿色框,您还需要重写getPreferredSize()以使高度与宽度保持同步。     ,        如果不进行大量分析,很难确定SpringLayout的布局。尝试使用TableLayout。布局中唯一棘手的部分是绿色方块的高度等于其宽度。对于布局管理器来说,这有点不寻常,因此我只是特例。一个可运行的示例:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.esotericsoftware.tablelayout.swing.Table;

public class Test extends JFrame {
    JButton button;
    JPanel red,green;

    public Test () {
        button = new JButton(\"Resize\");
        button.addActionListener(new ActionListener() {
            public void actionPerformed (ActionEvent e) {
                red.setPreferredSize(new Dimension(138,new Random().nextInt(190) + 10));
                red.revalidate();
            }
        });

        red = new JPanel();
        red.setPreferredSize(new Dimension(138,145));
        red.setBackground(Color.red);

        green = new JPanel();
        green.setPreferredSize(new Dimension(100,100));
        green.setBackground(Color.green);

        // The DSL can be much easier to describe complex hierarchies.
        boolean dsl = false;
        if (dsl)
            dsl();
        else
            javaApi();

        setSize(160,400);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void javaApi () {
        final Table table = new Table() {
            public void layout () {
                green.setPreferredSize(new Dimension(getWidth(),getWidth()));
                super.layout();
            }
        };
        table.pad(10).defaults().left().space(5);
        table.addCell(button);
        table.row();
        table.addCell().expandY();
        table.row();
        table.addCell(red);
        table.row();
        table.addCell(green).expandX().fillX();
        getContentPane().add(table);
    }

    private void dsl () {
        final Table table = new Table() {
            public void layout () {
                green.setPreferredSize(new Dimension(getWidth(),getWidth()));
                super.layout();
            }
        };
        table.register(\"button\",button);
        table.register(\"red\",red);
        table.register(\"green\",green);
        table.parse(\"pad:10 * left space:5 \" //
            + \"[button] ---\" //
            + \"[] expandy ---\" //
            + \"[red] ---\" //
            + \"[green] expandx fillx\" //
        );
        getContentPane().add(table);
    }

    public static void main (String[] args) throws Exception {
        new Test();
    }
}
基于表,很容易一目了然地了解布局。我提供了使用Java API和DSL的代码。自完成后,Java API很不错。这只是布局代码:
table.pad(10).defaults().left().space(5);
table.addCell(button);
table.row();
table.addCell().expandY();
table.row();
table.addCell(red);
table.row();
table.addCell(green).expandX().fillX();
DSL非常适合描述层次结构,此示例可能不需要。不幸的是,Java没有逐字字符串,尽管可以在文件中描述较大的UI。对于此示例,不带Java字符串引号的DSL将为:
pad:10 * left space:5
[button]
---
[] expandy
---
[red]
---
[green] expandx fillx