Switching light/dark mode in window's paint event

Hello,
in the appearanceChanged event of app I have this code:

for i as Integer = 0 to WindowCount-1 if Window(i) isa versionsWin then if IsDarkMode then versionsWin.RoundRectangle1.FillColor = kClrDarkMode else versionsWin.RoundRectangle1.FillColor = kClrWhite end if exit end if next

Switching between light and dark mode works OK when the window is not a floating window.
But if I make the window a floating window, RoundRectangle1 does not react; it remains the same as in light mode.

So I put the code into the paint event of the floating window, and now RoundRectangle1 changes its color all right:

if IsDarkMode then RoundRectangle1.FillColor = backClrDM else RoundRectangle1.FillColor = recBackClr end if

Hence my question: is it safe to move into the paint event of all windows their own code that at present resides in appearanceChanged, even if a window would not necessarily need a paint event?

Thank you for any suggestion.

You forgot to cast the Window(i):

for i as Integer = 0 to WindowCount-1 if Window(i) isa versionsWin then if IsDarkMode then versionsWin( Windows(i) ).RoundRectangle1.FillColor = kClrDarkMode else versionsWin( Windows(i) ).RoundRectangle1.FillColor = kClrWhite end if exit end if next

Thank you foe answering. But still no luck. When the window is a floating one, it remains in lightMode.

Try invalidating the window after setting the color.

Window(i).invalidate

I would put any Light/Darkmode stuff in the PAINT event as it seems that does fire when it transitions

@jim mckay invalidate did it.

@Dave S

So, this seems to answer my question about using the paint event of any window to deal with its Light/Darkmode stuff.

Thank you both.

Yes:

g.ForeColor = aBrightColor if IsDarkMode then g.ForeColor = aDarkColor
No:

if IsDarkMode then me.FillColor = someOtherColor if IsDarkMode then me.BackDrop = anotherPicture
Please do not change Control properties in the .Paint-Event. This may lead to unexpected behavior (especially on TargetWindows), since that Property-assignment could trigger yet another .Invalidate of the Control (called by the Xojo Framework) which is leading to an endlessly repeating Invalidation-Paint-Loop).
If that’s your only option… then at the very least please do it like this (to avoid unnecessary Property assignments):

Dim useColor As Color = aLightColor if IsDarkMode then useColor = aDarkColor if (me.FillColor <> aLightColor) then me.FillColor = aLightColor

[quote=418710:@Jürg Otter]g.ForeColor = aBrightColor
if IsDarkMode then g.ForeColor = aDarkColor[/quote]

Just to clarify… you could use g.FillRoundRect and g.DrawRoundRect in the paint event of the window or a canvas with the appropriate color based on IsDarkMode rather than a RoundedRect control.

@jim mckay

Actually yesterday I had replaced the roundRectangle with a canvas, but since in DarkMode I noticed that the angles did not show “clean”, I had reverted using a roundRectangle.
Well, this morning I tried again using a canvas with the same code of yesterday, and everything looks all right. All is well that ends well (google translation of the idiom: tutto bene quello che finisce bene). Thanks.

Hi,
as I said in one of my posts above, I moved various codes requiring different colors for certain objects in the paint event of the object’s window. For instance, if my textArea.backcolor is set to Yellow but in DarkMode should switch to Blue, the window’s paint event handles it:
(paint event handler)
dim mBackColor as color = color.yellow
if isDarkMode then mBackColor = color.blue
myTextArea.backcolor = mBackColor

Now, my textArea.text contains certain words in colors different in Light and DarkMode, handled by a “resetColors” method. So, in the paint event of the window I added:

if myTextArea.text <> “” then
resetColors
end if

Then I noticed that myTextArea kept redrawing when I changed the size of the window or edited the text etc. Therefore I realized what I should have been aware of, i.e. the paint event draws continually.
Of course, I moved the call to resetColors to the app.appearanceChanged event.

So I’m now wondering if the idea of keeping all code (the above snippet is just an instance, but I have more calls for controls that do not auto-change their colors when changing appearance) in the paint events of windows is really a good idea, and I’m tempted to go back and make use of the app.appearanceChanged event.

Suggestions and advice welcome. Thank you.

[quote=428640:@Carlo Rubini]So I’m now wondering if the idea of keeping all code (the above snippet is just an instance, but I have more calls for controls that do not auto-change their colors when changing appearance) in the paint events of windows is really a good idea, and I’m tempted to go back and make use of the app.appearanceChanged event.

Suggestions and advice welcome. Thank you.[/quote]

Indeed, recoloring, recommended by Apple, should be done in the paint event. Changing colors as you do can be done in the AppearanceChanged event, given you manually change them. You should be fine.

If you ever are going to use Apple-named colors like “textColor” then it is mandatory to call “textColor” in the paint event. The AppearanceChanged event should not be used to call “textColor” because the system is not ready yet to change “textColor” to dark or light mode. Using light-dark aware NSColors does not even require the AppearanceChanged event, it just signals an upcoming change and it is safe as well as mandatory to use the paint event…

Thank you, Alfred.