Recent

Author Topic: [Solved] Dark mode in app, white flash on treeview load ...due to icon retrieval  (Read 628 times)

d7_2_laz

  • Sr. Member
  • ****
  • Posts: 396
For everybody who might be interested in:

Earlier i had (within topic: Dark Theme in my program?) mentioned that i had problems in my app
occuring as white flash at a treeview load. I did find a workaround here, it's fine, more or less), healing the background erasure. See: https://forum.lazarus.freepascal.org/index.php/topic,62695.30.html      (reply #43 and #44)

But i didn't know at that stage at all why exactly this issue even did occur. Occasionally, now i saw the reason why:
It's by the OnGetImageIndex, especially here by the runtime of SHGetFileInfoW when dealing with icon retrieval, just happening during the background erasure.

For to have a small test case, i found it easy to demonstrate using a ShellTreeView as an example.
Test project attached. All needed files are inside (from zamtmn's metadarkstyle repo), no package needs to be installed.

You can see by this sample how annoying the issue is. Click also on the Gif file for to see.
The test project also shows how it might be somehow circumvented a bit.
A bit, because it's still not fully convincing as all controls will eppear instantly, whereas  the treeview does not, and so it feels kind of bumpy.

It's not by a flaw of one of the compoenents involved of course, it's by Windows.
Btw., suppressing WM_ERASEBKGND (treeview scope) won't have an effect.
To establish an icon thread solely for this very special matters would appear to be too much overhead.

Any clever idea how to make it more smooth would be welcome!
« Last Edit: May 31, 2023, 11:30:45 pm by d7_2_laz »

Joanna

  • Sr. Member
  • ****
  • Posts: 377
Hello since nobody else has answered I’ll have a try at this.
I’ve never used treeview but I’ve been able to solve flickering issues with other types of controls by making doublebuffered:= true;
Also sometimes flickering can be caused by other things happening with control. I can’t see your code but maybe try testing with skipping code and see if it behaves any differently.
More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channels  #fpc  #pascal Please private Message me if you have any questions or need assistance.

d7_2_laz

  • Sr. Member
  • ****
  • Posts: 396
Thanks Joanna for attention! (btw: a sample project was attached)
I think it's an interesting as well as annoying issue that disturbs a professional look of an app.
But, to repeat, it's not a treeview or themeing's issue, it's simply by constellation of things:

Whilst (or short before/after) the background erasure runs, a lengthy operation (icon retrieval) does block the app before it is able to apply the dark themeing. Therefore the flash.

Experimenting, one will see that none of the typical flicker solver will help here: keywords: doublebuffer (which is already set); wm_setredraw & co.; LockWindowUpdate & co.; suppression of wm_erasebkgnd. Etc.

What i already had tried too:  to defer the lengthy operation after the control is initially drawn dark.
First, with a (maybe double nested) Post_Message that activates the icon retrieval at a later time. But such will apply too early though.
What might help is - alternatively - to use Application.OnIdle (if idle happens = drawing is done, a flag is activated that allows icon retrieval now).
Will help somehow, but the method has two disadvantages though. Therefore i won't follow it at all.
But nevertheless i attach a slighly modified version of the test project that shows this method.

eljo

  • Sr. Member
  • ****
  • Posts: 457
Thanks Joanna for attention! (btw: a sample project was attached)
I think it's an interesting as well as annoying issue that disturbs a professional look of an app.
But, to repeat, it's not a treeview or themeing's issue, it's simply by constellation of things:

Whilst (or short before/after) the background erasure runs, a lengthy operation (icon retrieval) does block the app before it is able to apply the dark themeing. Therefore the flash.

Experimenting, one will see that none of the typical flicker solver will help here: keywords: doublebuffer (which is already set); wm_setredraw & co.; LockWindowUpdate & co.; suppression of wm_erasebkgnd. Etc.

What i already had tried too:  to defer the lengthy operation after the control is initially drawn dark.
First, with a (maybe double nested) Post_Message that activates the icon retrieval at a later time. But such will apply too early though.
What might help is - alternatively - to use Application.OnIdle (if idle happens = drawing is done, a flag is activated that allows icon retrieval now).
Will help somehow, but the method has two disadvantages though. Therefore i won't follow it at all.
But nevertheless i attach a slighly modified version of the test project that shows this method.

try to override the WMEraseBkgnd procedure of the control and make sure that you fillrect the background with the correct color. This will be shown before the lengthy operation of folder retrieval from the loaded method (already tried it) but the flicker of the node drawing on the tree will be present.
« Last Edit: May 31, 2023, 07:16:39 pm by eljo »

d7_2_laz

  • Sr. Member
  • ****
  • Posts: 396
@eljo, thanks! Honestly, i'm a bit surprised now:
When i initially had tested in a component to intercept the WM_ERASEBKGND message, returning true - without doing FillRect: -, then because i expected that Windows leaves it to me to fill the background (or not) in that case. This did not happen though (probably one Must handle the device context and use it).

Then (workaround_1) i expected that the SetClassLongPtrW GCL_HBRBACKGROUND with COLOR_INACTIVECAPTIONTEXT (it's an index, no TColor) should even do just the same (= the FillRect, but using the color with the index provided, instead of white).
The result is surprising for me: the workaround already looks quite good but still a bit bumpy .... whereas your approach visually does appear noticeably better than workaround_1!! Very very close to one would expect. Thanks fot the kick, very valuable!

Maybe the difference is due to the color indexed via COLOR_INACTIVECAPTIONTEXT is not close enough to the final dark color that one can specify more exactly when doing the FillRect.

Question: is there any specific reason for the override of procedure Loaded?

eljo

  • Sr. Member
  • ****
  • Posts: 457
Question: is there any specific reason for the override of procedure Loaded?
I was trying to delay loading the tree's data but it did not work, you can safely ignore it.

d7_2_laz

  • Sr. Member
  • ****
  • Posts: 396
Thanks eljo, had the same impression (when trying having commented it out).

Just tested the solution in the app where i had noticed that the workaround mentioned was not fully convincing and i think that's the best solution we can have. It's just as expected, many thanks for your input, the treeview now behaves just one would expect!
// Workaround's COLOR_INACTIVECAPTIONTEXT  was not precise enough

 

TinyPortal © 2005-2018