【问题标题】:Container doesn't resize itself after invoking validate调用 validate 后容器不会自行调整大小
【发布时间】:2012-01-05 14:10:46
【问题描述】:

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

validate 方法用于使容器布局其 再次。当这个容器的 子组件被修改(添加到容器中或从容器中删除,或 布局相关信息更改)后容器已 显示出来。

重新布置其子组件”这句话让我觉得容器会相应地调整自己的大小,但事实并非如此。相反,在调用validate() 之后,我还需要调用pack() 以查看其所有子组件。

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

【问题讨论】:

  • 在使用 Swing 时,我使用 revalidate()。同样,它不会调整框架的大小,但会调整容器的大小,这可能会导致布局发生变化。例如,如果容器位于滚动窗格中,那么您可能会看到添加或删除了滚动条。
  • @camickr - 可能误解了你在说什么,但是对容器进行重新/验证永远不会调整该容器的大小,只会调整其子容器的大小
  • @kleopatra,再看我的评论,我想我不应该使用“容器”这个词。我使用术语“容器”来表示“jpanel”,并试图强调它只会影响“容器”内组件的布局。它不会调整顶级容器(JFrame、JDialog、JWindow)的大小。
  • @camickr 好点!我错过了验证根 :-) 实际上,我认为您的意思是 container 您在编辑后的评论中解释的方式 :-)

标签: java swing resize containers


【解决方案1】:

我认为您自己回答了您的问题,希望对您的演示有所帮助

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();
    }
}

【讨论】:

  • 很好的演示,可能会很方便!
【解决方案2】:

(可能是由于这种歧义,latest javaDoc 中的描述已更改)

JavaDoc 7 不是在说,

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

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

请注意,pack() 明确表示,

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

【讨论】:

    【解决方案3】:

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

    布局是:

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

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

    你可能会尝试的一些事情:

    • 确保您在组件/容器上设置了最大尺寸,这将在重新布局时强制限制组件的尺寸
    • 习惯性地打电话给pack()
    • 尝试一些关于common layout issues的建议

    Swing 很棘手,因为您必须了解绘画管道、布局管理器以及窗口系统的一些细节。当涉及到 Swing 文档(以及所有方法和做任何一件事的几种不同方法)时,我尝试用“什么都不做”的方法来阅读文档,意思是,“这种方法的最小可能是什么?文档暗示它可能会这样做,”除非您观察到其他行为,否则不要被欺骗认为它的作用不止于此。

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

    这意味着,如果 LayoutManager 不认为它需要调整某个东西的大小以使其适合其整体策略,那么基本上它不会调整它的大小。另一方面,对pack 的调用是一个明确的请求,将所有东西打包在一起并移除额外的空间。

    【讨论】:

    • 此描述中微妙的错误假设(据我了解,编辑以澄清我的理解是否错误)是 LayoutManager 正在调整 container 的大小管理。它从不这样做,而是完全专注于容器的 children。在顶级容器中,唯一可以进行任何大小调整的方法是 pack 和 setSize - 如果适当,应用程序代码必须调用其中之一。
    猜你喜欢
    • 1970-01-01
    • 2020-04-10
    • 2013-07-10
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多