我知道这可能看起来像是重复的,但我没有通过试验invalidate / validate / revalidate / repaint来获得任何地方,所以请耐心等待。我的面板结构看起来像这样:
JPanel/GridBagLayout (1)
+-- JPanel/BorderLayout
+-- JPanel/GridBagLayout (2)
| +-- JTextField (3)
| +-- JComboBox
+-- JPanel/WhateverLayout
...
......等等。在我的子面板(2)
中,我更改了插图(右侧和底部),我想布局整个顶部面板(1)
。是否有一些简单的方法来布局所有内容(最好从顶部面板(1)
向下,但任何有效的东西都是okey)。现在我已尝试在所有级别上使用invalidate / validate / revalidate / repaint的组合,但似乎没有任何工作(事实上根本没有任何变化)。谢谢!
修改:我发现GridBagLayout
克隆了GridBagConstraints
,因为组件已添加,因此我的代码无法运行revalidate和朋友的原因是我更新了错误的约束。我在下面找到并添加了解决这个问题的方法。
答案 0 :(得分:2)
re_layout整个JFrame
(JDialog
e.i。)是JFrame#pack()
表示容器中的填充可用区域(在remove
/ add
之后)revalidate()
和repaint()
您必须决定Components hierarchy
关于pack()
&的代码示例(re)validate()
& repaint()
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class AddComponentsAtRuntime {
private JFrame f;
private JPanel panel;
private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;
public AddComponentsAtRuntime() {
JButton b = new JButton();
b.setBackground(Color.red);
b.setBorder(new LineBorder(Color.black, 2));
b.setPreferredSize(new Dimension(600, 10));
panel = new JPanel(new GridLayout(0, 1));
panel.add(b);
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel, "Center");
f.add(getCheckBoxPanel(), "South");
f.setLocation(200, 200);
f.pack();
f.setVisible(true);
}
private JPanel getCheckBoxPanel() {
checkValidate = new JCheckBox("validate");
checkValidate.setSelected(false);
checkReValidate = new JCheckBox("revalidate");
checkReValidate.setSelected(false);
checkRepaint = new JCheckBox("repaint");
checkRepaint.setSelected(false);
checkPack = new JCheckBox("pack");
checkPack.setSelected(false);
JButton addComp = new JButton("Add New One");
addComp.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JButton b = new JButton();
b.setBackground(Color.red);
b.setBorder(new LineBorder(Color.black, 2));
b.setPreferredSize(new Dimension(600, 10));
panel.add(b);
makeChange();
System.out.println(" Components Count after Adds :" + panel.getComponentCount());
}
});
JButton removeComp = new JButton("Remove One");
removeComp.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int count = panel.getComponentCount();
if (count > 0) {
panel.remove(0);
}
makeChange();
System.out.println(" Components Count after Removes :" + panel.getComponentCount());
}
});
JPanel panel2 = new JPanel();
panel2.add(checkValidate);
panel2.add(checkReValidate);
panel2.add(checkRepaint);
panel2.add(checkPack);
panel2.add(addComp);
panel2.add(removeComp);
return panel2;
}
private void makeChange() {
if (checkValidate.isSelected()) {
panel.validate();
}
if (checkReValidate.isSelected()) {
panel.revalidate();
}
if (checkRepaint.isSelected()) {
panel.repaint();
}
if (checkPack.isSelected()) {
f.pack();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
}
});
}
}
答案 1 :(得分:2)
GridBagLayout
在添加组件时克隆GridBagConstraints
(这就是为什么更改原始版本对布局没有影响的原因),因此我扩展GridBagLayout
以便能够更新实际约束运行。下面的代码根据组件的类型设置布局边距,如果“扩展”,我用它在两种模式之间切换:
public class ExpandableGridBagLayout extends GridBagLayout {
public void setExpand(boolean expanded) {
for (Map.Entry<Component, GridBagConstraints> entry : comptable.entrySet()) {
setExpandedMargin(entry.getKey(), entry.getValue(), expanded);
}
}
private void setExpandedMargin(Component component, GridBagConstraints constraints, boolean expanded) {
constraints.insets.right = 2;
if (component instanceof JLabel) {
constraints.insets.top = expanded ? 3 : 0;
constraints.insets.bottom = expanded ? 3 : 0;
} else {
constraints.insets.bottom = expanded ? 8 : 5;
}
}
}
然后,我所要做的就是在panel.revalidate()
上调用(1)
,布局按预期工作。
答案 2 :(得分:2)
仍然不完全确定您的确切背景,但从您的“答案”判断,您似乎正在改变组件约束。要触发受影响部件的重新布局,您需要
段:
ExpandableGridBagLayout bag = panel2.getLayout();
bag.setExpand(true);
for(Component child: panel2.getComponents())
child.invalidate();
panel1.validate();
没有公共api以递归方式使给定容器下面的所有内容无效(invalidateTree是包私有)。快速入侵是暂时切换父容器的字体(内部消息invalidateTree)
/**
* Invalidates the component hierarchy below the given container.<p>
*
* This implementation hacks around package private scope of invalidateTree by
* exploiting the implementation detail that the method is internally
* used by setFont, so we temporary change the font of the given container to trigger
* its internal call.<p>
*
* @param parent
*/
protected void invalidateTree(Container parent) {
Font font = parent.getFont();
parent.setFont(null);
parent.setFont(font);
}
修改强>
不知道这个答案的哪一部分你的意思是不正确 - 显然我没有任何详细的知识就无法解决你的问题;-)
好奇的我想知道层次结构中的重新验证将如何导致有效的grand / children的重新布局:validate / Tree明显停在有效的组件上。以下是与
一起使用的代码段结果因f.i而异。在父
的LayoutManager上看起来像一个有效的孩子的重新布局可能(或没有)更高的重新布局的副作用 - 没有任何保证发生和难以预测。没什么我想依靠的; - )
final JComponent sister = new JPanel();
final Border subBorder = BorderFactory.createLineBorder(Color.RED);
sister.setBorder(subBorder);
sister.add(new JTextField(20));
sister.add(new JButton("dummy - do nothing"));
JComponent brother = new JPanel();
brother.setBorder(BorderFactory.createLineBorder(Color.GREEN));
brother.add(new JTextField(20));
// vary the parent's LayoutManager
final JComponent parent = Box.createVerticalBox();
// final JComponent parent = Box.createHorizontalBox();
// final JComponent parent = new JPanel();
parent.add(sister);
parent.add(brother);
// action to simulate a change of child constraints
Action action = new AbstractAction("change sub constraints") {
@Override
public void actionPerformed(ActionEvent e) {
FlowLayout layout = (FlowLayout) sister.getLayout();
layout.setHgap(layout.getHgap() * 2);
// layout.setVgap(layout.getVgap() * 2);
// sister.invalidate();
parent.revalidate();
}
};
brother.add(new JButton(action));
JFrame frame = new JFrame("play with validation");
frame.add(parent);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);