Opened 11 years ago
Closed 11 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 11 years ago by Jpm
comment:2 Changed 11 years ago by Trolleule
The Problem was discussed here:
http://www.autoitscript.com/forum/topic/165109-guictrlcreatelistviewitem-and-wm-notify-bug/
comment:3 Changed 11 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 11 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 11 years ago by Jpm
I still cannot reproduce under Win8.1 update 1
comment:6 Changed 11 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 11 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