How to show a rapidly changing image in an SWT canvas? ( paintControl() listener method is not being called rapidly)

StackOverflow https://stackoverflow.com/questions/18952545

Question

I'm using a MouseMoveListener on a composite to update the image on another canvas. Basically, if the user drags Composite1 to somewhere on his screen, that will call the mouseMoveEventListener everytime the mouse moves, which will get the x,y location of the mouse, take a screenshot using Awt.robot.captureScreenRegion, and try to update the image of Canvas1 by calling its repaint() method. The purpose is just to show the user a preview of what's under the composite as he's dragging it.

Here's the problem. While the mouseMove callback is called, and it in turns takes the screenshot and calls the repaint method in time, the actual paintControl() listener method of the canvas (listening to its Paint event) is not being called each time the mouse moves. I.e, if you drag the composite, then pause a few seconds, that will call the repaint method. But if you just drag it all the way to the left of your screen without pausing, the repaint method will not be called with every mousemove, it will only be called when you stop / pause moving the pause.

Is there a solution, i.e can the paint event be forced to occur everytime the mouse moves? Should I start a new thread for the repainting / previewing? Both the preview shell and the main shell are two separate shells.

Edit: Method which draws the image:

canvas.addPaintListener(new PaintListener()
        {
            public void paintControl(PaintEvent e)
            {
                if (img != null)
                    e.gc.drawImage(img, 0, 0);
            }
        });

(The image is converted from BufferedImage to Image before repaint() is called. From system.out.println logs I can see that all that is happening correctly, only the logs within paintControl() aren't printed till I stop moving the mouse.)

Edit 2: Event handling code:

public void mouseMove(MouseEvent e)
{
    if (e.stateMask == 0)
        return;
    //Just some wrapper methods to do shell.setLocation(), shell.getBounds().x, shell.getBounds.y
    setLocation(getX() + e.x, getY() + e.y);
}

public void controlMoved(ControlEvent e)
{
    updatePreview();
}



public void updatePreview()
{
    //Just a wrapper around Awt.robot, uses selectionCanvas's toDisplay() to get coordinates, takes
    //screenshot, converts it from BufferedImage to Image, and returns. 
    Image img = 
            ImgUtility.getScreenShot( selectionCanvas );


    this.image = img;
    //Upto this point it works fine.

    canvas.redraw(); //this calls the preview canvas's redraw method which 
    //should call the PaintListener previously described, but doesn't.
}
Was it helpful?

Solution 2

Found the solution, and it turned out to be really simple!

Just changed the controlMoved from this:

public void controlMoved(ControlEvent e)
{
    updatePreview();
}

to this:

public void controlMoved(ControlEvent e)
{
    Runnable r = new Runnable()
    {
        @Override
        public void run()
        {
           updatePreview();
        }
    };
    Display.getDefault().asyncExec(r);
}

and now it works perfectly!

OTHER TIPS

Just call canvas.update() after canvas.redraw().

public void update()

Forces all outstanding paint requests for the widget to be processed before this method returns.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top