【问题标题】:Method slows execution paintComponent()方法减慢执行paintComponent()
【发布时间】:2014-09-17 16:12:41
【问题描述】:

我有一个小问题。在动画期间执行paintComponent() 方法时,我必须不断更新变量bgImage。但这需要很多时间,以至于动画变慢了。

有问题的代码块:

public class ProblemClass extends JComponent {
    private static final int FRAME_FREQUENCY = 30;
    private final Timer animationTimer;

    public ProblemClass() {
        this.animationTimer = new Timer(1000 / FRAME_FREQUENCY, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                repaint(); // When the animation started is often invoked repaint()
            }
        });
    }

    // Other code...

    /** 
     * Start animation from another class
     */
    public void startAnimation() {
        this.animationTimer.start();
    }

    @Override 
    protected void paintComponent(Graphics g) { 
        // GraphicsUtils.gaussianBlur(...) it's a long-time operation
        BufferedImage bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage()); 
        g2.drawImage(bgImage, 0, 0, null); 

        // Other code...
    }
}

我在互联网上读到我需要在并行线程 (SwingWorker) 中运行长任务,但我不知道如何在我的情况下执行此操作。我该如何解决这个问题?

P.S.对不起,我的英语不好,这不是我的母语。

【问题讨论】:

  • the documentation 开头。它应该非常简单——只要有一个SwingWorker<BufferedImage, Void>。致电AnotherClass.getBgImage() 并将结果传递给您的SwingWorker。在done() 方法中调用get 并将图像绘制到屏幕上。确保Swing 组件和SwingWorker 之间没有交互,因为这会破坏事情。
  • AnotherClass.getBgImage() 的结果会在调用之间改变吗?
  • 一个完整的例子显示在here
  • 顺便说一句:g2.drawImage(bgImage, 0, 0, null); 应该是g2.drawImage(bgImage, 0, 0, this);,因为每个JComponent 都是ImageObserver..

标签: java multithreading swing animation swingworker


【解决方案1】:

您要做的最好的事情是在绘制方法之外更新图像,并且仅在准备好新图像时重绘。获取您现有的代码,并添加对图像的持久引用,该引用被绘制到 JComponent 每个绘制方法上。然后让您的动画计时器进行高斯模糊并更新您的图像。

public class ProblemClass extends JComponent {
    private static final int FRAME_FREQUENCY = 30;
    private final Timer animationTimer;

    //persistent reference to the image
    private BufferedImage bgImage;

    public ProblemClass() {
        this.animationTimer = new Timer(1000 / FRAME_FREQUENCY, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //Update the image on each call before repainting
                bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage());
                repaint();
            }
        });
    }

    /** 
     * Start animation from another class
     */
    public void startAnimation() {
        this.animationTimer.start();
    }

    @Override
    protected void paintComponent(Graphics g2) {
        g2.drawImage(bgImage, 0, 0, null);

        // Other code...
    }
}

【讨论】:

  • 感谢您提出这个想法!我在Timer 内部遇到了一个逻辑方法调用,效果很好。但是,我必须优化方法gaussianBlur(),但它是所有细节。问题解决了,客户很满意:)
【解决方案2】:

当您每次生成新的背景图像然后对其进行模糊处理时,没有通用的方法可以解决此问题。 GaussianBlur 是一个缓慢的操作,句号。

IfAnotherClass.getBgImage() 从预定义的图像集 传递图像,然后将模糊一次 应用到集中的每个图像,问题就解决了。

如果您在 AnotherClass.getBgImage() 中动态创建图像,那么您也许可以通过更改图像创建以从开始。根据创建图像所做的工作,这可能可行,也可能不可行。

如果以上都不能解决,您需要研究其他选项来生成更快的模糊图像;有一些更简单的模糊方法通常更快,但看起来有点类似于高斯。

您看到这一切都归结为在性能关键路径上重复调用 GaussianBlur。

【讨论】:

  • 感谢您的想法!
【解决方案3】:

你应该从画家那里提取逻辑。 Painters 被不断调用,执行速度应该非常快。

  BufferedImage bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage()); 

这行必须每次都执行?也许您可以使用一个字段来存储图像,而画家可以只绘制图像,而不是每次都应用 gaussianBlur。

试试这个: 公共类 ProblemClass 扩展 JComponent {

    private static final int FRAME_FREQUENCY = 30;
    private final Timer animationTimer;
    private final BufferedImage bgImage;

    public ProblemClass() {
        bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage());
        this.animationTimer = new Timer(1000 / FRAME_FREQUENCY, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                repaint(); // When the animation started is often invoked repaint()
            }
        });
    }

        // Other code...
    /** 
     * Start animation from another class
     */
    public void startAnimation() {
        this.animationTimer.start();
    }

    @Override
    protected void paintComponent(Graphics g2) {
        // GraphicsUtils.gaussianBlur(...) it's a long-time operation
        g2.drawImage(bgImage, 0, 0, null);

        // Other code...
    }
}

【讨论】:

  • 是的,我试过去掉这行,效果很快,但是没有想要的效果。看看program,你就会明白为什么需要这条线。 VirusTotal
猜你喜欢
  • 1970-01-01
  • 2015-06-08
  • 1970-01-01
  • 1970-01-01
  • 2011-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-15
相关资源
最近更新 更多