Jump to content

Flickering of entire GUI during $WM_MOUSEWHEEL on a list view


Go to solution Solved by Nine,

Recommended Posts

Posted (edited)

Perhaps there's a simple solution to it but I don't see it. Or a different method.

Basically, I need custom scroll distance in the list view control so I am using subclassing for WM_MOUSEWHEEL.
I MUST have $WS_EX_COMPOSITED flag on the parent GUI for other reasons.

To test my issue just hover over the list view and scroll really fast up or down. The issue becomes even more apparent if the list view is populated with hundreds of thumbnails.

#include <GUIConstantsEx.au3>
#include <WindowsStylesConstants.au3>
#include <ListViewConstants.au3>
#include <GuiListView.au3>
#include <EditConstants.au3>
#include <WinAPISysWin.au3>

Global $GUI_WindowLibrary = GUICreate('TEST', 1000, 725, -1, -1, BitOR($WS_POPUP, $WS_BORDER), $WS_EX_COMPOSITED)
GUISetBkColor(0x202025, $GUI_WindowLibrary)
GUICtrlCreateLabel('TEST', 20, 5, 100, 50)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
GUICtrlSetColor(-1, 0xCCCCCC)
Global $GUI_WindowLibrary_ImageList = GUICtrlCreateListView('',  10, 85, 980, 300, _
                                     BitOR($LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_NOCOLUMNHEADER, $LVS_REPORT), _
                                     BitOR($LVS_EX_SNAPTOGRID, $LVS_EX_DOUBLEBUFFER))
GUICtrlSetBkColor(-1, 0x19191A)
_GUICtrlListView_SetView($GUI_WindowLibrary_ImageList, 0)
_GUICtrlListView_SetIconSpacing($GUI_WindowLibrary_ImageList, 119, 40)
_GUICtrlListView_SetTextColor($GUI_WindowLibrary_ImageList, 0xCCCCCC)

GUICtrlCreatePic("C:\Windows\Web\Wallpaper\ThemeB\img24.jpg", 10, 410, 176, 250)
GUICtrlCreateLabel('TEST', 200, 410, 100, 20, $DT_PATH_ELLIPSIS)
GUICtrlSetColor(-1, 0x8A8A8A)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
GUICtrlCreateLabel('TEST', 200, 435, 100, 20, $DT_PATH_ELLIPSIS)
GUICtrlSetColor(-1, 0x8A8A8A)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
GUICtrlCreateLabel('TEST', 200, 460, 100, 20, $DT_PATH_ELLIPSIS)
GUICtrlSetColor(-1, 0x8A8A8A)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
GUICtrlCreateInput('TEST', 315, 410, 675, 20, BitOR($ES_LEFT, $ES_AUTOHSCROLL, $ES_READONLY), 0)
GUICtrlSetColor(-1, 0xCCCCCC)
GUICtrlSetBkColor(-1, 0x3F3F3F)
GUICtrlCreateInput('', 315, 435, 675, 20, BitOR($ES_LEFT, $ES_AUTOHSCROLL, $ES_READONLY), 0)
GUICtrlSetColor(-1, 0xCCCCCC)
GUICtrlSetBkColor(-1, 0x3F3F3F)
GUICtrlCreateInput('', 315, 460, 570, 20, BitOR($ES_LEFT, $ES_AUTOHSCROLL, $ES_READONLY), 0)
GUICtrlSetColor(-1, 0xCCCCCC)
GUICtrlSetBkColor(-1, 0x3F3F3F)
GUICtrlCreateLabel('', 0, 0, 1000, 50, -1)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
GUICtrlCreatePic("C:\Windows\Web\Wallpaper\Windows\img19.jpg", 0, 0, 1000, 725)
GUISetState(@SW_SHOW, $GUI_WindowLibrary)

Global $PROGRAM_WindowLibrary_Procedure = _WinAPI_SetWindowLong(GUICtrlGetHandle($GUI_WindowLibrary_ImageList), $GWL_WNDPROC, DllCallbackGetPtr(DllCallbackRegister('LibraryListViewProc', 'int', 'hwnd;uint;wparam;lparam')))

Local $iMsg
While 1
    $iMsg = GUIGetMsg()
    Select
        Case $iMsg = $GUI_EVENT_CLOSE
            GUIDelete($GUI_WindowLibrary)
            Exit
    EndSelect
WEnd

