【问题标题】:repaint not being called重绘没有被调用
【发布时间】:2012-10-02 14:22:58
【问题描述】:

您好,我用 google 搜索过,不知道为什么我的 paintComp 方法没有被调用

我有以下代码 包 com.vf.zepto.view;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import com.vf.zepto.view.interfaces.ProcessorPanel;

public class CountryDetailsPanel extends JPanel implements ProcessorPanel, Runnable {
    private GridBagConstraints c = new GridBagConstraints();
    private String countryName;
    private Properties prop = new Properties();
    private BufferedImage image;

    public CountryDetailsPanel() {
        try {
            prop.load(new FileInputStream("country.props"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //this.setLayout(new GridBagLayout());

        c.gridx = 0;
        c.gridy = 0;
        c.fill = GridBagConstraints.BOTH;
        c.insets = new Insets(5, 5, 5, 5);

        this.setPreferredSize(new Dimension(200, 200));
    }

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

        try {
            if(countryName != null) {
                String asset = prop.getProperty(countryName+".flag");

                if(!asset.equals(null)) {
                    image = ImageIO.read(new File(asset));
                    g.drawImage(image, 0, 0, null);
                }
            }
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void updateDetails(Object o) {
        countryName = (String)o;
        SwingUtilities.invokeLater(this);
    }

    @Override
    public void run() {
        this.repaint();
    }
}

当调用 this.repaint() 时,期望调用 paintComponent 方法,但不是为了爱和金钱。

已尝试强制它使用 EDT,以防出现问题但不是。

有什么想法吗?

【问题讨论】:

标签: java swing repaint paintcomponent event-dispatch-thread


【解决方案1】:
  • 您永远不应该调用paintComponent() repaint() 方法合并所有更改组件的请求(在屏幕刷新之间可能有多个重绘请求)。它将更新请求添加到 GUI 事件队列,以便更新与其他 GUI 操作正确协调(Swing 和 AWT 不是线程安全的)。此更新请求在处理后会调用update(),它会调用paint(),它会调用您的paintComponent()

  • 为什么会有这个:

    @Override
    public void run() {
        this.repaint();
       }
    

它似乎没有任何用处(创建一个新线程来重绘一次?更不用说线程不在 EDT 上,而是在 JPanel 实例上调用 repaint() (如果在外部进行了修改,你甚至不应该担心). 但是要启动修改 UI 组件使用的线程 SwingTimer/SwingWorkerSwingUtilities#invokeXXX()

  • 这可能不相关,但在您的代码中我看到了:

            if(!asset.equals(null)) {
                image = ImageIO.read(new File(asset));
                g.drawImage(image, 0, 0, null);
            }
    

不要使用equals()null 值进行比较,因为这可能会抛出NullPointerException,因为您正在尝试 尊重一个空指针,例如这段代码抛出一个NPE

    String s=null;
    if(!s.equals(null)) {//throws NPE
        System.out.println("Here");//is never printed
    }
  • 也正如 mKorbel 所说(对他 +1)不要在 paintComponent() 中执行长时间运行的任务,全局声明您的 Image,在构造函数中分配它,然后在 paintComponent() 中使用它。 F.i

宁可这样做:

public class TestPanel extends JPanel {

private Image image;

public TestPanel() {
image = ImageIO.read(new File(asset));
}

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
                if(asset!=null) {
                    g.drawImage(image, 0, 0, null);
                }
    }
}

【讨论】:

  • +1 以获得精彩的信息集,虽然从 paintComponent() 中调用 repaint() 并不是一个好主意,因为在执行与绘画相关的事情时,它进入了 paintComponent() 方法并且在这里,我们再次将 Swing 派回无缘无故地重新绘制整个事物。油漆是一项艰巨的任务。来自 Filthy Rich Client 的一句话可以证明这一点
  • 请务必注意,重绘请求会“合并”或合并。因此,例如,如果您请求重绘并且队列中已经有一个尚未被服务,那么第二个请求将被忽略,因为您的重绘请求已经被之前的请求完成了。这种行为在生成许多重绘请求的情况下特别有用,可能是由非常不同的情况和组件生成的,Swing 应该避免处理多余的请求和浪费精力。
  • @gagandeepbali +1 谢谢你,感谢你提供关于重绘的新事实。保持微笑:)
  • 你很受欢迎,保持微笑:-)
  • 哇,这让我直截了当!为信息欢呼!我意识到 null 的问题并在阅读本文之前对其进行了更改。
【解决方案2】:
  1. 不要paintComponent中加载图像或其他硬或长时间运行的代码

  2. 将此Object 加载为局部变量且仅加载一次

  3. paintComponent() 被调用

    • 隐式地,当JComponent 需要重绘时,或

    • 明确地,例如在每个鼠标事件上,如果要从 MouseMotionListener 调用 paintComponent()

  4. 如果有动画,则使用Swing Timer并调用repaint()

【讨论】:

  • @mKorbel : 请解释一下 e.i. 的含义。如第 3 点 :-) 不是 i.e. 代表 that is 吗?
  • 猜测:exempli gratiafor instance 的混合体?
  • @Gagandeep Bali 把 System.out.println() 放在那里,疯狂的事件从任何地方被触发,phaaaa 或者我在你的评论中错过了什么:-),
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多