Bug: Debug stepping alters behavior

Description:
Xojo incorrectly renders a Canvas Subclass unless the user steps through a breakpoint. If the user does not break execution, the Canvas Subclass renders the image twice. If the user steps through a breakbpoint, Xojo correctly renders one image.

This behavior is consistent. Stepping through the code should not alter behavior.

Repro steps:

  1. Create a project with a Subclass for Canvas. Add a property - RealImage to the Subclass
  2. Add an instance of the Subclass to the Window, with a Backdrop image
  3. Add a Paint event, using the code below
  4. Observe behavior by running the program
  5. Add a breakpoint in the Paint event and restart, stepping through it
  6. Observe behavior

Here is the Paint event:

// In the Paint event of the Canvas
if Me.RealImage = Nil then
  Me.RealImage = Me.Backdrop // Get the backdrop
  Me.Backdrop = nil // And then remove it
end if

If Me.RealImage <> Nil Then
  // Draw the image scaled to fit the Canvas
  g.DrawPicture(Me.RealImage, 0, 0, Me.Width, Me.Height, 0, 0, Me.RealImage.Width, Me.RealImage.Height)
End If

I would assume the backdrop removal would require a repaint of the control, which you are currently in. So it would render it twice.
Try moving your RealImage extraction code to an opening event and call refresh after updating the backdrop, may or may not actually need it but cannot hurt.
Only have actually drawing logic in the paint event.

Opening Event

if Me.RealImage = Nil then
  Me.RealImage = Me.Backdrop // Get the backdrop
  Me.Backdrop = nil // And then remove it
end if
RaiseEvent opening //Create opening event and raise it so sub classes / window can handle it
Refresh() //might not need this

Painting Event

If Me.RealImage <> Nil Then
  // Draw the image scaled to fit the Canvas
dim ar as double  = me.Realimage.Width / me.RealImage.height //Get aspect ratio of image
dim w as integer = g.width  //try fitting to width
dim h as integer = round(w / ar) //get height
if h > g.height then //check height fits
h = g.height //Nope fit to height
w = round(h * ar) //get width
end if
//Render in the center of g
  g.DrawPicture(Me.RealImage, g.width / 2 - w / 2, g.height / 2 - h / 2, w,h, 0, 0, Me.RealImage.Width, Me.RealImage.Height)
End If

Or something simular to that

That is my understanding but logically, repainting after the removal should mean it’s not there. Why would it “paint” something set to nil?

The main point is that it consistently draws it once if there is a breakpoint and twice if not.

That’s not how it should work. Breakpoints are not supposed to alter behavior.

Stepping through the code would be doing an app.doevents type thing that allows the app to update. This does not happen until end of methods / events during normal running.
Moving the code to opening event is better way to handle it as you only want to check it once. Not every paint event.

The issue you are running into has to do with the fact that the OS paints things when it wants to, not on any particular schedule set by the debugger.

If you really want to use the code you have, I suggest moving that first block to the Opening event so it doesn’t get run on every paint event.

2 Likes

FYI, I’m not seeing any difference in behavior.

Run with a breakpoint on the first line and stepping through:

Run w/o breakpoints:

This is on Xojo 2025r1, macOS 15.3.2 M4 chip.

Sample Project:
canvas1.zip (63.4 KB)

Using your example I see exactly the same behavior as I described.


Here you can see the second image on top of the first.

I put a breakpoint at if Me.RealImage = Nil then and step through until I get past Me.Backdrop = nil . Then I remove the breakpoint and resume.


Here there is only one image.

EDIT:

I tried another experiment. I ran without a breakpoint and saw the two images. Then I resized the window and the backdrop image disappeared.

Right. My example is not the way to do this but I think there is a underlying flaw in how Xojo is processing it. Otherwise, the interrupt by the debugger wouldn’t matter.

It’s not about using the code I have, it’s about Xojo’s debugger changing the output. My guess is that breaking execution is causing another Paint event.

Never mind that. Just pay attention to what @Greg_O says.

I’m not saying you’re wrong, but personally, I never think of any IDE debugger being a promise of catching your code executing as it would when your app is a stand-alone built app.

For example, sometimes when debugging inside a Focus event, debugger stepping will inadvertently cause focus events to fire repeatedly (losing & receiving) making it near impossible to replicate what should be happening.

Sometimes System.DebugLog is a better choice than breakpoints.

1 Like

I appreciate your viewpoint but that would severely weaken the purpose of a debugger - to be able to step through a program and predictably observe the results. I don’t think I’ve ever seen such behavior on GDB, Visual Studio, VS Code, Code::Blocks, etc. Perhaps the quirks are typical for Xojo. I have many years of experience in other environments and languages but I am still new to Xojo. I’ve used it very little but I am hopeful that it will work for a medium-sized project.

@Greg_O makes an important point and it certainly looks like a timing issue. However, I would still contend that this is a matter Xojo should look into and see if they can improve the behavior.

1 Like

The problem is here. Don’t do this in a Paint event.

3 Likes

So do I.

And I’ve seen the VS debugger tell me lies several times, but thankfully that’s all in the past. I’m unintentionally retired now, and only play at Xojo to help keep me occupied, when I’m well enough.

All development platforms have their quirks, but I find Xojo the least problematic and somewhat calming, for an all-in-one tool.

If you hang out on the forum long enough, you’ll come across references to some very successful (and large) projects.

Plus, don’t forget that the Xojo IDE itself is built using Xojo :wink:

Why are you still using the backdrop image? This is not necessary at all.

2 Likes

I use it to set a picture at design time. And then grab it on open. Helps if you are doing custom buttons and want to see an icon or mask image etc at design time.

Then you should only be doing that assignment in the Opening event, not in Paint.

1 Like

Unless you were referring to someone else, that’s what I clearly say I am doing, and show in all my sample code on this thread. I was just giving Beatrix an reason of why you would use the Backdrop Image in a canvas with custom rendering.

Also the reply button, does not seem to add the quote or who you are replying to anymore.

In your first note, you clearly said that you were doing that assignment in the paint event.

I am not Ken. I replied with open events and paint event sections of code.

Sorry!