slow canvas on Windows

My app has a canvas 127 pixels high and the width of the window, in which the user drags a “viewport” box with the mouse left and right over a background image. On Mac, everything works great, as expected: the user drags the box, the box follows the mouse, the image is updated smoothly. On Windows, the box does not drag smoothly; instead, it follows in a very choppy fashion, lagging after the action a second or two, so you click and drag, but only see one image, then no motion, then another image at the end of the motion, and everything in between is never shown.

What’s going on? Is Windows really unable to update the graphics? I’ve gone over and over the code and I can’t see why it should be this slow. The smaller I make the window, the better the response is, but it is never smooth on Windows. A large window results in extremely slow, lagging, choppy response.

Looks like you are doing a lot during the drag. What is the box ? Is it a control ? How do you drag it ?

In fact there is not a lot happening during the drag. The box is simply drawn over the background image.

Further testing shows that the image does not get updated at all during dragging. It only gets updated on the first click and then when the mouse stops moving. (remember this is on Windows only, on Mac it works correctly).

Is there some major difference in how the drag event fires on Windows versus Mac? It’s as if dragging the mouse is blocking all updating. I’m not using a timer; I’m calling Invalidate from the drag event, and only when the X or Y values are different from values stored at each redraw.

So basically, you drag a picture within the canvas, right ?

You may want to test the example /Example Projects/Graphics and Multimedia/CanvasDrawDrag.xojo_binary_project

It is very smooth. If it works for you, you can pick the same kind of code.

I took a look and noticed this uses Self.Invalidate and not me.Invalidate, so I made that change, and it makes no difference. The graphics are not updated.

So your code is in the Canvas Mousedrag just the same ?

On Windows, I have sometimes seen choppy results when actually Paint is called too often. You may want to verify how many times the event fires. If necessary, reduce the number of executions to one every tick.

My code is not literally the same as the Xojo example, but yes the user is dragging a drawn box, and the drag event calls code that does some trivial calculation and then updates the canvas using invalidate.

You should check how many times a second the MouseDrag event calls your code. If it is anything faster than one every 20 ms or so, then use an if structure to make sure it does not fire faster than every tick.

Well I’m already doing that by only calling Invalidate when X or Y values change. But just to be sure I added a static lastTicks and compare it to ticks() to also bypass any invalidating faster than a tick. No difference. It does not update at all during dragging.

But, have you verified the event fires during dragging ?

Yes.

Well, I just ran CanvasDrawDrag under 2017R1.1 in Windows 10, dragged pictures are very smooth. Must be something in your code that does not agree with Windows.

CanvasDrawDrag also works fine here on Windows 7.

No idea. The canvas doesn’t redraw no matter what I do. Invalidate does nothing during the drag event.

Thank you anyway for your time. I’ll come back to this on Monday. Goodnight.

Aaron, what version of Xojo are you using? In Xojo 2016r2 and later, I’ve had a lot of graphic problems with our main app, which uses a lot of canvases. 2016r1.1 and before, it is as smooth as silk. It may not be related, but might be worth the effort to install 2016r1.1 and try it, if you are using a later version.

He did not say which version he was using. I purposefully used 2017R1.1 to check CanvasDrawDrag because with Direct2D, I would expect it to be somewhat slower.

Usually, what explains the UI not updating is a tight loop. I wonder if he has any in his code.

Aaron, would it not be time to post your code ? We are shooting in the dark.

In my experience the canvas on Windows is much much slower compared to macOS.
The main reason is that macOS uses double buffering by default (OS = double buffered). But that’s not the only reason.
Also, with the latest Xojo versions, it uses Direct2D for drawing, still it is very slow.

That said, if you installed the latest Windows 10 Creator, the canvas drawing is much faster, still not as fast as macOS though.

Indeed Windows executables in general are slower (just as the IDE BTW). But the CanvasDrawDrag example dragging is very smooth nonetheless. Aaron’s description of a choppy drag is something else entirely, which makes me suspect something in his code is doing it.

Just tested this with zero issues in Xojo 2015:

Create a window
Give it properties
MPOSX as integer
MPOSY as integer
bIsDragging as boolean

Add a Canvas
Drag a picture into the project (‘MyPicture’)

Set the canvas to grow with the window size (align right and left)

Add these methods to the Canvas:

[code]Function MouseDown(X As Integer, Y As Integer) As Boolean
bIsdragging = true
mposx = x
mposy = y

return true
End Function[/code]

Sub MouseDrag(X As Integer, Y As Integer) if bIsdragging then if x <> mposx or y <> mposy then mposx = x mposy= y me.invalidate end if end if End Sub

[code]Sub MouseUp(X As Integer, Y As Integer)
bIsdragging = false
End Sub

[/code]

[code]Sub Paint(g As Graphics, areas() As REALbasic.Rect)
g.drawpicture MyPicture,0,0,me.width, me.height

g.forecolor = &cff0000
g.penwidth = 3
g.DrawRect mposx - 50,mposy-50, 100,100

End Sub
[/code]

This runs smoothly for me.
Can be tweaked by setting erasebackground and doublebuffer properties.
I probably wouldnt bother with a canvas myself, since this works just as well on the window itself.

My guess about the delay is either cascading paint events, lots of unecessary calculations, trying to use ‘drag and drop’ methodology, or maybe having the image as a backdrop.

Try the code above and compare with what you are doing at the moment?

Well as I wrote above, I had intended not to work on this until tomorrow, but it was bugging me too much so here I am again …

Thank you kindly, Michel, Merv, Christoph, and Jeff Tullin for your assistance …

I found that graphics rendering on Windows is indeed faster in earlier versions. I’ve used Xojo since 2001, and have almost every version since then installed already, but I had skipped 2016r1.1, so tried Xojo2015r2.41, and found that the canvas updating is in general faster, BUT the same problem remained. No updating during dragging.

I figured out what causes the problem. There are two canvases on the window. Dragging the box on the canvas in question fires its paint event, and then calls an update on the other canvas. It’s this call to update the other canvas that for some reason blocks invalidating the canvas in question. In pseudo-code:

// event called when box is dragged
' calculate some stuff
self.Invalidate
UpdateOtherCanvas ' <-- this causes the problem

When I comment out UpdateOtherCanvas, I get correct results.

I’ve run into this kind of thing before, on both platforms – that sometimes redrawing a control (for me usually listboxes) will simply not fire at a particular point in code. Calling Invalidate (or Refresh) sometimes has absolutely no effect, depending on where in the code it is called. Usually I solve the problem by calling a Timer which then calls Invalidate. Then it works. It is the “decoupling” of the call to invalidate or refresh that solves the problem.

My solution for now: on Windows, simply skip updating the other canvas during dragging. Update it only on MouseUp. It’s not as slick as Mac, which updates everything smoothly and looks perfect, but at least it doesn’t stall and stutter. It’s acceptable for Windows. So, I have essentially:

// event called when box is dragged
' calculate some stuff
self.Invalidate
#if TargetWin32 then
if WeAreDragging then return
#endif

UpdateOtherCanvas

Then the other canvas only gets updated on MouseDown and MouseUp. Not what I’d like, but acceptable.