Swing:垂直堆叠组件,无需 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, 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);
}
}
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):
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);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用 BoxLayout。
您可以使用 Box.createVerticalGlue() 作为空白空间。
BoxLayout 尊重组件的最大尺寸,因此您可能需要重写 getMaximumSize() 方法以返回红色和绿色框的首选尺寸。
对于绿色框,您还需要重写 getPreferredSize() 以保持高度与宽度同步。
Use a BoxLayout.
You would use Box.createVerticalGlue() for the empty space.
BoxLayout respects the maximum size of a component, so you would probably need to override the getMaximumSize() method to return the preferred size for the red and green boxes.
For the green box you would also need to Override getPreferredSize() to keep the height in sync with the width.
您可以使用 SpringLayout 将所有组件连接在一起并连接到其容器的边缘来解决此问题。
按钮面板
按钮面板的左侧和顶部到容器面板的左侧和顶部
绿色面板
left、right、bottom到容器面板的left、right、bottom
Red Panel
容器面板从左到左以及绿色面板从下到上
空格标签
从上到南的按钮面板,从左到右到容器面板的左和右,从下到上的红色面板
编辑:我喜欢 SpringLayout,它什么都做不了'不做。
You can solve this using
SpringLayout
by wiring all your compenents together and to the edges of their container.Button Panel
left and top of the button panel to left and top of the container panel
Green Panel
left, right and bottom to the left, right and bottom of the container panel
Red Panel
left to left of container panel and bottom to top of the green panel
Space Label
top to south of the button panel, left and right to left and right of the container panel, bottom to top of the red panel
Edit: I love SpringLayout, there's nothing it can't do.
如果不进行大量分析,SpringLayout 很难确定它是如何布局的。尝试表格布局。布局中唯一棘手的部分是绿色方块的高度等于其宽度。对于布局管理器的支持来说,这有点不寻常,所以我只是对其进行特殊处理。一个可运行的示例:
基于表格,很容易一眼就了解布局。我包含了使用 Java API 和 DSL 的代码。 Java API 很好,因为您可以完成。这里只是布局代码:
DSL 非常适合描述层次结构,但对于本例来说可能不是必需的。不幸的是,尽管可以在文件中描述大型 UI,但 Java 没有逐字字符串。此示例中不带 Java 字符串引号的 DSL 为:
SpringLayout is difficult to determine how it is laid out without a lot of analyzing. Try TableLayout. The only tricky part of your layout is the green square's height being equal to its width. This is a bit unusual for a layout manager to support, so I would just special case it. A runnable example:
Being table based, it is easy to get an idea of the layout at a glance. I included code for using the Java API and also the DSL. The Java API is nice since you get completion. Here is just the layout code:
The DSL is nice for describing hierarchies, probably not necessary for this example. Unfortunately Java doesn't have a verbatim string, though a large UI could be described in a file. The DSL for this example without the Java string quotes would be: