【问题标题】:jPanel is not refreshing until I resize the app window在我调整应用程序窗口大小之前,jPanel 不会刷新
【发布时间】:2012-05-10 13:29:43
【问题描述】:

我的 jPanel 有一个问题。 我有一个按钮,它来自字符串输入(数学公式)的 PNG 图像,然后它将在 jPanel 中重新绘制旧图像。问题就出现了。图像已更改,但在我手动调整应用程序窗口大小之前,jPanel 不会重新绘制。

看起来面板在调整大小之前不会重新绘制。但我不知道如何在那个按钮中做到这一点。

我尝试了thisthis,但没有任何变化。

顺便说一句。我在 netbeans 中使用 GUI Builder。

我的代码...第一次尝试:

public class ImagePanel extends JPanel {

   private String path;
   Image img;
   public ImagePanel() {
        try {
            //save path
            path = "Example5.png";
            //load image
            img = ImageIO.read(new File(path));
        } catch (IOException ex) {
        }
    }
   @Override
   public void paint(Graphics g) {
      //draw the image
      if (show) {
        try {
            if (img != null) {
                img = ImageIO.read(new File(path));
                g.drawImage(img, 0, 0, this);
            }
        } catch (IOException ex) {
        }
     } else {
        show = true;
     }
   }
}

在Window类/按钮方法中:

   imagePanel = new ImagePanel();
   imagePanel.repaint();
   imagePanel.updateUI();

第二次尝试:

public class ImagePanel extends JPanel {

   private String path;
   Image img;
   ImagePanel(Image img) {
        this.img = img;
   }

   public void setImg(Image img) {
       this.img = img;
   }

   @Override
   public void paintComponent(Graphics g) {
       super.paintComponent(g);

       // Draw image centered in the middle of the panel
       g.drawImage(img, 0, 0, this);
   }

}

和按钮:

imagePanel.setImg(new ImageIcon("2.png").getImage());
imagePanel.repaint();

【问题讨论】:

  • 开窗时面板会被涂漆吗?还是完全看不见?请注意,如果布局管理器尚未计算其边界,则面板的大小可能为 0/0。
  • 添加图片时能否检查jPanel是否失效?调整大小会导致调用 validateTree,因此布局管理器会验证其子级
  • 调用 revalidate();在重绘()之前;?

标签: java image swing jpanel paintcomponent


【解决方案1】:

您正在覆盖您的paint(...) 方法,这在任何方面都不是一个好策略,因为在Swing 中尽可能尝试覆盖您的paintComponent(...) 方法。此外,我猜您可能错过了将代码放入 SwingUtilities.invokeLater(...) 方法中。尝试使用您的更新后的代码,将图像放在您的 .class 文件旁边(在图像文件夹内),这样结构就可以了,

PanelTest.class      ImagePanel.class        image(Folder)
                                             |     |     |
                                         image1 image2  image3(and so on)

================================================ ====================================

import java.awt.*;
import java.awt.event.*;
import java.net.URL;
import javax.swing.*;

public class PanelTest
{
    private URL[] url = new URL[5]; 
    private int counter = 0;
    private ImageIcon image;
    private JButton updateButton;

    public PanelTest()
    {
        try
        {
            for (int i = 0; i < 5; i++)
            {
                url[i] = getClass().getResource("/image/geek" + i + ".gif");
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    private void createAndDisplayGUI()
    {
        JFrame frame = new JFrame("Panel Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        image = new ImageIcon(url[0]);
        final ImagePanel ip = new ImagePanel(image.getImage());
        updateButton = new JButton("UPDATE");
        updateButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                counter++;
                if (counter < 5)
                {
                    image = new ImageIcon(url[counter]);
                    ip.setImg(image.getImage());
                }
                else
                    counter = -1;
            }
        });

        frame.getContentPane().add(ip, BorderLayout.CENTER);
        frame.getContentPane().add(updateButton, BorderLayout.PAGE_END);

        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new PanelTest().createAndDisplayGUI();
            }
        });
    }
}
class ImagePanel extends JPanel {

   private String path;
   private Image img;
   ImagePanel(Image img) {
        this.img = img;
   }

   public void setImg(Image img) {
       this.img = img;
       // Added by me, so as to update the image
       // as a new Image is made available.
       repaint();
   }

   /*
    * Added by me, make this a customary
    * habbit to override this method too
    * as you override paintComponent(...)
    * method of the said JComponent.
    */
   @Override
   public Dimension getPreferredSize()
   {
       return (new Dimension(300, 300));    
   }

   @Override
   public void paintComponent(Graphics g) {
       super.paintComponent(g);

       // Clears the previously drawn image.     
       g.clearRect(0, 0, getWidth(), getHeight());  
       // Draw image centered in the middle of the panel
       g.drawImage(img, 0, 0, this);
   }

}

如果你也想要图片,这里有

GEEK0 GEEK1 GEEK2 GEEK3 GEEK4

【讨论】:

    【解决方案2】:

    您可以使用背景重绘线程来解决这个问题。你可以把它放在你的 JPanel 子类的构造函数中。

    Thread repainter = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true) { // I recommend setting a condition for your panel being open/visible
                repaint();
                try {
                    Thread.sleep(30);
                } catch (InterruptedException ignored) {
                }
            }
        }
    });
    repainter.setName("Panel repaint");
    repainter.setPriority(Thread.MIN_PRIORITY);
    repainter.start();
    

    【讨论】:

    • 这几乎可以完美运行。图像将重绘,但在调整窗口大小之前,旧​​图像仍然存在于背景中。
    • 正如nice cOw 所发布的,您不应覆盖面板的paint 方法。您应该将组件绘制代码从 paint 移动到 paintComponent
    • 它还活着!太好了,非常感谢你们。我在 jdoc 中读到最好覆盖 paintComponent(),但我不认为这有什么大不了的。
    猜你喜欢
    • 2017-12-11
    • 2012-06-19
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 2011-09-18
    • 1970-01-01
    相关资源
    最近更新 更多