The method slows down the execution of paintComponent ()

I have a little problem. When executing the method paintComponent()

during animation, I have to keep updating the variable bgImage

. But it takes a long time, so the animation slows down.

Code block with problem:

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 a long-time operation
        BufferedImage bgImage = GraphicsUtils.gaussianBlur(AnotherClass.getBgImage()); 
        g2.drawImage(bgImage, 0, 0, null); 

        // Other code...
    }
}

      

I read online that I need to run a long task on a parallel thread (SwingWorker), but I don't know how to do it in my case. How can I solve this problem?

PS Sorry for my bad english, this is not my first language.

+3


source to share


3 answers


The best thing you are going to do is update the image outside of the paint method and only redraw when the new image is ready. Take your existing code and add a permalink to the image that is drawn for JComponent

each drawing method. Then enable the Gaussian blur animation timer and refresh the image.



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...
    }
}

      

+1


source


There is no general way to solve this problem where you create a new background image every time and then blur it. GaussianBlur - slow operation, period.

If AnotherClass.getBgImage () delivers images from a predefined set of images, then apply the blur once to each image in the set, the problem goes away.

If you create the image in AnotherClass.getBgImage () dynamically, you can speed it up by changing the image generation to create a blurry image from the start. Depending on what has been done to create the image, this may or may not be feasible.



If none of the above is worked out, you need to explore other options to create a blurry image that runs faster; there are simpler blur techniques that are usually faster, but look somewhat Gaussian-like.

You can see that it all boils down to getting rid of repeatedly calling GaussianBlur on the critical performance path.

+1


source


You have to extract logic from the artist. The artists are named strictly and must be executed very quickly.

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

      

Should this line be executed every time? maybe you could use a field to store the image and the artist could just pry on the image instead of using gaussianBlur every time.

Try this: public class ProblemClass extends 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 a long-time operation
        g2.drawImage(bgImage, 0, 0, null);

        // Other code...
    }
}

      

0


source







All Articles