2

我终于得到了我想要的垂直堆叠组件的行为,这些组件具有随时间变化的首选高度。但我需要使用 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, 0, w, h);
            g.setColor(Color.BLACK);
            g.drawRect(0, 0, w-1, h-1); 
            String s = this.dpref.width+"x"+this.dpref.height;
            FontMetrics fm = g.getFontMetrics();
            g.drawString(s, 0, 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);

    }

}
4

3 回答 3

6

使用 BoxLayout。

您将使用 Box.createVerticalGlue() 作为空白空间。

BoxLayout 尊重组件的最大尺寸,因此您可能需要重写 getMaximumSize() 方法以返回红色和绿色框的首选尺寸。

对于绿色框,您还需要覆盖 getPreferredSize() 以保持高度与宽度同步。

于 2011-06-14T16:20:29.603 回答
4

您可以SpringLayout通过将所有组件连接在一起并连接到其容器的边缘来解决此问题。

按钮面板
左侧和顶部按钮面板到容器面板左侧和顶部

Green Panel
left, right and bottom to the left, right and bottom of the container panel

容器面板从左到左的红色
面板和绿色面板的底部到顶部

空格标签
从上到南按钮面板,左右到容器面板左右,从下到上红色面板

编辑:喜欢 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, 0, w, h);
      g.setColor(Color.BLACK);
      g.drawRect(0, 0, w - 1, h - 1);
      String s = this.dpref.width + "x" + this.dpref.height;
      FontMetrics fm = g.getFontMetrics();
      g.drawString(s, 0, 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, buttonPanel, 5, 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.WEST, resizingPanelSquare, 5, SpringLayout.WEST, this);
    layout.putConstraint(SpringLayout.EAST, resizingPanelSquare, -5, SpringLayout.EAST, this);

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

    add(spaceLabel);
    layout.putConstraint(SpringLayout.NORTH, spaceLabel, 5, SpringLayout.SOUTH, buttonPanel);
    layout.putConstraint(SpringLayout.WEST, spaceLabel, 5, SpringLayout.WEST, this);
    layout.putConstraint(SpringLayout.EAST, spaceLabel, -5, SpringLayout.EAST, this);
    layout.putConstraint(SpringLayout.SOUTH, spaceLabel, -5, SpringLayout.NORTH, 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);

  }

}
于 2011-06-14T16:19:35.637 回答
0

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
于 2012-06-02T02:20:56.507 回答