我终于得到了我想要垂直堆叠具有随时间变化的首选高度的组件的行为。但我需要使用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);
}
}
答案 0 :(得分:6)
使用BoxLayout。
您可以将Box.createVerticalGlue()用于空白区域。
BoxLayout尊重组件的最大大小,因此您可能需要覆盖getMaximumSize()方法以返回红色和绿色框的首选大小。
对于绿色框,您还需要覆盖getPreferredSize()以保持高度与宽度同步。
答案 1 :(得分: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);
}
}
答案 2 :(得分: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