2

I finally got the behavior I want for vertically stacking components that have a preferred height that changes with time. But I needed to use MigLayout.

Is there a way to do this w/o MigLayout? (It's for a library and I don't want to force the dependency unless I have to)

Here's the behavior I'm looking for (which my test program achieves):

enter image description here

In vertical order, there's a resize button, "empty space" (well, a JLabel marked as such), a red rectangle, and a green square. The resize button has fixed height. The red square has a random size that can change at arbitrary times. The green square sets its preferred height to match its width, and I want to expand its width to fill the container. The empty space expands horizontally and vertically to fill the remaining space in the container.

What would work instead of 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これは、すべてのコンポーネントをまとめてコンテナの端に配線することで解決できます。

ボタン パネル
の左とボタン パネルの上部からコンテナ パネルの左と上部

グリーン パネル
の左、右、および下からコンテナ パネルの左、右、および下

赤のパネル
はコンテナー パネルの左から左、緑のパネルの下から上

スペース ラベル
は、ボタン パネルの上から南、コンテナ パネルの左右から左右、赤いパネルの下から上

編集:私は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 に答える