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 大小之前不会更新的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 JFrame 中 JPanel 的大小?

JAVA:如何调整JPanel的大小

如何将两个 JPanel 添加到中心的 JFrame?

swing:关于调整 JFrame 大小和条件滚动

使用JPanel绘图使JScrollPanel动态调整大小

在 GroupLayout 中设置 JPanel 的大小