Func LibraryListViewProc($hWnd, $iMsg, $wParam, $lParam)
    Local $iListView = 0 ;doesn't matter right now
    Switch $iMsg
        Case $WM_MOUSEWHEEL
            If $iListView = 2 Then      ;List
                Return _WinAPI_CallWindowProc($PROGRAM_WindowLibrary_Procedure, $hWnd, $iMsg, $wParam, $lParam)
            ElseIf $iListView = 0 Then  ;Large thumbnails
                Local $TempDistance = 160
            ElseIf $iListView = 1 Then  ;Small thumbnails
                Local $TempDistance = 75
            EndIf

            Local $iDelta = BitShift($wParam, 16)
            If $iDelta > 0 Then     ;Scroll up
                _SendMessage($hWnd, $LVM_SCROLL, 0, -1 * $TempDistance)
            Else                    ;Scroll down
                _SendMessage($hWnd, $LVM_SCROLL, 0, $TempDistance)
            EndIf

            Return 0
;~             Return 1
    EndSwitch

    Return _WinAPI_CallWindowProc($PROGRAM_WindowLibrary_Procedure, $hWnd, $iMsg, $wParam, $lParam)
EndFunc

 

Also, I used this as a reference for subclassing, but shouldn't I be calling DllCallbackFree() on exit (once it's not a one-liner)?

Edited by NMS
Posted (edited)

I'm trying to help but I can't even see the ListView or half of the GUI.

EDIT: But in general, without being able to run it, using WS_EX_COMPOSITED together with LVS_EX_DOUBLEBUFFER will cause additional flicker because they are both trying to do the same thing.

Edited by WildByDesign
Posted
1 minute ago, WildByDesign said:

I'm trying to help but I can't even see the ListView or half of the GUI.

Right. Sorry I was rushing and just cutting things left and right to make a runnable piece of code. But anyway, it's the big gray rectangle that takes about 50% of the entire window. I just didn't populate the list at all since the issue is reproducable anyway (at least in my case).

Posted (edited)

@WildByDesign just saw your edit. The issue in this particular instance is with the subclassing itself as no flicker whatsoever occurs with standard list view control scrolling.

I tried seeing if returning various states fixes this but it didn't. Also using VM_SCROLL but I don't quite remember what was the problem there.

Edited by NMS
Posted
2 hours ago, NMS said:

The issue in this particular instance is with the subclassing itself as no flicker whatsoever occurs with standard list view control.

Thanks for confirming. I don't have very much experience with subclassing so you'll need somebody else with those skills to help figure this flicker out.

Posted
23 minutes ago, WildByDesign said:

Thanks for confirming. I don't have very much experience with subclassing so you'll need somebody else with those skills to help figure this flicker out.

Yes I'll have to wait and see if somebody dealt with this before. Also removing $LVS_EX_DOUBLEBUFFER from the control did not solve the problem either (which I need as well).
And technically the issue isn't even the subclassing but specifically sending the message to the window with $LVM_SCROLL but I don't really know if I can replace this with something else as I need to trigger the scroll somehow.

Posted (edited)

It does not flicker for me like this.

;#AutoIt3Wrapper_UseX64=y

#include <GUIConstants.au3>
#include <GuiListView.au3>
#include <WinAPI.au3>

Global $GUI_WindowLibrary = GUICreate('TEST', 1000, 725, -1, -1, $WS_POPUP)
GUISetBkColor(0x202025)
Global $GUI_WindowLibrary_ImageList = GUICtrlCreateListView('', 10, 85, 980, 300, _
    BitOR($LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_NOCOLUMNHEADER, $LVS_REPORT))
GUICtrlSetBkColor(-1, 0x19191A)
_GUICtrlListView_SetView($GUI_WindowLibrary_ImageList, 0)
_GUICtrlListView_SetIconSpacing($GUI_WindowLibrary_ImageList, 119, 40)
_GUICtrlListView_SetTextColor($GUI_WindowLibrary_ImageList, 0xCCCCCC)
For $i = 1 To 200
  GUICtrlCreateListViewItem("item" & $i, $GUI_WindowLibrary_ImageList)
Next

GUICtrlCreatePic("C:\Windows\Web\Wallpaper\Windows\img19.jpg", 0, 0, 1000, 725)
GUISetState()

