GaryC Posted January 1, 2011 Posted January 1, 2011 I am trying to catch when the user checks an item in a list view so that it can be saved in a recovery info file. I found no way to find the focused item without iterating through the list view items, so I save the current item index when I receive LVN_ITEMCHANGED with focused state. Then when LVN_KEYDOWN for SPACE occurs I change the checked state and record the state with the param of the current item. I suppress default handling. I might have been able to allow default processing and record the opposite of the checked state (NOT _GUICtrlListView_GetItemChecked()) but I thought doing it myself was safer. The problem is that most of the time the checked state doesn't change, at least not long enough to show on the screen. The exception is if I press SPACE immediately after the program starts. The following is the debug output resulting from loading the program, and pressing DownArrow twice followed by SPACE. (Why does the first DownArrow do nothing?) The SPACE should cause the current item to be checked, and according to the debug output it does, but after the following LVN_ITEMCHANGED the debug output shows it is unchecked. Can anyone tell me why that's happening?WMNotify Roster keydown key = 40LVN_ITEMCHANGED: item 0 changed, not focus, NewState = 0x00000000, Changed = 00000008 Checked = FalseLVN_ITEMCHANGED: item 0 changed, new state 00000003, Changed = 00000008 Checked = FalseWMNotify Roster keydown key = 40LVN_ITEMCHANGED: item 0 changed, not focus, NewState = 0x00000000, Changed = 00000008 Checked = FalseLVN_ITEMCHANGED: item 0 changed, not focus, NewState = 0x00000000, Changed = 00000008 Checked = FalseLVN_ITEMCHANGED: item 1 changed, new state 00000003, Changed = 00000008 Checked = FalseWMNotify Roster keydown key = 32 $giCurItem = 1 Checking LVN_KEYDOWN after checking/unchecking Item check state is TrueLVN_ITEMCHANGED: item 1 changed, not focus, NewState = 0x00001000, Changed = 00000008 Checked = False(Note: I am blind. I used a modified version of the LbC.au3 (Layout by Code) library by Jamal Mazrui to do the rough layout and then tweaked it based on coordinate information provided by my JAWS screen reader. My understanding of the checked/unchecked state of list view items is that reported by JAWS. If the layout is strange, or if there is something happening on the screen I'm not seeing, that's probably why.)expandcollapse popup#include <array.au3> #Include <GUIConstantsEx.au3> #Include <WindowsConstants.au3> #include <ListviewConstants.au3> #include <GuiListview.au3> Global Const $VK_SPACE = 0x20 Global $gIdlRoster, $gIdeMemo Global $ghForm Global $giCurItem = 0 ; index in $gIdlRoster of current item, set in WMNotify Main() Func Main() FormCreate() ; Try to make the first press of DownArrow move to the second item, but it doesn't change this, even with focused set to true. _GUICtrlListView_SetItemSelected($gIdlRoster, 0) ;Local $sDbg = LbcDbgCtrlCoords() ;ConsoleWrite($sDbg) FormExec() GUIDelete() EndFunc ;==>Main Func Dbg($sMsg) Local $iRtn = GUICtrlSetData($gIdeMemo, $sMsg & @CRLF, 1) If $iRtn <> 1 Then MsgBox(0, "Dbg", "GUICtrlSetData returned " & $iRtn & "@LFmsg = " & $sMsg) ;_lbcSay($sMsg) EndFunc ;==>Dbg ; Create the GUI. Func FormCreate() $ghForm = GUICreate("Test logging of LV check/uncheck", 600, 500) $gIdlRoster = GUICtrlCreateListView("Item ", 14, 14, 400, 300, 0x5003000D, 0x00000004) For $i = 1 To 5 Local $sItem = "Item " & $i GUICtrlCreateListViewItem($sItem, $gIdlRoster) _GUICtrlListView_SetItemParam($gIdlRoster, $i - 1, $i) ; store index Next ; $i GUICtrlCreateLabel("Memo", 14, 328, 29, 16, 0x50020100, 0x00000000) $gIdeMemo = GUICtrlCreateEdit("", 49, 328, 500, 100, 0x503110C4, 0x00000000) WinSetState($ghForm, "", @SW_MAXIMIZE) GUISetState() EndFunc ;==>FormCreate Func FormExec() GUIRegisterMsg($WM_NOTIFY, "WmNotify") While 1 Local $iMsg = GUIGetMsg() Switch $iMsg Case 0 ContinueLoop Case $GUI_EVENT_CLOSE ExitLoop EndSwitch WEnd ; main loop EndFunc ;==>FormExec Func ErrorMsg($sMsg) MsgBox(0, "Error", $sMsg) EndFunc ;==>ErrorMsg ; GUIRegisterMsg function to handle the WM_NOTIFY message. ; We want to change the checked state of the item when SPACE is pressed as the default action, ; but we want to record that the item is checked. We do it by recording the 0-based ; index of the focused item in LVN_ITEMCHANGED, then we record it and set the state ; in LVN_KEYDOWN. We also set the checked/unchecked state and avoid default ; processing, although we could reverse the test and then let the default processing change the state. Func WmNotify($hWnd, $iMsg, $iWParam, $iLParam) Local $tagNM = DllStructCreate($tagNMHdr, $iLParam) Switch DllStructGetData($tagNM, "Code") Case $LVN_KEYDOWN If DllStructGetData($tagNM, "IdFrom") = $gIdlRoster Then $tagNM = DllStructCreate($tagNMLVKEYDOWN, $iLParam) Local $iKey = DllStructGetData($tagNM, "VKEY") Dbg("WMNotify Roster keydown key = " & $iKey) ; debug If $iKey = $VK_SPACE Then Local $iCheckin = _GUICtrlListView_GetItemParam($gIdlRoster, $giCurItem) Dbg(" $giCurItem = " & $giCurItem) ; debug ; $giCurItem was set in previous LVN_ITEMCHANGED. If _GUICtrlListView_GetItemChecked($gIdlRoster, $giCurItem) Then Dbg(" unchecking") ; debug _GUICtrlListView_SetItemChecked($gIdlRoster, $giCurItem, False) CheckinRemove($iCheckin) Else Dbg(" Checking") ; debug _GUICtrlListView_SetItemChecked($gIdlRoster, $giCurItem, True) CheckinAdd($iCheckin) EndIf ; checked ; Checked state is shown to be changed here. Dbg(" LVN_KEYDOWN after checking/unchecking Item check state is " & _GUICtrlListView_GetItemChecked($gIdlRoster, $giCurItem)) ; debug Return 0 ; suppress normal message handling ;Return $GUI_RUNDEFMSG ; debug EndIf ; if $VK_SPACE EndIf ; if lRoster Case $LVN_ITEMCHANGED If DllStructGetData($tagNM, "IdFrom") = $gIdlRoster Then $tagNM = DllStructCreate($tagNMLISTVIEW, $iLParam) If BitAND(DllStructGetData($tagNM, "NewState"), $LVIS_FOCUSED) Then ; We get here when we arrow up/down to the item. ; remember the item in this event. $giCurItem = DllStructGetData($tagNM, "Item") Dbg("LVN_ITEMCHANGED: item " & $giCurItem & " changed, new state " & Hex(DllStructGetData($tagNM, "NewState")) & ", Changed = " & Hex(DllStructGetData($tagNM, "Changed"))) ; debug Dbg(" Checked = " & _GUICtrlListView_GetItemChecked($gIdlRoster, $giCurItem)) ; debug Else ; debug Dbg("LVN_ITEMCHANGED: item " & $giCurItem & " changed, not focus, NewState = 0x" & Hex(DllStructGetData($tagNM, "NewState")) & ", Changed = " & Hex(DllStructGetData($tagNM, "Changed"))) ; debug Dbg(" Checked = " & _GUICtrlListView_GetItemChecked($gIdlRoster, $giCurItem)) ; debug EndIf ; else not focused Return $GUI_RUNDEFMSG ; do normal message handling EndIf ; if lRoster EndSwitch ; code EndFunc ;==>WmNotify ; Add a checkin to the list of checkins. ; $iCheckin - Identifier of checkin record (Index in $gaRoster of checkin or $gciNewCheckinFirst + index in $gaNewCheckins). ; Updates globals $gaCheckins, $gaNewCheckins. Func CheckinAdd($iCheckin) EndFunc ;==>CheckinAdd ; Updates globals $gaCheckins, $gaNewCheckins. Func CheckinRemove($iCheckin) EndFunc ;==>CheckinRemoveThanks.GaryC
Zedna Posted January 1, 2011 Posted January 1, 2011 (edited) Look hereYou were very close ;-)LVN_KEYDOWN logic is not neccessary hereEDIT:In my scripts where I need to react on change of checked/unchecked state in listview I use it like this:... If $hWndGUI = $Form1 And $wParam = $ListView1 And $disable_refresh_status = False Then If $event = $LVN_ITEMCHANGED Then $NMLISTVIEW = DllStructCreate($tagNMLISTVIEW, $lParam) If BitAND(DllStructGetData($NMLISTVIEW, "Changed"), $LVIF_STATE) = $LVIF_STATE And _ DllStructGetData($NMLISTVIEW, "NewState") <> DllStructGetData($NMLISTVIEW, "OldState") Then RefreshStatusBar() EndIf EndIf ...in Func RefreshStatusBar() I go through listview items and call _GUICtrlListView_GetItemChecked($ListView1, $i)to check number of checked items and show this number in statusbar Edited January 1, 2011 by Zedna Resources UDF ResourcesEx UDF AutoIt Forum Search
GaryC Posted January 25, 2011 Author Posted January 25, 2011 Thanks, Zedna. I ended up using something like you suggested. I use LVN_ITEMCHANGED. The trick is that checked and unchecked appear as state images in this notification. (This is extracted from working code but this sample doesn't stand alone.) #include <GUIConstantsEx.au3> #include <ListviewConstants.au3> #include <structureConstants.au3> Global Const $LVIS_CHECKED = 0x2000 ; list view item checked Global Const $LVIS_UNCHECKED = 0x1000 ; .... Func WmNotify($hWnd, $iMsg, $iWParam, $iLParam) Local $tagNM = DllStructCreate($tagNMHDR, $iLParam) Switch DllStructGetData($tagNM, "Code") Case $LVN_ITEMCHANGED If DllStructGetData($tagNM, "IdFrom") = $gIdlRoster Then $tagNM = DllStructCreate($tagNMLISTVIEW, $iLParam) Local $iCheckedState = BitAND(DllStructGetData($tagNM, "NewState"), $LVIS_STATEIMAGEMASK) ; state image index * 0x1000 If $iCheckedState Then $giCurItem = DllStructGetData($tagNM, "Item") Local $fChecked = ($iCheckedState = $LVIS_CHECKED) Local $fUnChecked = ($iCheckedState = $LVIS_UNCHECKED) EndIf ; $iCheckedState EndIf ; IDFrom EndSwitch EndFunc ;==>WmNotify I'm not testing that newstate is different from oldstate, or testing the member indicating what has changed, but it seems to work for my application. Gary
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