Что нового

Контекстное меню в TreeView с иконками в Autoit 3.3.12.0 и выше

pvnn

Осваивающий
Сообщения
305
Репутация
32
Всем добрый день
Создаю контекстное меню в TreeView. Все работает. Хочу добавить иконки, для этого использую ModernMenu UDF http://autoit-script.ru/index.php/topic,12136.0.html
И вроде бы получилось, но появился интересный глюк. Например, если вызвать контекстное меню подряд на нескольких пунктах TreeView, то последний пункт остается постоянно выделенным и Левый клик мыши уже не обрабатывается.
Как исправить глюк или может можно добавить иконки в контекстное меню стандартным способом?
Код:
#include <GUIConstantsEx.au3>
#include <ListViewConstants.au3>
#include <TreeViewConstants.au3>
#include <WindowsConstants.au3>
#include <GuiTreeView.au3>
#include <Array.au3>
#include <GuiListView.au3>

#include <ModernMenuRaw.au3> ; http://autoit-script.ru/index.php/topic,12136.0.html



$Form1 = GUICreate("Form1", 835, 436, -1, -1)
; TreeView
$iStyle=BitOR($TVS_HASBUTTONS,$TVS_HASLINES,$TVS_LINESATROOT,$TVS_DISABLEDRAGDROP,$TVS_SHOWSELALWAYS)
$hTreeView =_GUICtrlTreeView_Create($Form1,8, 8, 225, 433,$iStyle,$WS_EX_CLIENTEDGE)
_GUICtrlTreeView_AddFirst($hTreeView,0,'Первый')
$test=_GUICtrlTreeView_Add($hTreeView,0,'Второй')
_GUICtrlTreeView_AddChild($hTreeView,$test,'1')
_GUICtrlTreeView_AddChild($hTreeView,$test,'2')
_GUICtrlTreeView_Expand($hTreeView,$test)  ; Развернуть пункт

; Изображения
  $hImage = _GUIImageList_Create(16, 16, 5)
 _GUIImageList_AddIcon($hImage,'C:\Windows\system32\imageres.dll',4)
 _GUICtrlTreeView_SetNormalImageList($hTreeView, $hImage)

; Контекстное Меню
 $DummyMenu =   GUICtrlCreateDummy()
 $ContextMenu = GUICtrlCreateContextMenu($DummyMenu)
; ModernMenu UDF
 $AddGroup =  _GUICtrlCreateODMenuItem("Добавить группу", $ContextMenu,'C:\Windows\system32\imageres.dll',0)
 $EditGroup =  _GUICtrlCreateODMenuItem("Редактировать группу", $ContextMenu)
 $DelGroup =  _GUICtrlCreateODMenuItem("Удалить группу", $ContextMenu)
; Standart menu
 ;~  $AddGroup =  GUICtrlCreateMenuItem("Добавить группу", $ContextMenu)
;~  $EditGroup =  GUICtrlCreateMenuItem("Редактировать группу", $ContextMenu)
;~  $DelGroup =  GUICtrlCreateMenuItem("Удалить группу", $ContextMenu)


GUISetState(@SW_SHOW)
 GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")             ; Для Контекстного меню и Сортировки по клику на заголовок

While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd



; Show a menu in a given GUI window which belongs to a given GUI ctrl
Func ShowMenu($hWnd, $nContextID, $nContextControlID, $iMouse=0)
    Local $hMenu = GUICtrlGetHandle($nContextID)
    Local $iCtrlPos = ControlGetPos($hWnd, "", $nContextControlID)

    Local $X = $iCtrlPos[0]
    Local $Y = $iCtrlPos[1] + $iCtrlPos[3]

    ClientToScreen($hWnd, $X, $Y)

    If $iMouse Then
        $X = MouseGetPos(0)
        $Y = MouseGetPos(1)
    EndIf

    DllCall("user32.dll", "int", "TrackPopupMenuEx", "hwnd", $hMenu, "int", 0, "int", $X, "int", $Y, "hwnd", $hWnd, "ptr", 0)
