Invalidate(False) clearing the background

I’m using a MVC model so my data are represented by objects which are provided by a controller and then drawn on screen in a Paint event. I want to make this more efficient by not redrawing things that haven’t changed. So I added a “NeedsRefresh” property to my objects, and check this property is true before drawing them in the Paint event. The problem is that the ones that aren’t marked with NeedsRefresh=True get erased every time Paint is triggered by calling Invalidate. My understanding is that Invalidate(False) should prevent the background from being erased, but nonetheless the canvas is filled with grey each time, and only the items marked as NeedsRefresh are drawn. Can I actually invalidate the canvas without clearing its contents so that I can then just redraw over the top the parts I need to?

maybe try

.Invalidate(X As Integer, Y As Integer, Width As Integer, Height As Integer [,EraseBackground As Boolean])

or use the canvas Backdrop

Ahh so only invalidate the parts of the canvas that include things that have actually changed, I like it. If I do this, I guess the same Paint event is still fired but only canvas drawing which takes place within the specified coordinates actually happens. Is that right?

Yes the paint event is fired but passed into it is an array called areas() that contains a list of coordinates of regions that are to be redrawn. It is then up to you to check that areas() has entries (LastIndex) and see if anything in each area needs to be redrawn. If LastIndex is -1 then the whole control needs to be redrawn. The reason there’s a list of areas is that multiple invalidates can occur before a paint due to the nature of invalidate happening when it has a chance as opposed to refresh which happens immediately.

As far as I can remember, erasebackground is no longer in use but my memory is a little fuzzy these days so that may be wrong.

Thanks Julian. I’m trying to invalidate only the rect of a specific area, but I’m finding that if I do so, areas() contains a Rect with the same coordinates no matter which item I ask to be refreshed. For example:

' ClickedItem is an abstract object representing the data displayed in the canvas. it has a Frame property which is already set with its top/left and width/height
Self.Invalidate(ClickedItem.Frame.Left, ClickedItem.Frame.Top, ClickedItem.Frame.Width, ClickedItem.Frame.Height)

In my Paint event I then iterate through the areas() array and any items which don’t fall inside any of them don’t get drawn. However, the Rect in areas(), when its coordinates are logged, are always at 80 (x) and 288 (y) with always the same size. I don’t know the significance of these numbers. The ClickedItem frame is not set to those values. I know this because if I also log those, then the correct values are shown. I even tried doing “Invalidate(1, 2, 3, 4)” and still those were not the values in any of the Rects in areas(). I don’t know if I’m misunderstanding something here because this behaviour doesn’t seem consistent with how I have understood this process.

Ahh wait, I got it I think. I took a screenshot and found the location of those coordinates, and they’re another control which is overlapping this canvas. I moved it away, and this Rect disappeared from the array and was replaced with the correct one (I was lazily logging it in a way that cleared the previous Paint results so didn’t know it was Painting more than once). I’m now getting the correct coordinates for the clicked item so I can test for its location correctly and redraw

1 Like

I was about to suggest that but you beat me to it :slight_smile:

Haha the forum told me you were typing while I was and I wondered if you’d already come up with the solution :wink: Working in Xojo is very different to Cocoa which has been my primary API for years, so it’s a fun challenge to get to know its idiosyncrasies. I really appreciate this forum!