views:

372

answers:

5

I am calling repaint a bunch of times from a listeners, but the way I designed my paint function is only one repaint is required. I generate a bunch of repaints, since it hooked into my mouse motion listener.

Is there a way to cancel all pending repaints for a certain component? I can't just start ignoring repaints, since some are valid like when you resize the frame or restore it from minimize.

Why do I care? Because my paint code is very heavy and I can't do full repaints at a very high FPS.

+1  A: 

My understanding is that repaint() simply schedules a repaint by adding a region of the component to the repaint queue. If a repaint has already been requested on a component, the new repaint region will just be unioned with the previously requested regions. The repaint is not actually executed until all other events in the event queue are handled. So, your additional repaints may not make much of a difference, i.e. your painting code will only be executed once. See JComponent.repaint and RepaintManager.addDirtyregion.

Dave Ray
+1  A: 

Frequent repaint requests are automatically collapsed into one. The best way to optimize this is not to repaint the whole thing, but call repaint with coordinates of specific area. This means you repaint only the area which actually changed.

eugener
+2  A: 

Swing will combine repaints for you: see "Painting in AWT and Swing" on Sun's website. If you schedule a number of repaints in rapid succession, they'll get combined into a single call to paintImmediately().

Sbodd
A: 

I've hacked something similar together to improve how JFreechart decides to paint when it makes lots of calls to repaint.

Essentially I do the following:

  • Create a ScheduledExecutorService as a field in the class
  • Receive first repaint request and and submit it to the executor to run on the EDT in say 50ms getting back the future
  • Receive second request - test to see if the previous repaint has finished (fut.isDone()) and if so to schedule the next repaint; otherwise do nothing.

This way you should get at most 20 repaint request per second.

I've done similar things for batching up the number of calls to fireDataTableChanged when lots of changes are occuring at the same time.

pjp
A: 

I hear what your saying. You can indeed repaint only a section of area. In the "Performing Custom Painting Examples" on the Sun website, I found a useful example which shows how to draw a dragged rectangle, and then only repaint that area when the mouse is moving or released.

Here is the relevant section of code...

public void mouseDragged(MouseEvent e) {
            updateSize(e);
        }

        public void mouseReleased(MouseEvent e) {
            updateSize(e);
        }

        /* 
         * Update the size of the current rectangle
         * and call repaint.  Because currentRect
         * always has the same origin, translate it
         * if the width or height is negative.
         * 
         * For efficiency (though
         * that isn't an issue for this program),
         * specify the painting region using arguments
         * to the repaint() call.
         * 
         */
        void updateSize(MouseEvent e) {
            int x = e.getX();
            int y = e.getY();
            currentRect.setSize(x - currentRect.x,
                                y - currentRect.y);
            updateDrawableRect(getWidth(), getHeight());
            Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
            repaint(totalRepaint.x, totalRepaint.y,
                    totalRepaint.width, totalRepaint.height);
        }

This code is subject to copyright (see here for full code and copyright notice)

See here for further example listings

Truth be told, I'm having a similar issue on FPS, but that may be due to my currently poor code! I've learnt so much over the past few months, that I can now make my code so more efficient. Hopefully I can overcome the FPS issue when more than 2 "people" slow down my graphics! Hummmm... I have only implemented the above code for the same section in my code, and not others, but by all means give it a try!

Relequestual