gpt4 book ai didi

java - 计算 JDialog 组件的大小,在使可见之前设置总大小

转载 作者:行者123 更新时间:2023-11-30 06:27:54 24 4
gpt4 key购买 nike

我有一个 JDialog,我希望它具有一定的给定大小:

JDialog dialog = new JDialog();
dialog.setSize(800, 600);
dialog.setResizable(false);

然后我添加一个组件:

JLabel label = new JLabel("Test");
dialog.add(label);

现在我可以使对话框可见并检查组件的大小

dialog.setVisible(true);
System.out.println(label.getSize());

答案是“[width=784,height=562]”。显然,组件的大小已调整为填充对话窗口的整个客户区/内容 Pane 。很好,正如我所愿。

问题:如何在调用 setVisible(true) 之前获取组件的最终大小?

  • getPreferredSize() 不会是我想要的大小,因为我希望组件适应给定对话框的大小
  • dialog.pack() 也不是正确的,因为它将对话框的大小调整为我不想要的组件的首选大小
  • dialog.validate() 在这里没有任何用处,组件的大小仍然是 0
  • dialog.getLayout().layoutContainer(dialog) 也不设置组件的大小

所以我在这里不知所措。我想让布局管理器在显示对话框之前计算所有组件和子组件的正确大小,以适应对话框的整体大小。但我不知道怎么办。

最佳答案

我现在发现可以这样做:

JDialog dialog = new JDialog();
JLabel label = new JLabel("Test");
dialog.add(label);

// pack(), setSize(), validate() in this order will
// set sizes on all components as wished
dialog.pack();
dialog.setSize(800, 600);
dialog.validate();

System.out.println(label.getSize());

这里的输出也是“[width=784,height=562]”,但是对话框还不可见。重要的部分是按顺序组合 pack()、setSize(desiredSize) 和 validate()。 pack() 可能确定对话框的新大小(所有组件的首选大小),这就是为什么必须在此处设置大小并且 validate() 负责调整组件大小的原因。到达相同大小的 setVisible(true) 可能在内部做类似的事情。

多次调整组件的大小似乎有点浪费,但如果没有 pack(),setSize() 和 validate() 也没有任何效果。

我猜其他答案是基于一些误解,因为他们总是隐含地假设您想要拥有首选尺寸,但也有一些情况,例如如果用户调整对话框的大小,或者如果对话框的大小从一开始就固定,您无法获得首选大小,并且某些组件只需要填充可用空间。

这就是这里的布局问题,具有给定的对话框全局大小并确定组件填充可用空间时的大小。 LayoutManagers 很好地解决了这个问题,但通常只在 setVisible(true) 之后。

我测试了一下:

    // new dialog
JDialog dialog = new JDialog();

// new label, prints messages if resized or painted
JLabel label = new JLabel("Test") {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("Component painted.");
}
};
label.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
System.out.println("Resized: " + e.getComponent().getSize());
}
});
dialog.add(label);
System.out.println("Size after new JLabel: " + label.getSize());

// pack dialog - necessary for setSize/validate to work
dialog.pack();
System.out.println("Size after pack: " + label.getSize());

// set a size and validate changes sizes
dialog.setSize(800, 600);
dialog.validate();
System.out.println("Size after setSize and validate: " + label.getSize());

// set visible would have also done the trick
dialog.setVisible(true);
System.out.println("Size after setVisible(true): " + label.getSize());

// and another resizing (no validation neccessary)
dialog.setSize(300, 200);

// dispose
dialog.dispose();

输出是

  • 新 JLabel 后的尺寸:java.awt.Dimension[width=0,height=0]
  • 打包后尺寸:java.awt.Dimension[width=116,height=16]
  • setSize 和验证后的大小:java.awt.Dimension[width=784,height=562]
  • setVisible(true) 后的尺寸:java.awt.Dimension[width=784,height=562]
  • 调整大小:java.awt.Dimension[width=284,height=162]
  • 调整大小:java.awt.Dimension[width=284,height=162]
  • 绘制的组件。

我了解了有关 Swing 内部工作原理的更多信息:

  • ComponentResized 事件不会在 setVisible(true) 之前被触发,即使组件被调整大小(它们的大小改变)
  • 即使大小相同的 ComponentResized 事件也可以连续触发多次
  • 如果组件相互跟随的速度足够快,它们可能不会在调整大小之间绘制
  • 在任何情况下,第一次绘制都是在 setVisible(true) 之后进行的,届时组件将具有所需的大小(首选大小或由此处的其他约束定义)。
  • 如果出于某种原因您必须在第一次绘制之前知道组件的大小,请使用 pack()、setSize()、validate() 来完成

我进行了更多测试,同样使用最大化帧,现在可以将所有结果组合成:第一个 painComponent() 始终具有正确的大小,相关的 componentResized() 事件始终紧随其后,有时两次。但是 LayoutManager之前一定要知道,不然例子画不对。因此,如果有人自己绘制背景,要么在每个 paintComponent 中读出正确的大小,要么实现自定义布局管理器,要么等待调整大小的事件并调用重绘,这样组件就会被绘制两次,但它应该可以工作。应用程序包括要显示的组件数量取决于大小的情况(如在我的地理 map 应用程序中)。


如果用户最大化或调整框架/对话框的大小,我认为流程是这样的:

  • frame/dialog.setSize()
  • LayoutManager.layoutContainer(frame/dialog) 使用实际大小
  • 使用布局尺寸的框架/对话框 paint()
  • 为所有组件等触发 Resized() 事件。

pack() 可能只是调用 setSize(layout.preferredLayoutSize()) 作为第一步。

因此,例如,如果您必须根据大小添加或删除组件,那么覆盖 setSize() 并在那里监听更改可能是个好主意。我最初是在监听 Resized() 事件,但它们对于第一张图来说来得太晚了。

关于java - 计算 JDialog 组件的大小,在使可见之前设置总大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13046508/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com