desktopCanvas.paint not firing

I have a simple window, with a canvas that includes me.Refresh on MouseUp, however the associated paint event is not firing - at least not consistently.

In my app it is within several layers of containerControls and paint doesn’t fire.

In trying to isolate the problem I have 2 items on a window. A canvas with this code:

Function MouseDown(x As Integer, y As Integer) Handles MouseDown as Boolean
  return true
End Function

Sub MouseUp(x As Integer, y As Integer) Handles MouseUp
  counter = counter + 1
End Sub

Sub Paint(g As Graphics, areas() As Rect) Handles Paint
  g.drawstring(counter.tostring, 10,10)
End Sub

The window also contains a containerControl with the same canvas/counter/paint event.

If I click the canvas in the container - it increments and displays the counter.
If I click the canvas on the window - the counter is incremented but the paint event doesn’t fire, so doesn’t show the new value.
Forcing a window refresh, by taking the window off and on screen again fires the paint event, showing the right value. Also by inserting a break point in the debugger, it forces a paint event.

Strangely in the test code, the canvas inside the container does fire the paint event.

MacOS Ventura 13.0, Xojo 2022r3.

Just tested same in Monterey 12.6 - works OK there - seems to be a Ventura problem. Ugh.

Now I’m more confused. Just loaded same test app on clean virtual versions of Monterey and Ventura - both work fine. Seems to be something to do with my main machine, or the plug-ins (which I’m not using for the test app), or something else …

Have you tried rectControl.invalidate instead?
AFAIK Refresh should trigger a paint event there and then, while invalidate just marks the view as dirty and allows the OS to update when you the current cycle is complete.

I would also suggest making sure that you’re not using doubleBuffer on the macOS and just let the macOS buffer the view for you.

API2: .Refresh() is deferred. .Refresh( True ) is immediate.


API 1.0 : Don’t use Refresh unless you really need it, otherwise use Invalidate.
API 2.0: Don’t use invalidate, use Refresh instead, even if you don’t need an immediate refresh.

Xojo wonders why long time users don’t like API 2.0.

They could have actually used terminology which would explain which function to use and when. I don’t know, like “updateWhenReady” and “updateNow” or “updateCoalesced”.

There is only one method, on API2 controls and windows:

Refresh( immediately As Boolean = False )

Invalidate does not exist on the new controls so you will be directed to correct the usage the first time you try and compile after changing controls types.

I could write a whole lot of snark about this decision, but it’s not going to affect any positive change, will probably get me labelled as a Troll and is just detracting from what little time I have to write software.


Aha! I tried desktopUICOntrol(me).refresh(true) and bingo, it now works. Would seem there is a bug lurking in there somewhere.

Spoke too soon - works in the test project, not in the main app that had me looking for a soln.

1 Like

I would recommend you try skipping the Xojo function and directly using the Apple API. This will rule out a Xojo bug between refresh/invaliate and the OS function.

declare sub NSView_setNeedsDisplay lib "AppKit" selector "setNeedsDisplay:" ( NSViewInstance as integer, value as boolean ) // --- OSX 10 +
NSView_setNeedsDisplay( me.handle, true )

If that doesn’t work, then you’re down to several options I can see.

  1. An incorrectly configured window, which isn’t enabling triple buffering.
  2. A parent control that is asking all sub views to share the same view buffer (and not getting an update on Ventura).
  3. Most likely option, yet another bug in Apple’s wonderfully high quality OS releases.

Tks, I will try tomorrow when awake and report back.

1 Like