EndFunc

; Convert the client (GUI) coordinates to screen (desktop) coordinates
Func ClientToScreen($hWnd, ByRef $x, ByRef $y)
    Local $stPoint = DllStructCreate("int;int")

    DllStructSetData($stPoint, 1, $x)
    DllStructSetData($stPoint, 2, $y)

    DllCall("user32.dll", "int", "ClientToScreen", "hwnd", $hWnd, "ptr", DllStructGetPtr($stPoint))

    $x = DllStructGetData($stPoint, 1)
    $y = DllStructGetData($stPoint, 2)
    ; release Struct not really needed as it is a local
    $stPoint = 0
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	#forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom,  $iCode, $tNMHDR, $hWndTreeView, $tInfo

    $hWndTreeView = $hTreeView
    If Not IsHWnd($hTreeView) Then $hWndTreeView = GUICtrlGetHandle($hTreeView)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iCode = DllStructGetData($tNMHDR, "Code")

    Switch $hWndFrom
        Case $hWndTreeView
            Switch $iCode
				Case $NM_RCLICK ; Клик Правой клавишей мыши (Контекстное меню)
                        ShowMenu($hWnd, $ContextMenu, $hTreeView, 1)
				Case $NM_CLICK

            EndSwitch
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc
 
Автор
P

pvnn

Осваивающий
Сообщения
305
Репутация
32
Обратите внимание:
В названии темы как раз это учтено. Взял UDF, какую смог найти.

Причем здесь это? Мне не нужно в пункт TreeView вставлять иконку.
Необходимо вставить иконку в контекстное меню, то есть сюда:
Код:
$AddGroup =  GUICtrlCreateMenuItem("Добавить группу", $ContextMenu)
 
Автор
P

pvnn

Осваивающий
Сообщения
305
Репутация
32
Alofa, а можете привести пример кода с контекстным меню?
 

InnI

AutoIT Гуру
Сообщения
4,922
Репутация
1,432
pvnn
последний пункт остается постоянно выделенным и Левый клик мыши уже не обрабатывается
Проблема не в меню, а в способе его вызова. В справке к функции GUIRegisterMsg() сказано [box]Внимание: блокировка выполняющейся пользовательской функции, например командой MsgBox() может привести к непредсказуемому поведению, вернуть управление системе нужно как можно быстрее !!![/box] А всплывающее меню как раз и есть аналог блокирующей функции.

Один из вариантов такой. Создать глобальную переменную, сообщающую о необходимости отображения меню, и проверять её в главном цикле. При необходимости - вызывать меню. Устанавливать переменную при клике правой клавишей, обнулять в функции меню
Код:
...
; Контекстное Меню
 $ShowMenu = False ; <= глобальная переменная
 $DummyMenu =   GUICtrlCreateDummy()
...
...
While 1
    If $ShowMenu Then ShowMenu($Form1, $ContextMenu, $hTreeView, 1) ; <= отображение меню
    $nMsg = GUIGetMsg()
...
...
Func ShowMenu($hWnd, $nContextID, $nContextControlID, $iMouse=0)
    $ShowMenu = False ; <= обнуление переменной
    Local $hMenu = GUICtrlGetHandle($nContextID)
...
...
                Case $NM_RCLICK ; Клик Правой клавишей мыши (Контекстное меню)
                        $ShowMenu = True ; <= установка переменной
                Case $NM_CLICK
...
Если нужно выделить пункт кликом ПКМ, то добавьте этот код
Код:
...
                Case $NM_RCLICK ; Клик Правой клавишей мыши (Контекстное меню)
                        $tMPos = _WinAPI_GetMousePos(True, $hWndFrom)
                        $hItem = _GUICtrlTreeView_HitTestItem($hWndFrom, $tMPos.X, $tMPos.Y)
                        If $hItem > 0 Then
                          _GUICtrlTreeView_SelectItem($hWndTreeView, $hItem)
                        EndIf
                        $ShowMenu = True ; <= установка переменной
                Case $NM_CLICK
...
 
Верх