GridBagLayout 不稳定的大小调整和显示
GridBagLayout erratic resizing and displaying
我正在制作一个在容器中使用 GridBagLayout 的程序。我对此的主要用途是有两个 JPanel,分别占据 window 的水平 space 的 75% 和 25%。但出于某种原因,这两个面板看起来更像是 90/10,并且在调整大小时,较小的面板的尺寸会迅速变化,在它明显的最小尺寸和我认为所需的 25% 之间。
这里是相关代码。
frmReedreadV = new JFrame();
frmReedreadV.setBounds(x, y, width, height);
frmReedreadV.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmReedreadV.getContentPane().setLayout(new BoxLayout(frmReedreadV.getContentPane(), BoxLayout.Y_AXIS));
JPanel stretchyPanel = new JPanel();
frmReedreadV.getContentPane().add(stretchyPanel);
stretchyPanel.setLayout(new CardLayout(0, 0));
JPanel textAndUsers = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.weighty = 1;
textArea = new JTextArea();
textArea.setMargin(new Insets(2, 5, 5, 2));
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
scrollPane = new JScrollPane(textArea);
scrollPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
gbc.weightx = 0.8;
textAndUsers.add(scrollPane, gbc);
list = new FriendsList(listUpdate);
gbc.weightx = 0.2;
textAndUsers.add(list.frmUserList, gbc);
stretchyPanel.add(textAndUsers);
FriendsList 是包含在 JPanel 中的 JList。
CardLayout 主内容窗格中还有其他按钮和文本字段,但这些应该不会影响此 GridBagLayout 中的内容,对吗?
我制作了这个 JPanel 的另一个副本作为独立应用程序,它可以完美地显示和调整大小。看这里:
JFrame frame = new JFrame();
frame.getContentPane().setLayout((new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(100, 100, 550, 600);
JPanel stretchyPane = new JPanel();
frame.getContentPane().add(stretchyPane);
stretchyPane.setLayout(new CardLayout(0, 0));
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JTextArea text = new JTextArea();
text.setMargin(new Insets(2, 5, 5, 2));
JScrollPane panel1 = new JScrollPane(text);
FriendsList panel2 = new FriendsList(new Object());
c.fill = GridBagConstraints.BOTH;
c.weightx = .8;
c.weighty = 1;
panel.add(panel1, c);
c.weightx = .2;
//c.fill = GridBagConstraints.HORIZONTAL;
panel.add(panel2.frmUserList, c);
stretchyPane.add(panel);
frame.setVisible(true);
是什么导致了两者之间的差异,因为我已将原始文件逐行复制到副本中?
weightx 和 weighty 属性可能看起来像比例大小,但这不是它们的作用。事实上,它们决定了额外 space 在布局中的分布。
如果您通过在 JFrame 上调用 pack() 将所有内容设置为首选大小,则不会有额外的 space。这意味着 weightx 和 weighty 属性在该状态下无效。
一旦用户开始将 window 调整得更大,就会有额外的 space,只有那时 GridBagLayout 才会参考 weightx 和 weighty 属性来确定如何分配额外的 space 到每一列和每一行。在那之前,weightx 小的组件完全有可能比 weightx 大的组件宽,如果它们的首选尺寸决定的话。
希望这个简单的程序能够展示这个概念。尝试使用鼠标(或键盘)将 window 的大小调整得更宽,并观察每个文本字段如何增长:
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GridBagProportions {
static void buildAndShowWindow() {
JTextField small = new JTextField("small (0.8)", 5);
JTextField large = new JTextField("LARGE (0.2)", 30);
small.setMinimumSize(small.getPreferredSize());
large.setMinimumSize(large.getPreferredSize());
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets.left = 6;
gbc.insets.top = 6;
gbc.insets.bottom = 6;
gbc.weightx = 0.8;
panel.add(small, gbc);
gbc.weightx = 0.2;
gbc.insets.right = 6;
panel.add(large, gbc);
JFrame frame = new JFrame("GridBagLayout Proportions");
frame.getContentPane().add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
buildAndShowWindow();
}
});
}
}
那么可以做些什么呢?嗯,这是 GridBagLayout 做不到的一种布局场景。我会尝试使用 SpringLayout:
SpringLayout layout = new SpringLayout();
JPanel textAndUsers = new JPanel(layout);
SpringLayout.Constraints scrollPaneConstraints =
new SpringLayout.Constraints(scrollPane);
Spring scrollPaneWidth = scrollPaneConstraints.getWidth();
SpringLayout.Constraints listConstraints =
new SpringLayout.Constraints(scrollPaneWidth,
scrollPaneConstraints.getY(),
Spring.scale(scrollPaneWidth, 0.25f),
scrollPaneConstraints.getHeight());
layout.putConstraint(SpringLayout.EAST, textAndUsers, 0,
SpringLayout.EAST, frmUserList);
layout.putConstraint(SpringLayout.SOUTH, textAndUsers, 0,
SpringLayout.SOUTH, scrollPane);
textAndUsers.add(scrollPane, scrollPaneConstraints);
textAndUsers.add(frmUserList, listConstraints);
请注意,listConstraints 的创建指定了宽度参数,即 Spring.scale(scrollPaneWidth, 0.25f)
。这确保列表始终是包含 JTextArea 的 scrollPane 的四分之一宽。
SpringLayout 使用起来很棘手,因为您必须确保 link 布局容器的远边缘明确地指向子组件,因为 SpringLayout 不会自动增长以容纳所有子组件。这就是 putConstraint 调用正在做的事情。
我正在制作一个在容器中使用 GridBagLayout 的程序。我对此的主要用途是有两个 JPanel,分别占据 window 的水平 space 的 75% 和 25%。但出于某种原因,这两个面板看起来更像是 90/10,并且在调整大小时,较小的面板的尺寸会迅速变化,在它明显的最小尺寸和我认为所需的 25% 之间。
这里是相关代码。
frmReedreadV = new JFrame();
frmReedreadV.setBounds(x, y, width, height);
frmReedreadV.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmReedreadV.getContentPane().setLayout(new BoxLayout(frmReedreadV.getContentPane(), BoxLayout.Y_AXIS));
JPanel stretchyPanel = new JPanel();
frmReedreadV.getContentPane().add(stretchyPanel);
stretchyPanel.setLayout(new CardLayout(0, 0));
JPanel textAndUsers = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.weighty = 1;
textArea = new JTextArea();
textArea.setMargin(new Insets(2, 5, 5, 2));
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
scrollPane = new JScrollPane(textArea);
scrollPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
gbc.weightx = 0.8;
textAndUsers.add(scrollPane, gbc);
list = new FriendsList(listUpdate);
gbc.weightx = 0.2;
textAndUsers.add(list.frmUserList, gbc);
stretchyPanel.add(textAndUsers);
FriendsList 是包含在 JPanel 中的 JList。
CardLayout 主内容窗格中还有其他按钮和文本字段,但这些应该不会影响此 GridBagLayout 中的内容,对吗?
我制作了这个 JPanel 的另一个副本作为独立应用程序,它可以完美地显示和调整大小。看这里:
JFrame frame = new JFrame();
frame.getContentPane().setLayout((new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(100, 100, 550, 600);
JPanel stretchyPane = new JPanel();
frame.getContentPane().add(stretchyPane);
stretchyPane.setLayout(new CardLayout(0, 0));
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JTextArea text = new JTextArea();
text.setMargin(new Insets(2, 5, 5, 2));
JScrollPane panel1 = new JScrollPane(text);
FriendsList panel2 = new FriendsList(new Object());
c.fill = GridBagConstraints.BOTH;
c.weightx = .8;
c.weighty = 1;
panel.add(panel1, c);
c.weightx = .2;
//c.fill = GridBagConstraints.HORIZONTAL;
panel.add(panel2.frmUserList, c);
stretchyPane.add(panel);
frame.setVisible(true);
是什么导致了两者之间的差异,因为我已将原始文件逐行复制到副本中?
weightx 和 weighty 属性可能看起来像比例大小,但这不是它们的作用。事实上,它们决定了额外 space 在布局中的分布。
如果您通过在 JFrame 上调用 pack() 将所有内容设置为首选大小,则不会有额外的 space。这意味着 weightx 和 weighty 属性在该状态下无效。
一旦用户开始将 window 调整得更大,就会有额外的 space,只有那时 GridBagLayout 才会参考 weightx 和 weighty 属性来确定如何分配额外的 space 到每一列和每一行。在那之前,weightx 小的组件完全有可能比 weightx 大的组件宽,如果它们的首选尺寸决定的话。
希望这个简单的程序能够展示这个概念。尝试使用鼠标(或键盘)将 window 的大小调整得更宽,并观察每个文本字段如何增长:
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GridBagProportions {
static void buildAndShowWindow() {
JTextField small = new JTextField("small (0.8)", 5);
JTextField large = new JTextField("LARGE (0.2)", 30);
small.setMinimumSize(small.getPreferredSize());
large.setMinimumSize(large.getPreferredSize());
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets.left = 6;
gbc.insets.top = 6;
gbc.insets.bottom = 6;
gbc.weightx = 0.8;
panel.add(small, gbc);
gbc.weightx = 0.2;
gbc.insets.right = 6;
panel.add(large, gbc);
JFrame frame = new JFrame("GridBagLayout Proportions");
frame.getContentPane().add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
buildAndShowWindow();
}
});
}
}
那么可以做些什么呢?嗯,这是 GridBagLayout 做不到的一种布局场景。我会尝试使用 SpringLayout:
SpringLayout layout = new SpringLayout();
JPanel textAndUsers = new JPanel(layout);
SpringLayout.Constraints scrollPaneConstraints =
new SpringLayout.Constraints(scrollPane);
Spring scrollPaneWidth = scrollPaneConstraints.getWidth();
SpringLayout.Constraints listConstraints =
new SpringLayout.Constraints(scrollPaneWidth,
scrollPaneConstraints.getY(),
Spring.scale(scrollPaneWidth, 0.25f),
scrollPaneConstraints.getHeight());
layout.putConstraint(SpringLayout.EAST, textAndUsers, 0,
SpringLayout.EAST, frmUserList);
layout.putConstraint(SpringLayout.SOUTH, textAndUsers, 0,
SpringLayout.SOUTH, scrollPane);
textAndUsers.add(scrollPane, scrollPaneConstraints);
textAndUsers.add(frmUserList, listConstraints);
请注意,listConstraints 的创建指定了宽度参数,即 Spring.scale(scrollPaneWidth, 0.25f)
。这确保列表始终是包含 JTextArea 的 scrollPane 的四分之一宽。
SpringLayout 使用起来很棘手,因为您必须确保 link 布局容器的远边缘明确地指向子组件,因为 SpringLayout 不会自动增长以容纳所有子组件。这就是 putConstraint 调用正在做的事情。