Opened 10 years ago
Closed 10 years ago
#2927 closed Bug (Works For Me)
Adding Items with GUICtrlCreateListViewItem will cause GUI freeze if a subitem is empty
Reported by: | Trolleule | Owned by: | |
---|---|---|---|
Milestone: | Component: | AutoIt | |
Version: | 3.3.12.0 | Severity: | None |
Keywords: | GUICtrlCreateListViewItem, WM_NOTIFY, WM_DRAWITEM | Cc: |
Description
When i add listview items with GUICtrlCreateListViewItem to an ownerdraw listview control and there is a empty subitem in the subitem chain and WM_NOTIFY is present, the LV control freezes. Adding items with UDF works.
I noticed that even when the display of the LV is frozen, the WM_NOTIFY function is still active and responding. I put a consolewrite in the WM_NOTIFY function and could see writing after the listview display froze. Surprisingly, minimizing the GUI unfreezes the listview and all controls on the GUI.
#include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <ColorConstants.au3> 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 Global $GUI_main = GUICreate("", 300, 300, -1, -1) Global $hGUI_tab_listview[2][10] $hGUI_tab_listview[0][0] = GUICtrlCreateListView("A|B|C", 15, 10, 250, 280, _ BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS, $LVS_OWNERDRAWFIXED, $WS_BORDER, $WS_CLIPCHILDREN), 0) ; + $LVS_EX_CHECKBOXES + $LVS_SINGLESEL _GUICtrlListView_SetExtendedListViewStyle($hGUI_tab_listview[0][0], $LVS_EX_DOUBLEBUFFER) For $i = 0 To 50 ;~ _GUICtrlListView_AddItem(-1, "test " & $i) ;~ _GUICtrlListView_AddSubItem(-1, $i, $i, 1) If $i = 5 Then GUICtrlCreateListViewItem("|" & "sdfdsfs" & "|" & "", $hGUI_tab_listview[0][0]) ; if empty slot is present, gui gets freezed ; comment this lines out for check ContinueLoop EndIf GUICtrlCreateListViewItem("|" & "sdfdsfs" & "|" & $i, $hGUI_tab_listview[0][0]) Next GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUISetState(@SW_SHOW) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idOK ExitLoop EndSwitch WEnd Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam) 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 $cID ; will look for ControlID, not window handle. Case $hGUI_tab_listview[0][0] Switch $itmAction Case $ODA_DRAWENTIRE ; don't forget, this is BGR, not RGB If $itmState = $bSelected Then ; item is not selected $iBrushColor = 0xEEDDBB Else ; item is selected $iBrushColor = $COLOR_RED EndIf Local $aBrush = _WinAPI_CreateSolidBrush($iBrushColor) Local $aBrushOld = _WinAPI_SelectObject($hDC, $aBrush) 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) _WinAPI_SelectObject($hDC, $aBrushOld) _WinAPI_DeleteObject($aBrush) ; for all columns of the row: $local_alignment = $DT_LEFT For $i = 0 To _GUICtrlListView_GetColumnCount($hGUI_tab_listview[0][0]) - 1 ; 1. get subitem text: Local $iSubItmText = _GUICtrlListView_GetItemText($hGUI_tab_listview[0][0], $itmID, $i) ; If $iSubItmText = "" Then ContinueLoop ;ConsoleWrite("hier") ; 2. get subitem coordinates for drawing its respective text Local $aSubItmRect = _GUICtrlListView_GetSubItemRect($hGUI_tab_listview[0][0], $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) _WinAPI_SetTextColor($hDC, $COLOR_RED) DllCall("user32.dll", "int", "DrawTextW", "hwnd", $hDC, "wstr", $iSubItmText, "int", StringLen($iSubItmText), _ "ptr", DllStructGetPtr($iSubItmRect), "int", $local_alignment) Next ;#ce EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>WM_DRAWITEM
Attachments (0)
Change History (7)
comment:1 Changed 10 years ago by Jpm
comment:2 Changed 10 years ago by Trolleule
The Problem was discussed here:
http://www.autoitscript.com/forum/topic/165109-guictrlcreatelistviewitem-and-wm-notify-bug/
comment:3 Changed 10 years ago by Melba23
Trolleule,
And as discussed in that thread I cannot make the GUI freeze other then by resizing the columns - which I fixed by amending the redraw process. Certainly scrolling the ListView does not induce a freeze in either 3.3.12.0 or 3.3.13.19, Win7 x32.
M23
comment:4 Changed 10 years ago by Trolleule
There is definitive a bug. Look what BrewManNH has written. When i scroll with mouse fast up and down more than one time, anytime the listview/ gui freeze and the LV becomes empty. Minimizing and Maximizing restores the LV. If you uncomment WM_NOTIFY registering, it works fine. Using Win7 x86.
Use this example, this will avoid missunderstandings:
#include <GuiListView.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <ColorConstants.au3> 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 Global $GUI_main = GUICreate("", 300, 300, -1, -1) Global $idLV = GUICtrlCreateListView("A|B|C", 15, 10, 250, 280, _ BitOR($LVS_REPORT, $LVS_SHOWSELALWAYS, $LVS_OWNERDRAWFIXED, $WS_BORDER, $WS_CLIPCHILDREN), -1) ; + $LVS_EX_CHECKBOXES + $LVS_SINGLESEL ;~ _GUICtrlListView_SetExtendedListViewStyle($idLV, $LVS_EX_DOUBLEBUFFER) For $i = 0 To 50 ;~ _GUICtrlListView_AddItem(-1, "test " & $i) ;~ _GUICtrlListView_AddSubItem(-1, $i, $i, 1) If $i = 5 Then GUICtrlCreateListViewItem("|" & "" & "|" & "", $idLV) ; if empty slot is present, gui gets freezed ; comment this lines out for check ContinueLoop EndIf GUICtrlCreateListViewItem("|" & "sdfdsfs" & "|" & $i, $idLV) Next GUIRegisterMsg($WM_DRAWITEM, "WM_DRAWITEM") GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") GUISetState(@SW_SHOW) ; Loop until the user exits. While 1 Switch GUIGetMsg() Case $GUI_EVENT_CLOSE, $idOK ExitLoop EndSwitch WEnd Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) Return $GUI_RUNDEFMSG EndFunc ;==>WM_NOTIFY Func WM_DRAWITEM($hWnd, $Msg, $wParam, $lParam) Local $tagDRAWITEMSTRUCT, $iBrushColor, $cID, $itmID, $itmAction, $itmState, $hItm, $hDC, $bSelected $tagDRAWITEMSTRUCT = DllStructCreate("uint cType;uint cID;uint itmID;uint itmAction;uint itmState;" & _ "hwnd hItm;hwnd hDC;int itmRect[4];dword 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 If $itmState = $bSelected Then $iBrushColor = 0xFFFFFF Else $iBrushColor = 0x0000FF EndIf 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 + 5, 1) _WinAPI_FillRect($hDC, DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), $aBrush[0]) _WinAPI_SelectObject($hDC, $aBrushOld) _WinAPI_DeleteObject($aBrush[0]) Local $itmText = _GUICtrlListView_GetItemText($hItm, $itmID) DllStructSetData($tagDRAWITEMSTRUCT, "itmRect", DllStructGetData($tagDRAWITEMSTRUCT, "itmRect", 1) + 2, 1) DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $itmText, "int", StringLen($itmText), _ "ptr", DllStructGetPtr($tagDRAWITEMSTRUCT, "itmRect"), "int", $DT_LEFT) Local $iSubItmText = _GUICtrlListView_GetItemText($hItm, $itmID, 1) Local $aSubItmRect = _GUICtrlListView_GetSubItemRect($hItm, $itmID, 1) Local $iSubItmRect = DllStructCreate("int[4]") DllStructSetData($iSubItmRect, 1, $aSubItmRect[0], 1) DllStructSetData($iSubItmRect, 1, $aSubItmRect[1], 2) DllStructSetData($iSubItmRect, 1, $aSubItmRect[2], 3) DllStructSetData($iSubItmRect, 1, $aSubItmRect[3], 4) DllCall("user32.dll", "int", "DrawText", "hwnd", $hDC, "str", $iSubItmText, "int", StringLen($iSubItmText), _ "ptr", DllStructGetPtr($iSubItmRect), "int", $DT_LEFT) EndSwitch Return $GUI_RUNDEFMSG EndFunc
comment:5 Changed 10 years ago by Jpm
I still cannot reproduce under Win8.1 update 1
comment:6 Changed 10 years ago by Melba23
Trolleule,
I made that code crash just once in multiple attempts and when it did it was obvious that the problem lies in the redrawing as the ListView continued to scroll but was gradually emptied of its contents. So I think that rather than having found an AutoIt bug you have a serious problem in your WM_DRAWITEM handler and you should return to the forum and seek advice.
M23
comment:7 Changed 10 years ago by Jpm
- Resolution set to Works For Me
- Status changed from new to closed
I agree with M23 remark your WM_DRAWITEM has a pb so go to the forum to get help to locate it
I will close it
Just reopen a new one if you really islotae the pb.
Cheers
Guidelines for posting comments:
- You cannot re-open a ticket but you may still leave a comment if you have additional information to add.
- In-depth discussions should take place on the forum.
For more information see the full version of the ticket guidelines here.
I don't see any freeze Under my Windows8.1
Mixing UDF and standard AutoIt GUI is not a great idea specialy trying to register message.
some time no conflict sometime conflict as 2 separate handling without any communication between them