Switching light/dark mode in window's paint event

  1. 3 months ago
    Edited 3 months ago

    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.

  2. Carsten B

    Dec 20 Pre-Release Testers, Xojo Pro Germany, NRW, Europe

    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
  3. Thank you foe answering. But still no luck. When the window is a floating one, it remains in lightMode.

  4. jim m

    Dec 20 Pre-Release Testers Phoenix, Arizona piDog.com

    Try invalidating the window after setting the color.

    Window(i).invalidate
  5. Dave S

    Dec 20 San Diego, California USA

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

  6. @jim mckay invalidate did it.

    @Dave Sisemore

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

    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.

  7. Jürg O

    Dec 20 Pre-Release Testers, Xojo Pro

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

    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
  8. jim m

    Dec 20 Pre-Release Testers Phoenix, Arizona piDog.com

    @Jürg O g.ForeColor = aBrightColor
    if IsDarkMode then g.ForeColor = aDarkColor

    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.

  9. @jim m

    or a canvas with the appropriate color based on IsDarkMode rather than a RoundedRect control.

    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.

  10. 6 days ago

    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.

  11. Alfred V

    Mar 15 Pre-Release Testers

    @Carlo R 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.

    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..

  12. 5 days ago

    Thank you, Alfred.

or Sign Up to reply!