Global $hProc = DllCallbackRegister(LibraryListViewProc, 'int', 'hwnd;uint;wparam;lparam')
Global $PROGRAM_WindowLibrary_Procedure = _WinAPI_SetWindowLong(GUICtrlGetHandle($GUI_WindowLibrary_ImageList), $GWL_WNDPROC, DllCallbackGetPtr($hProc))

While True
  Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
      ExitLoop
  EndSwitch
WEnd

_WinAPI_SetWindowLong(GUICtrlGetHandle($GUI_WindowLibrary_ImageList), $GWL_WNDPROC, $PROGRAM_WindowLibrary_Procedure)
DllCallbackFree($hProc)

Func LibraryListViewProc($hWnd, $iMsg, $wParam, $lParam)
  Local $iListView = 0   ;doesn't matter right now
  Switch $iMsg
    Case $WM_MOUSEWHEEL
      If $iListView = 2 Then            ;List
        Return _WinAPI_CallWindowProc($PROGRAM_WindowLibrary_Procedure, $hWnd, $iMsg, $wParam, $lParam)
      ElseIf $iListView = 0 Then        ;Large thumbnails
        Local $TempDistance = 160
      ElseIf $iListView = 1 Then        ;Small thumbnails
        Local $TempDistance = 75
      EndIf

      Local $iDelta = BitShift($wParam, 16)
      If $iDelta > 0 Then           ;Scroll up
        _SendMessage($hWnd, $LVM_SCROLL, 0, -1 * $TempDistance)
      Else                          ;Scroll down
        _SendMessage($hWnd, $LVM_SCROLL, 0, $TempDistance)
      EndIf
  EndSwitch

  Return _WinAPI_CallWindowProc($PROGRAM_WindowLibrary_Procedure, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>LibraryListViewProc

 

Edited by Nine
corrected SetWindowLong statement and restating original handler
Posted
15 minutes ago, Nine said:

It does not flicker for me like this.

I can confirm that this works very well with no flicker. So that confirms that the WS_EX_COMPOSITED is what was causing the flicker.

@NMS In one of my scripts (Files Au3), I temporarily remove WS_EX_COMPOSITED when the ListView starts to scroll, then add WS_EX_COMPOSITED back when it stops. And that simple thing saved all of my ListView functionality while also being able to make use of WS_EX_COMPOSITED.

Posted
14 minutes ago, Nine said:

It does not flicker for me like this.

;#AutoIt3Wrapper_UseX64=y

#include <GUIConstants.au3>
#include <GuiListView.au3>
#include <WinAPI.au3>

Global $GUI_WindowLibrary = GUICreate('TEST', 1000, 725, -1, -1, $WS_POPUP)
GUISetBkColor(0x202025)
Global $GUI_WindowLibrary_ImageList = GUICtrlCreateListView('', 10, 85, 980, 300, _
    BitOR($LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_NOCOLUMNHEADER, $LVS_REPORT))
GUICtrlSetBkColor(-1, 0x19191A)
_GUICtrlListView_SetView($GUI_WindowLibrary_ImageList, 0)
_GUICtrlListView_SetIconSpacing($GUI_WindowLibrary_ImageList, 119, 40)
_GUICtrlListView_SetTextColor($GUI_WindowLibrary_ImageList, 0xCCCCCC)
For $i = 1 To 200
  GUICtrlCreateListViewItem("item" & $i, $GUI_WindowLibrary_ImageList)
Next

GUICtrlCreatePic("C:\Windows\Web\Wallpaper\Windows\img19.jpg", 0, 0, 1000, 725)
GUISetState()

Global $hProc = DllCallbackRegister(LibraryListViewProc, 'int', 'hwnd;uint;wparam;lparam')
Global $PROGRAM_WindowLibrary_Procedure = _WinAPI_SetWindowLong($GUI_WindowLibrary_ImageList, $GWL_WNDPROC, DllCallbackGetPtr($hProc))

While True
  Switch GUIGetMsg()
    Case $GUI_EVENT_CLOSE
      ExitLoop
  EndSwitch
WEnd

DllCallbackFree($hProc)

Func LibraryListViewProc($hWnd, $iMsg, $wParam, $lParam)
  Local $iListView = 0   ;doesn't matter right now
  Switch $iMsg
    Case $WM_MOUSEWHEEL
      If $iListView = 2 Then            ;List
        Return _WinAPI_CallWindowProc($PROGRAM_WindowLibrary_Procedure, $hWnd, $iMsg, $wParam, $lParam)
      ElseIf $iListView = 0 Then        ;Large thumbnails
        Local $TempDistance = 160
      ElseIf $iListView = 1 Then        ;Small thumbnails
        Local $TempDistance = 75
      EndIf

      Local $iDelta = BitShift($wParam, 16)
      If $iDelta > 0 Then           ;Scroll up
        _SendMessage($hWnd, $LVM_SCROLL, 0, -1 * $TempDistance)
      Else                          ;Scroll down
        _SendMessage($hWnd, $LVM_SCROLL, 0, $TempDistance)
      EndIf
  EndSwitch

  Return _WinAPI_CallWindowProc($PROGRAM_WindowLibrary_Procedure, $hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>LibraryListViewProc

 

Thanks for looking into this. I see that you removed the composited style from the window however. Unfortunately I need it as it fixes the bug with the guiflatbutton UDF. Without it, the buttons disappear when window is moving and a picture control is present behind them.

And I see that your example does answer my question at least when it comes to freeing the callback to the prelocedure as the provided example didn't do it.

Posted
1 minute ago, WildByDesign said:

I can confirm that this works very well with no flicker. So that confirms that the WS_EX_COMPOSITED is what was causing the flicker.

@NMS In one of my scripts (Files Au3), I temporarily remove WS_EX_COMPOSITED when the ListView starts to scroll, then add WS_EX_COMPOSITED back when it stops. And that simple thing saved all of my ListView functionality while also being able to make use of WS_EX_COMPOSITED.

I didn't think of that. Will look into it once home. This could only cause an issue with a UDF that I'm using that requires composited style but it technically should work.

I did however try to pause window redrawing before sending LVM_SCROLL message and then resuming again but that still caused flicker DURING the scrolling which I'm not sure should've been possible but oh well...

Posted
3 minutes ago, NMS said:

Unfortunately I need it as it fixes the bug with the guiflatbutton UDF.

This is actually why I ditched guiflatbutton UDF recently from several of my GUI projects. Each button gets created as a child GUI which can be very problematic.

Instead, I switched my GUI projects to @Nine’s custom drawn buttons. It freed up so much resources too.

Posted (edited)

@Nine I ran through your example code and simply bruteforced the issue by replacing chunks of your code with mine, in the end it was specifically this part:

Global $hProc = DllCallbackRegister(LibraryListViewProc, 'int', 'hwnd;uint;wparam;lparam')
Global $PROGRAM_WindowLibrary_Procedure = _WinAPI_SetWindowLong($GUI_WindowLibrary_ImageList, $GWL_WNDPROC, DllCallbackGetPtr($hProc))
...
DllCallbackFree($hProc)

Aside from not using DllCallbackFree() what exactly was the issue? I'm genuinely stunned here. From what I see, you just separated the one-liner that I had, which was flawed in a sense that I never released the resources, but that's it..?

 

Edit: Scratch that. The LibraryListViewProc() never is actually run in your example. Subclassing didn't work?

Edit 2: I can see that  $WS_EX_COMPOSITED is definitely causing the issue but sorry I must keep it.

Edited by NMS
  • Solution
Posted (edited)
55 minutes ago, NMS said:

The LibraryListViewProc() never is actually run in your example

You're absolutely right, I made a mistake when recopying the SetWindLong statement, you need to convert the id into handle :

Global $PROGRAM_WindowLibrary_Procedure = _WinAPI_SetWindowLong(GUICtrlGetHandle($GUI_WindowLibrary_ImageList), $GWL_WNDPROC, DllCallbackGetPtr($hProc))

If you want to free the dllcallback, you have to save the handle (doing it you need to break your single liner).

55 minutes ago, NMS said:

$WS_EX_COMPOSITED is definitely causing the issue but sorry I must keep it

Then try adding it to your GUI handle when necessary with GUISetStyle and remove it after.

And you also need to reinstate the original handler before exiting, otherwise it may crash your script.  See updated code above.

Edited by Nine
Posted

So the solution is pretty much the combination of what both @Nine and @WildByDesign recommended.

I ended up keeping $WS_EX_COMPOSITED style, however was able to remove the doublebuffering from the list view control (will work on that) and simply removing/adding the composited style in between the LVM_SCROLL message. The reality of it is that my list view control in the actual program is very heavy in thumbnails so some flicker is still there but I really have to hammer it to see it. That being said, this entire issue arises ONLY if I'm not using any of the Mica effects. Somehow, when I use mica, tabbed or acrylic none of the flicker is there and that's why I never noticed this issue until I decided to simply switch my program back to dark theme (without mica) and saw it instantly.

But before I'm done with this thread, can any of you let me know how the thumbnail drawing behaves in your cases on your particular systems? The reason being and I'm not sure if this is on my system only, but when I do not add sleep timer to the loop that draws thumbnails they simply draw over one another. This wasn't the case until around I updated the OS to build 22631.

#include <GUIConstantsEx.au3>
#include <WindowsStylesConstants.au3>
#include <ListViewConstants.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>

Global $GUI_WindowLibrary = GUICreate('TEST', 1000, 725, -1, -1, BitOR($WS_POPUP, $WS_BORDER), $WS_EX_COMPOSITED)
GUISetBkColor(0x202025, $GUI_WindowLibrary)
GUICtrlCreateLabel('TEST', 20, 5, 100, 50)
GUICtrlSetBkColor(-1, $GUI_BKCOLOR_TRANSPARENT)
GUICtrlSetColor(-1, 0xCCCCCC)
Global $GUI_WindowLibrary_ImageList = GUICtrlCreateListView('',  10, 85, 980, 300, _
                                     BitOR($LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_NOCOLUMNHEADER, $LVS_REPORT))
GUICtrlSetBkColor(-1, 0x19191A)
_GUICtrlListView_SetView($GUI_WindowLibrary_ImageList, 0)
_GUICtrlListView_SetIconSpacing($GUI_WindowLibrary_ImageList, 119, 40)
_GUICtrlListView_SetTextColor($GUI_WindowLibrary_ImageList, 0xCCCCCC)

GUICtrlCreatePic("C:\Windows\Web\Wallpaper\Windows\img19.jpg", 0, 0, 1000, 725)
GUISetState(@SW_SHOW, $GUI_WindowLibrary)

Global $GUI_WindowLibrary_LibraryThumbnailList = _GUIImageList_Create(100, 100, 5, 1)
_GUICtrlListView_SetImageList($GUI_WindowLibrary_ImageList, $GUI_WindowLibrary_LibraryThumbnailList, 0)
For $i = 0 To 30
        _GUIImageList_Add($GUI_WindowLibrary_LibraryThumbnailList, _GUICtrlListView_CreateSolidBitMap($GUI_WindowLibrary_ImageList, 0xFF0000, 100, 100))
        _GUICtrlListView_AddItem($GUI_WindowLibrary_ImageList, $i, $i)
        _GUICtrlListView_SetItemImage($GUI_WindowLibrary_ImageList, $i, $i)
;~ -------------------------------------------------------------------------------------------
    Sleep(10) ;REMOVE THIS LINE TO TEST
;~ -------------------------------------------------------------------------------------------
Next

Local $iMsg
While 1
    $iMsg = GUIGetMsg()
    Select
        Case $iMsg = $GUI_EVENT_CLOSE
            GUIDelete($GUI_WindowLibrary)
            Exit
    EndSelect
WEnd
Spoiler

With sleep:

2.jpg.1bf2a1c140eb231dc4765588ad9e425b.jpg

Without sleep:

1.jpg.0b9509d3646fa0a082adf2aa3036b713.jpg

 

Posted
5 minutes ago, Nine said:

Same as you (kind of strange). 

Well, good to know that's it's not just me and was one of the updates around 22631 because before that I never needed the sleep.

5 minutes ago, Nine said:

Also there is very big flickers when I drag the scroll bar with the left mouse (instead of scrolling with the wheel).

That is good old $WS_EX_COMPOSITED. I don't know why, but I remember giving up trying to figure that part out a while ago.

Posted

Ok I think I've found the problem with your display issue.  As explained in help file

Quote

Values for $iCX and $iCY are relative to the upper-left corner of an icon bitmap. To set spacing between icons that do not overlap, the $iCX or $iCY values must include the size of the icon, plus the amount of empty space desired between icons.  Values that do not include the width of the icon will result in overlaps.

Having set it up to :

_GUICtrlListView_SetIconSpacing($GUI_WindowLibrary_ImageList, 130, 130)

I do not need the sleep.  Still why the sleep helped ?  No idea.
 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...