Jump to content
Sign in to follow this  

Move controls within a ListView with WM_PAINT

Recommended Posts


i have covered the old ListView_Progress UDF but instead of moving the controls on WM_NOTIFY, i want to move them on WM_PAINT, cause i think i can get better performance with it, but on rezising the columns the GUI gets freezed.

Doese someone know how to avoid to get stucked?

#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#include <FontConstants.au3>
#include <GuiListView.au3>
#include <Constants.au3>
#include <WinAPIGdi.au3>
#include <ListView_Progress.au3>
#include <WinAPISys.au3>
#include <WinAPIShellEx.au3>

Opt('MustDeclareVars', 1)

Global $hGUI, $cListView, $hListView
Global $iDllUSER32 = DllOpen("user32.dll")

Global Const $ODT_LISTVIEW = 102
Global Const $ODA_DRAWENTIRE = 0x1
Global Const $ODA_SELECT = 0x2
Global Const $ODA_FOCUS = 0x4
Global Const $ODS_SELECTED = 0x0001

$hGUI = GUICreate("Set Listview Header Colour ", 500, 500)
$cListView = GUICtrlCreateListView("Items List", 10, 10, 480, 480, BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS, $WS_BORDER));, $LVS_OWNERDRAWFIXED))
$hListView = GUICtrlGetHandle($cListView)

; Register DLL callback that will be used as window subclass procedure
Global $g_hDll = DllCallbackRegister('_SubclassProc', 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
Global $g_pDll = DllCallbackGetPtr($g_hDll)

; Install window subclass callback
_WinAPI_SetWindowSubclass($hListView, $g_pDll, 1000, 0)

_SendMessage($hListView, $LVM_SETTEXTBKCOLOR, 0, 0xFFFFFF) ; trick to get better performance

For $i = 1 To 15
    GUICtrlCreateListViewItem("", $cListView)
    _ListView_InsertProgressBar($hListView, $i-1, 0) ; insert control




Func _SubclassProc($hWnd, $iMsg, $wParam, $lParam, $iID, $pData)
    #forceref $iID, $pData

    ConsoleWrite("Proc $hWnd: " & $hWnd  & " imsg: " & $iMsg & " $wParam: " & $wParam & " $lParam: " & $lParam & @CRLF)

    Switch $iMsg
        Case $WM_NCPAINT
        Case $WM_SIZE
        Case $WM_ERASEBKGND
        Case $WM_PAINT
            Local $struct
            _WinAPI_BeginPaint($hWnd, $struct)

            For $i = 1 To $aProgress[0][0]
                If $aProgress[$i][3] = $hWnd Then _
                _MoveProgress($hWnd, $aProgress[$i][0], $aProgress[$i][1], $aProgress[$i][2]) ; move controls
            _WinAPI_EndPaint($hWnd, $struct)

    Return _WinAPI_DefSubclassProc($hWnd, $iMsg, $wParam, $lParam)
EndFunc   ;==>_SubclassProc

; not used yet
Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam)
;~  ConsoleWrite("Draw   $hWnd: " & $hWnd  & " imsg: " & $Msg & " $wParam: " & $wParam & " $lParam: " & $lParam & @CRLF)
    Local $tagDRAWITEMSTRUCT, $iBrushColor, $cID, $itmID, $itmAction, $itmState, $hItm, $hDC, $bSelected
    $tagDRAWITEMSTRUCT = DllStructCreate( _
       "uint cType;" & _
       "uint cID;" & _
       "uint itmID;" & _
       "uint itmAction;" & _
       "uint itmState;" & _
       "hwnd hItm;" & _
       "handle hDC;" & _
       "long itmRect[4];" & _
       "ulong_ptr itmData" _
       , $lParam)
    If DllStructGetData($tagDRAWITEMSTRUCT, "cType") <> $ODT_LISTVIEW Then Return $GUI_RUNDEFMSG
    $cID = DllStructGetData($tagDRAWITEMSTRUCT, "cID")
    $itmID = DllStructGetData($tagDRAWITEMSTRUCT, "itmID")
    $itmAction = DllStructGetData($tagDRAWITEMSTRUCT, "itmAction")
    $itmState = DllStructGetData($tagDRAWITEMSTRUCT, "itmState")
    $hItm = DllStructGetData($tagDRAWITEMSTRUCT, "hItm")
    $hDC = DllStructGetData($tagDRAWITEMSTRUCT, "hDC")
    $bSelected = BitAND($itmState, $ODS_SELECTED)
        Switch $itmAction
            Case $ODA_DRAWENTIRE
                ; don't forget, this is BGR, not RGB
                If $itmState = $bSelected Then ; item is not selected
                    $iBrushColor = 0xCCEECC
                Else ; item is selected
                    $iBrushColor = 0xEEDDBB
                Local $aBrush = DllCall("gdi32.dll", "hwnd", "CreateSolidBrush", "int", $iBrushColor)
                Local $aBrushOld = _WinAPI_SelectObject($hDC, $aBrush[0])
                Local $iLeft = DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1)
                DllStructSetData($tagDRAWITEMSTRUCT, "itmRect", $iLeft + 1, 1) ; rectangle coordinates for coloring
                ; +1 is the left margin
                _WinAPI_FillRect($hDC, DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), $aBrush[0])
                _WinAPI_SelectObject($hDC, $aBrushOld)
                ; for all columns of the row:
                ConsoleWrite("hITm: " & $hItm & @CRLF)
                For $i = 0 To _GUICtrlListView_GetColumnCount($hItm) - 1
                    ; 1. get subitem text:
                    Local $iSubItmText = _GUICtrlListView_GetItemText($hItm, $itmID);, $i)
                    ; 2. get subitem coordinates for drawing its respective text
                    Local $aSubItmRect = _GUICtrlListView_GetSubItemRect($hItm, $itmID, $i)
                    ; the function above accepts not only subitems (one-based index), but also main item (index=0)
                    ; 3. pass the coordinates to a DLL struct
                    Local $iSubItmRect = DllStructCreate("long[4]")
                    DllStructSetData($iSubItmRect, 1, $aSubItmRect[0] + 6, 1) ; +6 is left margin (X)
                    DllStructSetData($iSubItmRect, 1, $aSubItmRect[1] + (-2), 2) ; + (-2) is upper margin (Y)
                    DllStructSetData($iSubItmRect, 1, $aSubItmRect[2], 3)
                    DllStructSetData($iSubItmRect, 1, $aSubItmRect[3], 4)
                    DllCall("user32.dll", "int", "DrawTextW", "hwnd", $hDC, "wstr", $iSubItmText, "int", StringLen($iSubItmText), _
                        "ptr", DllStructGetPtr($iSubItmRect), "int", $DT_LEFT)

EndFunc   ;==>WM_DRAWITEM


Share this post

Link to post
Share on other sites

wow thanks for this information, i never thought about a bug. But what is the solution? Do i take

Func CallWindowProc($lpPrevWndFunc, $hWnd, $Msg, $wParam, $lParam)
  Return DllCall("user32.dll", "lresult", "CallWindowProc", "ptr", $lpPrevWndFunc, "hwnd", $hWnd, "uint", $Msg, "wparam", $wParam, "lparam", $lParam)[0]

instead of _WinAPI_CallWindowProc?

And since when is it possible to access an array in this way?

Share this post

Link to post
Share on other sites

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
Sign in to follow this  

  • Create New...