调用validate后,Container不会自行调整大小

时间:2012-01-05 14:10:46

标签: java swing resize containers

通过addremove手动交换组件后,我在容器上调用validate()。根据文件,

  

validate方法用于使容器布局它   子组件再次。它应该在这个容器的时候调用   子组件被修改(添加到容器或从容器中删除,或   在容器出现之后,布局相关信息已经改变   显示。

短语“再次布置其子组件”让我觉得容器会相应调整大小,但事实并非如此。相反,在调用validate()之后,我还需要调用pack()以查看其所有子组件。

这是为什么?我做错了吗?

3 个答案:

答案 0 :(得分:7)

我认为你自己回答了你的问题,希望能帮到你这个演示

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
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) {
        AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
    }
}

答案 1 :(得分:6)

(可能由于这种歧义,描述在latest javaDoc

中发生了变化

JavaDoc 7 说,

  

验证方法用于使容器再次布置其子组件 ..

所以它只放置组件,而你需要再次pack()

请注意pack()清楚地说,

  

使此窗口的大小适合其子组件的首选大小和布局。

答案 2 :(得分:2)

这里有一个基本而微妙的假设:布局和大小直接相关,1对1 情况并非如此,是Swing编程中的常见假设。大小是布局和大小限制的结果。

布局是:

  • 在您指定的空间限制内
  • 考虑到我必须适应那个空间的组件
  • 根据指定的策略(BoxLayout,BorderLayout等)将这些组件相互关联放置

如果LayoutManager可以适合您给出的组件,而不更改容器的整体大小,不会改变容器的大小。另一方面,对pack的调用是对最小化使用空间的明确请求。这就是你看到结果的基本原因。

你可能会尝试一些事情:

  • 确保在组件/容器上设置最大尺寸,这会在重新布局时强制对组件进行尺寸限制
  • 始终将pack()称为习惯
  • 尝试一些有关common layout issues
  • 的建议

使用Swing很棘手,因为你必须了解绘画管道,布局管理器以及窗口系统的一些细节。当谈到Swing文档(以及所有方法和几种不同的方式来做任何事情)时,我尝试用“假设无”的方法阅读文档,意思是“这个方法的最小可能性是什么?文档意味着它可能会这样做,“除非你观察到其他行为,否则不要误以为它会做更多的事情。

最后,我要补充一点,LayoutManagers的工作一般不是容器的大小调整,而是根据布局策略将组件放在彼此的某种关系中(这是在additional detail here中讨论过。我们的想法是,使用正确的LayoutManager,您可以指定基本布局策略,因此当您调整窗口大小时,LayoutManager将智能地移动组件,以便您的UI继续遵循整体战略。通过这种方式,布局基本上意味着独立于它们工作空间的总体大小,因此它们尽量不假设可用空间 - 而是采用它们给出的大小并尝试做有意义的事情。除非您明确对组件设置大小限制,否则无法保证它们的大小。

这意味着,如果LayoutManager不相信它需要调整大小以使其适合其整体策略,基本上它将不会调整大小。另一方面,对pack的调用是将事物打包在一起并删除额外空间的明确请求。