JPanel 在调整 Jframe 大小之前不会更新
Posted
技术标签:
【中文标题】JPanel 在调整 Jframe 大小之前不会更新【英文标题】:JPanel doesn't update until resize Jframe 【发布时间】:2012-06-19 15:40:24 【问题描述】:我将 JPanel 子类化以覆盖paintComponent(Graphics),我想在 jframe 中将图像绘制到 jpanel 上。
但是直到我更改 jframe 的大小后,我的图像才显示出来。 这是我的代码:
public class ImagePanel extends JPanel
public void setImage(BufferedImage bi)
image = bi;
revalidate();
@Override
public void paintComponent(Graphics g)
super.paintComponent(g);
if(image != null)
g.drawImage(image, 0, 0, this);
【问题讨论】:
【参考方案1】:验证您是否在添加组件并调用pack()
之后调用setVisible()
,如相关example 中所述。您可能还需要采用适当的layout。按照建议here 调用repaint()
可能会解决症状,但不能解决根本原因。
【讨论】:
【参考方案2】:如果你想“刷新”JPanel,那么你应该调用repaint(),它会调用你的paintComponent()。这应该可以解决您的问题:
public void setImage(BufferedImage bi)
image = bi;
EventQueue.invokeLater(new Runnable()
public void run()
repaint();
);
使用 EDT 更新和更改 GUI 是一种很好的做法。如果您有兴趣,这里有更多关于 EDT 的信息:
How does the event dispatch thread work?
repaint
不需要从 EDT 调用。如果要更改 GUI,例如将文本设置为 JLabel,则它应该位于 EDT 内部。以下是关于在 EDT 之外可以调用什么的更多信息(由 nIcE cOw 提供):
Safe to use Component.repaint() outside EDT?
【讨论】:
+1 表示有价值的输入。只是一个建议,不需要在 EDT 中调用repaint()
,因为从任何线程调用 repaint()
都是安全的,如 here 所述
"具有 UI 委托的 Swing 组件的子类......应该调用 super.paintComponent()
"—The Paint Methods。【参考方案3】:
查看the docs 中的JPanel.add()
,它继承自java.awt.Container
:
将指定的组件附加到此容器的末尾。这是 addImpl(java.awt.Component, java.lang.Object, int) 的便捷方法。 此方法更改与布局相关的信息,因此 使组件层次结构无效。如果容器已显示,则必须随后验证层次结构才能显示添加的组件。
已添加重点。
因此,如果您在容器显示之后对其进行修改,则必须调用validate()
以使其显示。仅仅调用repaint()
是不够的。您可能已经注意到调用setVisible(true)
也可以;这是因为it calls validate()
internally。
【讨论】:
我使用revalidate()
获得了更好的结果。 validate()
完成了这项工作,但它不会更改尺寸以适应添加的新组件。
@Chameleon 虽然现在有点晚了,但我认为这是因为你没有覆盖 getPreferredSize【参考方案4】:
我遇到了同样的问题并通过调用 setVisible(true); 修复了它我正在使用的 JFrame。
示例:如果您的 JFrame 在使用后没有更新:
jframe.setContentPane(new MyContentPane());
修复它:
jframe.setContentPane(new MyContentPane());
jframe.setVisible(true);
我知道即使您的 JFrame 已经可见,这样做听起来很愚蠢,但这是我迄今为止找到的解决此问题的唯一方法(上面提出的解决方案对我不起作用)。
这是一个完整的例子。运行它,然后取消注释“f.setVisible(true);” Panel1 和 Panel2 类中的说明,您会看到不同之处。不要忘记导入(Ctrl + Shift + O 用于自动导入)。
主类:
public class Main
private static JFrame f;
public static void main(String[] args)
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new Panel1(f));
f.pack();
f.setVisible(true);
Panel1 类:
public class Panel1 extends JPanel
private JFrame f;
public Panel1(JFrame frame)
f = frame;
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JButton b = new JButton("Panel 1");
b.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent e)
f.setContentPane(new Panel2(f));
// Uncomment the instruction below to fix GUI "update-on-resize-only" problem
//f.setVisible(true);
);
add(b);
Panel2 类:
public class Panel2 extends JPanel
private JFrame f;
public Panel2(JFrame frame)
f = frame;
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JButton b = new JButton("Panel 2");
b.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent e)
f.setContentPane(new Panel1(f));
// Uncomment the instruction below to fix GUI "update-on-resize-only" problem
//f.setVisible(true);
);
add(b);
希望对您有所帮助。
问候。
【讨论】:
完美!不知道为什么会这样,但这是解决我问题的唯一方法。在此之前,我是这样做的:Dimension size = frame.getSize();布尔最大化 = frame.getExtendedState() == JFrame.MAXIMIZED_BOTH; frame.setSize(new Dimension((int)size.getWidth()-1,(int)size.getHeight()-1)); if (最大化) frame.setExtendedState(JFrame.MAXIMIZED_BOTH);否则 frame.setSize(大小);您的答案要干净得多,而且不那么老套。谢谢! @dberm22 实际上,不需要乱搞(至少在这个例子中没有,没有检查原始图像可能不同大小的图像,也没有扩展尺寸状态,这也可能很棘手) : 设置 contentPane 是对框架容器层次结构的修改,因此需要对框架进行重新验证。【参考方案5】:我也有同样的问题,但我找到了解决方案。只需在顶部创建一个jframe
对象并在底部调用jframe
方法,如jf.pack()
、jf.setVisible()
、jf.setSize()
、jf.setDefaultCloseOpetion()
应该位于该框架中添加的所有 UI 的底部,您会发现它工作得很好。
【讨论】:
以上是关于JPanel 在调整 Jframe 大小之前不会更新的主要内容,如果未能解决你的问题,请参考以下文章