更新组件的高度也会改变它的宽度
Updating component's height also changes it's width
我有一个 GUI,其中有一个主要 JPanel
并且在其中有多行,每一行都是另一行 JPanel
。每行(JPanel
类型)由 4 个较小的 JPanel
组成,这 4 个面板中的每个面板内部都有一个组件。最终结果是一个类似网格的界面。
主面板有一个 BoxLayout
,并且作为一行的一部分的面板有 FlowLayout
。
当我使用一些侦听器更新某些组件(从行)的高度时,整行变得更高,这按预期工作。但是发生的事情是,不仅高度发生了变化,而且组件(一行内)的宽度也发生了变化。我知道 BoxLayout
正在尝试使用 maxSize
和 minSize
来布局组件,我可以将它们设置为相同的值并且有效,但是当我调整 window 的大小时,其他行展开,而具有相同 minSize
和 maxSize
的行不会展开,网格结构变得混乱。
我想要实现的是只更新行的高度。当我调整 window 的大小时,整行都展开了,网格的结构仍然是网格。这是简短的、自包含的、正确的(可编译的)示例:
Main
class:
public class Main {
public static void main(String args[]) {
SwingUtilities.invokeLater(() -> {
new MainFrame(450,150);
});
}
}
MainFrame
class:
public class MainFrame extends JFrame{
public MainFrame(int width, int height) {
super("Title");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width, height);
setVisible(true);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
JScrollPane scrollPane = new JScrollPane(mainPanel);
add(scrollPane);
for(int i=0; i<50; i++) {
JPanel panel1 = new JPanel();
panel1.setLayout(new FlowLayout(FlowLayout.LEFT));
panel1.setBorder(BorderFactory.createMatteBorder(0, 1, 0, 1, Color.black));
panel1.setPreferredSize(new Dimension(70,35));
JPanel panel2 = new JPanel();
panel2.setLayout(new FlowLayout(FlowLayout.LEFT));
panel2.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
panel2.setPreferredSize(new Dimension(70,35));
JPanel panel3 = new JPanel();
panel3.setLayout(new FlowLayout(FlowLayout.LEFT));
panel3.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
panel3.setPreferredSize(new Dimension(70,35));
JTextArea area1 = new JTextArea("hello " + i);
area1.setPreferredSize(new Dimension(70,25));
panel1.add(area1);
JTextArea area2 = new JTextArea("hello " + i);
area2.setPreferredSize(new Dimension(70,25));
panel2.add(area2);
JTextArea area3 = new JTextArea("hello " + i);
area3.setPreferredSize(new Dimension(70,25));
panel3.add(area3);
JPanel row = new JPanel();
row.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.black));
row.setLayout(new BoxLayout(row, BoxLayout.X_AXIS));
row.add(panel1);
row.add(panel2);
row.add(panel3);
JButton button = new JButton("Click me");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
buttonPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
buttonPanel.setPreferredSize(new Dimension(70,35));
buttonPanel.add(button);
button.addActionListener(event -> {
panel1.setPreferredSize(new Dimension(panel1.getWidth(), panel1.getHeight() + 30));
area1.setPreferredSize(new Dimension(area1.getWidth(), area1.getHeight() + 30));
area1.updateUI();
});
row.add(buttonPanel);
mainPanel.add(row);
}
}
}
如果您 运行 此代码并按下按钮,它不仅会更新行高,还会更新行宽,并且网格不再对齐。
您正在根据组件的 "size" 设置 "preferred size"。两者可以不同。
你的代码应该是这样的:
//panel1.setPreferredSize(new Dimension(panel1.getWidth(), panel1.getHeight() + 30));
Dimension d = panel1.getPreferredSize();
panel1.setPreferredSize(new Dimension(d.width, d.height + 30));
此外,您不应该使用 updateUI()
。这是 Swing 在 LAF 更改时内部使用的一种方法。
相反,当您想要调用布局管理器时,您可以在已更改的顶级组件上调用 revalidate():
//area1.updateUI();
panel1.revalidate();
我有一个 GUI,其中有一个主要 JPanel
并且在其中有多行,每一行都是另一行 JPanel
。每行(JPanel
类型)由 4 个较小的 JPanel
组成,这 4 个面板中的每个面板内部都有一个组件。最终结果是一个类似网格的界面。
主面板有一个 BoxLayout
,并且作为一行的一部分的面板有 FlowLayout
。
当我使用一些侦听器更新某些组件(从行)的高度时,整行变得更高,这按预期工作。但是发生的事情是,不仅高度发生了变化,而且组件(一行内)的宽度也发生了变化。我知道 BoxLayout
正在尝试使用 maxSize
和 minSize
来布局组件,我可以将它们设置为相同的值并且有效,但是当我调整 window 的大小时,其他行展开,而具有相同 minSize
和 maxSize
的行不会展开,网格结构变得混乱。
我想要实现的是只更新行的高度。当我调整 window 的大小时,整行都展开了,网格的结构仍然是网格。这是简短的、自包含的、正确的(可编译的)示例:
Main
class:
public class Main {
public static void main(String args[]) {
SwingUtilities.invokeLater(() -> {
new MainFrame(450,150);
});
}
}
MainFrame
class:
public class MainFrame extends JFrame{
public MainFrame(int width, int height) {
super("Title");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width, height);
setVisible(true);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
JScrollPane scrollPane = new JScrollPane(mainPanel);
add(scrollPane);
for(int i=0; i<50; i++) {
JPanel panel1 = new JPanel();
panel1.setLayout(new FlowLayout(FlowLayout.LEFT));
panel1.setBorder(BorderFactory.createMatteBorder(0, 1, 0, 1, Color.black));
panel1.setPreferredSize(new Dimension(70,35));
JPanel panel2 = new JPanel();
panel2.setLayout(new FlowLayout(FlowLayout.LEFT));
panel2.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
panel2.setPreferredSize(new Dimension(70,35));
JPanel panel3 = new JPanel();
panel3.setLayout(new FlowLayout(FlowLayout.LEFT));
panel3.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
panel3.setPreferredSize(new Dimension(70,35));
JTextArea area1 = new JTextArea("hello " + i);
area1.setPreferredSize(new Dimension(70,25));
panel1.add(area1);
JTextArea area2 = new JTextArea("hello " + i);
area2.setPreferredSize(new Dimension(70,25));
panel2.add(area2);
JTextArea area3 = new JTextArea("hello " + i);
area3.setPreferredSize(new Dimension(70,25));
panel3.add(area3);
JPanel row = new JPanel();
row.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.black));
row.setLayout(new BoxLayout(row, BoxLayout.X_AXIS));
row.add(panel1);
row.add(panel2);
row.add(panel3);
JButton button = new JButton("Click me");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
buttonPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
buttonPanel.setPreferredSize(new Dimension(70,35));
buttonPanel.add(button);
button.addActionListener(event -> {
panel1.setPreferredSize(new Dimension(panel1.getWidth(), panel1.getHeight() + 30));
area1.setPreferredSize(new Dimension(area1.getWidth(), area1.getHeight() + 30));
area1.updateUI();
});
row.add(buttonPanel);
mainPanel.add(row);
}
}
}
如果您 运行 此代码并按下按钮,它不仅会更新行高,还会更新行宽,并且网格不再对齐。
您正在根据组件的 "size" 设置 "preferred size"。两者可以不同。
你的代码应该是这样的:
//panel1.setPreferredSize(new Dimension(panel1.getWidth(), panel1.getHeight() + 30));
Dimension d = panel1.getPreferredSize();
panel1.setPreferredSize(new Dimension(d.width, d.height + 30));
此外,您不应该使用 updateUI()
。这是 Swing 在 LAF 更改时内部使用的一种方法。
相反,当您想要调用布局管理器时,您可以在已更改的顶级组件上调用 revalidate():
//area1.updateUI();
panel1.revalidate();