Info Posted July 16, 2011 Posted July 16, 2011 (edited) How do I get the menu item that the user selected if $iNotify is set to 1 for "Do not send notification messages"? Edited July 16, 2011 by Info
martin Posted July 16, 2011 Posted July 16, 2011 How do I get the menu item that the user selected if $iNotify is set to 1 for "Do not send notification messages"?If you do not want a notification to be sent then you would set $iNotify to 1 or 3. But you would need to use 3 rather than 1 because then the id of the menu item is returned by the function. Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Info Posted July 16, 2011 Author Posted July 16, 2011 Perhaps this isn't what I'm looking for. Here's my code Switch _GUICtrlMenu_TrackPopupMenu($hMenu, $Listview, -1, -1, 1, 1, 1) Case 1 _Func1() Case 2 _Func2() Case 3 _Func3() EndSwitch I create this PopupMenu when the user right clicks a Listview control. The problem is that the listview gets stuck until one of those functions (_Func1/2/3) finishes executing. What can I do?
rover Posted July 17, 2011 Posted July 17, 2011 (edited) Perhaps this isn't what I'm looking for. Here's my code Switch _GUICtrlMenu_TrackPopupMenu($hMenu, $Listview, -1, -1, 1, 1, 1) Case 1 _Func1() Case 2 _Func2() Case 3 _Func3() EndSwitch I create this PopupMenu when the user right clicks a Listview control. The problem is that the listview gets stuck until one of those functions (_Func1/2/3) finishes executing. What can I do? Are you running _GUICtrlMenu_TrackPopupMenu() in WM_NOTIFY or in WM_CONTEXTMENU? Read notes for GuiRegisterMsg() about not using blocking functions in a message handler You need to return from _GUICtrlMenu_TrackPopupMenu() and run functions from your main loop or on-event mode Here are two methods of implementing a contextmenu on a listview that return to the message loop after item selection and use hit testing. Contextmenu positioning on a control is all about hit testing. You need hit testing so the contextmenu does not popup over non-item elements of the listview. (header, blank areas, checkbox, icon) I posted an example in this thread of a contextmenu for a listview that includes hit testing and the ability to have a customized contextmenu per listview group or item. There are several ways to use a contextmenu. You can use the native contextmenu to run functions on event or from loop or use the UDF version or mix the UDFcommands with the native menu as we do here with _GUICtrlMenu_TrackPopupMenu() For the returned selected menu item you can use the messages WM_COMMAND or WM_MENUCOMMAND to get notifications from _GUICtrlMenu_TrackPopupMenu() or use the direct returned selected menu id from _GUICtrlMenu_TrackPopupMenu() in WM_CONTEXTMENU This is why the sometimes suggested method of sending a WM_COMMAND message with a menu item index to an external program to run one of its menu functions without having to show the menu and do a menu mouseclick will not work, because a contextmenu can be implemented using a method other than WM_COMMAND. Here are two examples, one uses hit testing in the WM_NOTIFY message handler using the NM_RCLICK notification, the other does the hit test in WM_CONTEXTMENU Both examples include optional keyboard Menu AppKey and Shift-F10 support Edit: verbiage Edit2: Changed the header size code in 1st example WM_CONTEXTMENU method expandcollapse popup#include <GuiListView.au3> #include <WindowsConstants.au3> #include <GuiConstantsEx.au3> #include <GuiMenu.au3> Opt('MustDeclareVars', 1) Global $hLv, $hLVCM Local $hGui, $msg, $cLv, $cLVCM, $cMenu1, $a, $b, $c $hGui = GUICreate('ListView ContextMenu', 410, 300, -1, -1) $cLv = GUICtrlCreateListView('List of Items', 5, 5, 400, 290) $hLv = GUICtrlGetHandle($cLv) ;get listview handle from control ID _GUICtrlListView_SetExtendedListViewStyle($cLv, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT)) _GUICtrlListView_SetColumnWidth($cLv, 0, 396) For $i = 1 To 150 GUICtrlCreateListViewItem('ITEM ' & $i, $cLv) Next ;Create a dummy parent for the listview contextmenu menu so it will not popup on right click ;unless shown with _GUICtrlMenu_TrackPopupMenu() $cMenu1 = GUICtrlCreateDummy() $cLVCM = GUICtrlCreateContextMenu($cMenu1) $hLVCM = GUICtrlGetHandle(-1) $a = GUICtrlCreateMenuItem('LV Menu Item 1', $cLVCM) $b = GUICtrlCreateMenuItem('LV Menu Item 2', $cLVCM) $c = GUICtrlCreateMenuItem('LV Menu Item 3', $cLVCM) GUIRegisterMsg($WM_CONTEXTMENU, "_WM_CONTEXTMENU") GUISetState(@SW_SHOW) While 1 $msg = GUIGetMsg() Switch $msg Case 0 Case $a ConsoleWrite("+ LV Menu Item 1" & @CRLF) Case $b ConsoleWrite("- LV Menu Item 2" & @CRLF) Case $c ConsoleWrite("> LV Menu Item 3" & @CRLF) Case -3 GUIDelete($hGui) Exit EndSwitch WEnd Func _WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam Switch $wParam Case $hLv ;bypass other contextmenus ;If $lParam = -1 Then Return $GUI_RUNDEFMSG ;option: ignore menu appkey/Shift-F10 Local $iRet, $iX, $iY, $aSel, $aPos, $iIdx, $tpoint, $fSysMenu = False If $lParam = -1 Then ;Keyboard: Menu Appkey/Shift-F10 ;get last selected item (if one or more selected by keyboard)) $aSel = _GUICtrlListView_GetSelectedIndices($wParam, True) If @error Or UBound($aSel) <= 1 Then Return $GUI_RUNDEFMSG If $aSel[$aSel[0]] = -1 Then Return $GUI_RUNDEFMSG $iIdx = $aSel[$aSel[0]] $aPos = _GUICtrlListView_GetItemPosition($wParam, $iIdx) $tpoint = DllStructCreate("int X;int Y") DllStructSetData($tpoint, "X", $aPos[0]) DllStructSetData($tpoint, "Y", $aPos[1]) _WinAPI_ClientToScreen($wParam, $tPoint) $iX = DllStructGetData($tpoint, "X") $iY = DllStructGetData($tpoint, "Y") $fSysMenu = True Else ;mouse right click on listview item $iX = BitAND($lParam, 0x0000FFFF) $iY = BitShift($lParam, 16) ;convert Screen to Client coordinates $tpoint = DllStructCreate("int X;int Y") DllStructSetData($tpoint, "X", $iX) DllStructSetData($tpoint, "Y", $iY) _WinAPI_ScreenToClient($wParam, $tpoint) Local $iYPos1 = DllStructGetData($tPoint, "Y") ;WM_NOTIFY NM_RCLICK notification is not sent for right clicks on header, ;so when using WM_CONTEXTMENU only, we have to check before hit test if click is on header ;by checking if Y position is less than the header height Local $tRect = DllStructCreate($tagRECT) Local $hHeader = _SendMessage($wParam, $LVM_GETHEADER, 0, 0, 0, "wparam", "lparam", "hwnd") $iRet = _SendMessage($hHeader, $HDM_GETITEMRECT, 0, DllStructGetPtr($tRect), 0, "wparam", "ptr") If @error Or $iRet < 0 Then Return $GUI_RUNDEFMSG Local $iYPos2 = DllStructGetData($tRect, "Bottom")-1 If $iYPos2 <0 Then Return $GUI_RUNDEFMSG If $iYPos1 <= $iYPos2 Then Return $GUI_RUNDEFMSG ;Do ListView HitTest Local $tTest = DllStructCreate($tagLVHITTESTINFO) DllStructSetData($tTest, "X", DllStructGetData($tPoint, "X")) DllStructSetData($tTest, "Y", $iYPos1) $iRet = _SendMessage($wParam, $LVM_HITTEST, 0, DllStructGetPtr($tTest)) If @error Or $iRet = -1 Then Return $GUI_RUNDEFMSG ; -1 = not on lv item, otherwise returns index Switch DllStructGetData($tTest, "Flags") Case $LVHT_ONITEMICON, $LVHT_ONITEMLABEL, $LVHT_ONITEM ;hit was on item icon or 1st column item or subitem $fSysMenu = True EndSwitch EndIf If $iX >= 0 And $iY >= 0 Then ;pop the listview contextmenu If $fSysMenu = True And _GUICtrlMenu_IsMenu($hLVCM) = 1 Then _GUICtrlMenu_TrackPopupMenu($hLVCM, $hWnd, $iX, $iY, 1, 1, 1) Return True EndIf EndIf EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>_WM_CONTEXTMENU WM_NOTIFY, WM_CONTEXTMENU method expandcollapse popup#include <GuiListView.au3> #include <WindowsConstants.au3> #include <GuiConstantsEx.au3> #include <GuiMenu.au3> Opt('MustDeclareVars', 1) Global $hLv, $hLVCM, $fSysMenu = False ;globals required for _WM_NOTIFY() and _WM_CONTEXTMENU() Local $hGui, $cLv, $msg, $cLVCM, $cMenu1, $a, $b, $c $hGui = GUICreate('ListView ContextMenu', 410, 300, -1, -1) $cLv = GUICtrlCreateListView('List of Items', 5, 5, 400, 290) $hLv = GUICtrlGetHandle($cLv) ;get listview handle from control ID _GUICtrlListView_SetExtendedListViewStyle($cLv, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT)) _GUICtrlListView_SetColumnWidth($cLv, 0, 396) For $i = 1 To 15 GUICtrlCreateListViewItem('ITEM ' & $i, $cLv) Next ;Create a dummy parent for the listview contextmenu menu so it will not popup on right click ;unless shown with _GUICtrlMenu_TrackPopupMenu() $cMenu1 = GUICtrlCreateDummy() $cLVCM = GUICtrlCreateContextMenu($cMenu1) $hLVCM = GUICtrlGetHandle(-1) $a = GUICtrlCreateMenuItem('LV Menu Item 1', $cLVCM) $b = GUICtrlCreateMenuItem('LV Menu Item 2', $cLVCM) $c = GUICtrlCreateMenuItem('LV Menu Item 3', $cLVCM) GUIRegisterMsg($WM_NOTIFY, "_WM_NOTIFY") GUIRegisterMsg($WM_CONTEXTMENU, "_WM_CONTEXTMENU") GUISetState(@SW_SHOW) While 1 $msg = GUIGetMsg() Switch $msg Case 0 Case $a ConsoleWrite("+ LV Menu Item 1" & @CRLF) Case $b ConsoleWrite("- LV Menu Item 2" & @CRLF) Case $c ConsoleWrite("> LV Menu Item 3" & @CRLF) Case -3 GUIDelete($hGui) Exit EndSwitch WEnd Func _WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam) #forceref $hWnd, $iMsg, $wParam, $lParam Switch $wParam Case $hLv ;bypass other contextmenus ;If $lParam = -1 Then Return $GUI_RUNDEFMSG ;option: ignore menu appkey/Shift-F10 Local $iRet, $iX, $iY, $aSel, $aPos, $iIdx, $tpoint;, $fSysMenu = False If $lParam = -1 Then ;Keyboard: Menu Appkey/Shift-F10 ;get last selected item (if one or more selected by keyboard)) $aSel = _GUICtrlListView_GetSelectedIndices($wParam, True) If @error Or UBound($aSel) <= 1 Then Return $GUI_RUNDEFMSG If $aSel[$aSel[0]] = -1 Then Return $GUI_RUNDEFMSG $iIdx = $aSel[$aSel[0]] $aPos = _GUICtrlListView_GetItemPosition($wParam, $iIdx) $tpoint = DllStructCreate("int X;int Y") DllStructSetData($tpoint, "X", $aPos[0]) DllStructSetData($tpoint, "Y", $aPos[1]) _WinAPI_ClientToScreen($wParam, $tPoint) $iX = DllStructGetData($tpoint, "X") $iY = DllStructGetData($tpoint, "Y") $fSysMenu = True Else ;mouse right click on listview item $iX = BitAND($lParam, 0x0000FFFF) $iY = BitShift($lParam, 16) EndIf If $iX >= 0 And $iY >= 0 Then ;pop the listview contextmenu If $fSysMenu = True And _GUICtrlMenu_IsMenu($hLVCM) = 1 Then _GUICtrlMenu_TrackPopupMenu($hLVCM, $hWnd, $iX, $iY, 1, 1, 1) $fSysMenu = False Return True EndIf EndIf EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>_WM_CONTEXTMENU Func _WM_NOTIFY($hWnd, $Msg, $wParam, $lParam) #forceref $hWnd, $Msg, $wParam Local $tNMHDR, $hWndFrom, $iCode $tNMHDR = DllStructCreate($tagNMHDR, $lParam) $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom")) $iCode = DllStructGetData($tNMHDR, "Code") Local $IDFrom = DllStructGetData($tNMHDR, "IDFrom") Switch $IDFrom Case $cLv Switch $iCode Case $NM_RCLICK ; determine if right click on an item Local $tInfox = DllStructCreate($tagNMITEMACTIVATE, $lParam) If @error Then Return $GUI_RUNDEFMSG Local $Item = DllStructGetData($tInfox, "Index") If @error Or $Item = -1 Then Return $GUI_RUNDEFMSG Local $tTest = DllStructCreate($tagLVHITTESTINFO) DllStructSetData($tTest, "X", DllStructGetData($tInfox, "X")) DllStructSetData($tTest, "Y", DllStructGetData($tInfox, "Y")) Local $iRet = GUICtrlSendMsg($IDFrom, $LVM_HITTEST, 0, DllStructGetPtr($tTest)) If @error Or $iRet = -1 Then Return $GUI_RUNDEFMSG ; -1 = not on lv item, otherwise returns index Switch DllStructGetData($tTest, "Flags") Case $LVHT_ONITEMICON, $LVHT_ONITEMLABEL, $LVHT_ONITEM ;hit was on item icon or 1st column item or subitem $fSysMenu = True EndSwitch EndSwitch EndSwitch Return $GUI_RUNDEFMSG EndFunc ;==>_WM_NOTIFY Edited July 17, 2011 by rover I see fascists...
Info Posted July 17, 2011 Author Posted July 17, 2011 Thank you but this still does not solve the whole issue. Although the Listview is not getting stuck anymore, it still waits until a menu item's event function finishes executing before it allows other menu items' functions to execute.
rover Posted July 17, 2011 Posted July 17, 2011 (edited) Thank you but this still does not solve the whole issue.Although the Listview is not getting stuck anymore, it still waits until a menu item's event function finishes executing before it allows other menu items' functions to execute.I changed the code in the first example, I use the hit test in WM_NOTIFY method myself and ran into another issue coding the WM_CONTEXTMENU only example that the other method does not have.Now, on to your comment.AutoIt is a single threaded language, so each instruction is queued, and run after the previous finishes.If you click all three menu items they will run sequentially.The only way around this is to run multiple script processes and use inter process communication.There are examples on the forum.There is another method, but it is advanced and limited in what can be run.This method runs code in another thread.On the forum is a script that polls internet connectivity without blocking the main loop by running assembly code in another thread.Although AU3 is not threadsafe, a method has been worked out using assembly code.I don't know much about it beyond testing a few of the examples of which there are several on the forum.So multi process communication may be your only way to go.Edit:You could use $iNotify = 3 (as Martin pointed out) with TrackPopupMenu and use the returned menu item in a conditional statement to send a message to a co-process to run functions instead of using main loop or on-event mode for functions in current process. Edited July 17, 2011 by rover I see fascists...
Info Posted July 17, 2011 Author Posted July 17, 2011 (edited) I see. Anyway, I give up on this. I should have chose C++ for this project but it's too late now. Thanks Edited July 17, 2011 by Info
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