mpower Posted November 7, 2013 Posted November 7, 2013 (edited) Basically I have a gui with a listview where items are highlighted in different colours (using NM_CUSTOMDRAW) and the listview columns are auto-sized when the gui is resized (using WM_SIZE). The problem I have is that every time i resize the gui its super slow because the listview items are re-drawn using NM_CUSTOMDRAW every time the gui and subsequently the listview columns are resized. Is there any way to turn of NM_CUSTOMDRAW after the initial draw? or is each cell required to be re-drawn when resizing columns/listview? Here is a reproducer, click the Populate button to fill the listview. Notice how it doesnt colour in the whole row correctly until you resize and when you resize its very choppy/slow/flickery. expandcollapse popup#include-once #NoTrayIcon #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include <Misc.au3> #Include <Array.au3> #Include <GuiListView.au3> Global $Font1 = _WinAPI_CreateFont(14, 0, 0, 0, $FW_BOLD) Global $Font2 = _WinAPI_CreateFont(14, 0, 0, 0, $FW_NORMAL, False, False, False, $DEFAULT_CHARSET, $OUT_DEFAULT_PRECIS, _ $CLIP_DEFAULT_PRECIS, $DEFAULT_QUALITY, 0, "MS Sans Serif") #Region ### START $maingui ### $maingui = GUICreate("Example", 860, 730, @DesktopWidth/2 - 860/2, @DesktopHeight/2 - 700/2, BitOR($WS_SIZEBOX, $WS_TABSTOP, $WS_MINIMIZEBOX, $WS_CLIPCHILDREN)) GUISetBkColor(0xFFFFFF, $maingui) $maingui_lv = _GUICtrlListView_Create($maingui, "", 0, 0, 860, 480, BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS)) _GUICtrlListView_SetExtendedListViewStyle($maingui_lv, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES, $LVS_EX_CHECKBOXES, $LVS_EX_INFOTIP, $LVS_EX_DOUBLEBUFFER)) _GUICtrlListView_AddColumn($maingui_lv, "Column 1", 100) _GUICtrlListView_AddColumn($maingui_lv, "Column 2", 100) _GUICtrlListView_AddColumn($maingui_lv, "Column 3", 100) _GUICtrlListView_AddColumn($maingui_lv, "Column 4", 100) _GUICtrlListView_AddColumn($maingui_lv, "Column 5", 100) _GUICtrlListView_AddColumn($maingui_lv, "Column 6", 100) _GUICtrlListView_AddColumn($maingui_lv, "Column 7", 100) _GUICtrlListView_AddColumn($maingui_lv, "Column 8", 100) $maingui_bn_populate = GUICtrlCreateButton("Populate", 10, 10, 100, 25) GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUIRegisterMsg($WM_COMMAND, "WM_COMMAND") GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUIRegisterMsg($WM_GETMINMAXINFO, "_WM_GETMINMAXINFO") GUISetState() #EndRegion ### END $maingui ### While 1 $msg = GUIGetMsg(1) Switch $msg[1] Case $maingui Switch $msg[0] Case $GUI_EVENT_CLOSE Exit Case $maingui_bn_populate Populate() EndSwitch EndSwitch WEnd Func Populate() For $a = 1 To 10 If $a = 5 or $a = 6 or $a = 10 Then _GUICtrlListView_AddItem($maingui_lv, "Test" & $a) $added = _GUICtrlListView_GetItemCount($maingui_lv) - 1 _GUICtrlListView_AddSubItem($maingui_lv, $added, "Wrong", 1) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 2) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 3) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 4) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 5) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 6) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 7) ElseIf $a = 2 or $a = 7 or $a = 8 Then _GUICtrlListView_AddItem($maingui_lv, "Test" & $a) $added = _GUICtrlListView_GetItemCount($maingui_lv) - 1 _GUICtrlListView_AddSubItem($maingui_lv, $added, "Right", 1) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 2) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 3) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 4) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 5) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 6) _GUICtrlListView_AddSubItem($maingui_lv, $added, "0", 7) Else _GUICtrlListView_AddItem($maingui_lv, "Test" & $a) $added = _GUICtrlListView_GetItemCount($maingui_lv) - 1 _GUICtrlListView_AddSubItem($maingui_lv, $added, "Right", 1) _GUICtrlListView_AddSubItem($maingui_lv, $added, "1", 2) _GUICtrlListView_AddSubItem($maingui_lv, $added, "1", 3) _GUICtrlListView_AddSubItem($maingui_lv, $added, "1", 4) _GUICtrlListView_AddSubItem($maingui_lv, $added, "1", 5) _GUICtrlListView_AddSubItem($maingui_lv, $added, "1", 6) _GUICtrlListView_AddSubItem($maingui_lv, $added, "1", 7) EndIf Next GUICtrlSetState($maingui_bn_populate, $GUI_DISABLE) EndFunc Func WM_SIZE($hWnd, $Msg, $wParam, $lParam) ;resize columns with gui resize Local $iHeight, $iWidth $iWidth = BitAND($lParam, 0xFFFF) ; _WinAPI_LoWord $iHeight = BitShift($lParam, 16) ; _WinAPI_HiWord _GUICtrlListView_BeginUpdate($maingui_lv) GuiSetState(@SW_LOCK, $maingui) WinMove($maingui_lv, "", 0, 0, $iWidth, $iHeight - 70) $jWidth = $iWidth - 140 _GUICtrlListView_SetColumnWidth($maingui_lv, 0, $jWidth*0.15) _GUICtrlListView_SetColumnWidth($maingui_lv, 1, $jWidth*0.20) _GUICtrlListView_SetColumnWidth($maingui_lv, 2, $jWidth*0.05) _GUICtrlListView_SetColumnWidth($maingui_lv, 3, $jWidth*0.125) _GUICtrlListView_SetColumnWidth($maingui_lv, 4, $jWidth*0.125) _GUICtrlListView_SetColumnWidth($maingui_lv, 5, $jWidth*0.125) _GUICtrlListView_SetColumnWidth($maingui_lv, 6, $jWidth*0.125) _GUICtrlListView_SetColumnWidth($maingui_lv, 7, -2) GUICtrlSetPos($maingui_bn_populate, $jWidth, $iHeight - 50) GuiSetState(@SW_UNLOCK, $maingui) _GUICtrlListView_EndUpdate($maingui_lv) Return $GUI_RUNDEFMSG EndFunc Func _WM_GETMINMAXINFO($hwnd, $Msg, $wParam, $lParam) ;lock gui min size If $hWnd = $maingui Then $tagMaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam) DllStructSetData($tagMaxinfo, 7, 617.6) ; W (min size) DllStructSetData($tagMaxinfo, 8, 744) ; H (min size) Return 0 EndIf EndFunc ;==>WM_GETMINMAXINFO Func WM_NOTIFY($hWnd, $Msg, $wParam, $lParam) Local $tNMHDR, $hWndFrom, $iCode $tNMHDR = DllStructCreate($tagNMHDR, $lParam) $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom") $iCode = DllStructGetData($tNMHDR, "Code") Switch $hWndFrom Case $maingui_lv Switch $iCode Case $NM_CUSTOMDRAW Local $tCustDraw = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam) Local $iDrawStage = DllStructGetData($tCustDraw, "dwDrawStage") Local $iSubItem = DllStructGetData($tCustDraw, "iSubItem") Local $iItem = DllStructGetData($tCustDraw, "dwItemSpec") Local $iColor, $hDC Switch $iDrawStage Case $CDDS_PREPAINT Return $CDRF_NOTIFYITEMDRAW ;request custom drawing of items Case $CDDS_ITEMPREPAINT Return $CDRF_NOTIFYSUBITEMDRAW ;request drawing each cell separately Case Else $hDC = DllStructGetData($tCustDraw, "hdc") If _GUICtrlListView_GetItemText($maingui_lv, $iItem, 1) = "Wrong" Then $iColor = RGB2BGR(0xFF0000) _WinAPI_SelectObject($hDC, $Font1) DllStructSetData($tCustDraw, "clrText", $iColor) ElseIf _GUICtrlListView_GetItemText($maingui_lv, $iItem, 3) = "0" OR _GUICtrlListView_GetItemText($maingui_lv, $iItem, 4) = "0" OR _GUICtrlListView_GetItemText($maingui_lv, $iItem, 5) = "0" OR _GUICtrlListView_GetItemText($maingui_lv, $iItem, 7) = "0" Then $iColor = RGB2BGR(0x000000) _WinAPI_SelectObject($hDC, $Font2) DllStructSetData($tCustDraw, "clrText", $iColor) DllStructSetData($tCustDraw, "clrTextBk", RGB2BGR(0xFFFF80)) EndIf Return $CDRF_NEWFONT EndSwitch Case $LVN_ENDSCROLL _WinAPI_InvalidateRect($maingui_lv) EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Func RGB2BGR($iColor) Return BitAND(BitShift(String(Binary($iColor)), 8), 0xFFFFFF) EndFunc ;==>RGB2BGR() Edited November 7, 2013 by mpower
LarsJ Posted November 7, 2013 Posted November 7, 2013 mpower, If you add_GUICtrlListView_BeginUpdate($maingui_lv) _GUICtrlListView_EndUpdate($maingui_lv)statements around your populate loop the rows will be drawn properly.If you don't use these statements a row will be drawn cell by cell. And for the first few cells in each row there is no information to draw the cells with a yellow background. The first test to draw a row with yellow background is in column 4:ElseIf _GUICtrlListView_GetItemText($maingui_lv, $iItem, 3) = "0" ...If you fill out the entire LV before you draw it, all information is available.You can create the LV with the built-in command GUICtrlCreateListView. Then you can use GUICtrlSetResizing to resize the LV. Move most of the code from WM_SIZE function to the message loop:Case $GUI_EVENT_RESTORE, $GUI_EVENT_MAXIMIZE, $GUI_EVENT_RESIZED ...Then you don't need the WM_SIZE function and the resize will be much better.You should consider to fill out the LV with GUICtrlCreateListViewItem. This is much faster than using the UDF.In the $NM_CUSTOMDRAW code you should not use slow UDF functions. Use an array to provide information for custom drawing. See post 7 here. Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now