Java JPanel没有';在调整Jframe的大小之前,请不要更新

Java JPanel没有';在调整Jframe的大小之前,请不要更新,java,swing,user-interface,paintcomponent,Java,Swing,User Interface,Paintcomponent,我将JPanel子类化以覆盖paintComponent(图形),我希望在jframe中在JPanel上绘制一个图像 但直到我改变了jframe的尺寸,我的图像才显示出来。 这是我的代码: public class ImagePanel extends JPanel{ public void setImage(BufferedImage bi) { image = bi; revalidate(); } @Override

我将JPanel子类化以覆盖paintComponent(图形),我希望在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);
        }
    }
}
如果要“刷新”JPanel,则应调用repaint(),这将调用paintComponent()。这将解决您的问题:

public void setImage(BufferedImage bi)
{
    image = bi;
    EventQueue.invokeLater(new Runnable()
    {
        public void run()
        {
            repaint();
        }
    });
}
使用EDT更新和更改GUI是一种很好的做法。如果您感兴趣,这里有更多关于EDT的信息:

重新绘制
不需要从EDT调用。如果要更改GUI,例如将文本设置为JLabel,则它应该位于EDT内部。以下是EDT之外的更多信息(由nIcE cOw提供):


验证是否在添加组件和调用后调用了
setVisible()
,如本相关章节所述。您可能还需要采取适当的措施。按照建议调用
repaint()
,可能会修复症状,但不会修复根本原因。

我也有同样的问题,并通过调用setVisible(true)修复了它;我使用的JFrame

示例:如果您的JFrame在使用后未更新:

jframe.setContentPane(new MyContentPane());
用以下方法修复它:

jframe.setContentPane(new MyContentPane());
jframe.setVisible(true);
我知道这样做听起来很傻,即使你的JFrame已经是可见的,但这是迄今为止我找到的唯一解决这个问题的方法(上面提出的解决方案对我不起作用)

这是一个完整的例子。运行它,然后取消注释类Panel1和Panel2中的“f.setVisible(true);”指令,您将看到它们的区别。不要忘记导入(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);
    }
}
第1组类别:

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);
    }
}
第2组类别:

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);
    }
}
希望有帮助

问候。

看看它从
java.awt.Container
继承的
JPanel.add()

将指定的组件追加到此容器的末尾。这是addImpl(java.awt.Component、java.lang.Object、int)的一种方便方法。 此方法会更改布局相关信息,因此,会使组件层次结构无效。如果容器已经显示,则此后必须验证层次结构,以便显示添加的组件。

重点补充


因此,如果在容器已经显示之后修改它,则必须调用
validate()
,才能显示它。仅仅调用
repaint()
是不够的。您可能已经注意到调用
setVisible(true)
也可以工作;这是因为。

我也有同样的问题,但我找到了解决办法。只需在顶部创建一个
jframe
对象,并在底部调用
jframe
方法,比如
jf.pack()
jf.setVisible()
jf.setDefaultCloseOpetion()
应该位于该框架中添加的所有UI的底部,您会发现它工作得很好

有价值的输入+1。只是一个建议,不需要在EDT中调用
repaint()
,因为从任何线程调用
repaint()
都是安全的,正如“具有UI委托的Swing组件的子类…应该调用
super.paintComponent()
”——所述。太棒了!不知道为什么会这样,但这是唯一解决我问题的办法。在此之前,我做过这样的工作:Dimension size=frame.getSize();布尔最大化=frame.getExtendedState()==JFrame.maximized\u两者;frame.setSize(新维度((int)size.getWidth()-1,(int)size.getHeight()-1));if(最大化)frame.setExtendedState(JFrame.maximized_两者);else frame.setSize(大小);你的答案是非常,非常干净和方式少黑客。谢谢@dberm22实际上,不需要进行黑客攻击(至少在本例中没有,没有使用可能不同大小的图像检查原始图像,也没有使用可能很棘手的扩展大小状态):设置contentPane是对框架容器层次结构的修改,因此需要对框架进行重新验证。使用
revalidate()
可以获得更好的结果
validate()
执行此操作,但不会更改尺寸以适应添加的新组件。