mpower Posted November 7, 2013 Share 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 Link to comment Share on other sites More sharing options...
LarsJ Posted November 7, 2013 Share 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 Link to comment Share on other sites More sharing options...
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