Jump to content
Luigi

Menu de contexto

Recommended Posts

Bom dia!

 

Existe um conjunto de UDF muito interessante: as funções de menu de contexto ou ContextMenu.

 

Sugiro quanto lhe sobrar um tempo, abra exemplo por exemplo no HELP do AutoIt e dê um olhada, há exemplos muito sugestivos.

 

Tá, mas o que é um menu de contexto?

 

No meu entendimento, menu de contexto, é aquela caixinha com opções para clicar, que se abre com o botão direito do mouse.

 

Veja este exemplo:

 

https://www.autoitscript.com/autoit3/docs/libfunctions/_GUICtrlMenu_CreatePopup.htm

 

[Módulo 1]

#include <GUIConstantsEx.au3>
#include <GuiMenu.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

Global Enum $e_idOpen = 1000, $e_idSave, $e_idInfo

Func Example()
    ; Create GUI
    ; aqui ele cria uma GUI ([G]raphic [U]ser [I]nterface) bem básica (e nem precisa mais do que isso)
    GUICreate("Menu", 400, 300)
    GUISetState(@SW_SHOW)

    ; Register message handlers
    ; preste a atenção nestes comandos "GUIRegisterMsg"
	
    ; o que é um GuiRegisterMsg?
    ; bem, vou aproveitar a explicação de outras linguagens
    ; é um "listner"
	; hein? cuma? isso é di cume?
	; carma jovem gafanhoto, dá um olhadinha aqui:
	; https://www.google.com.br/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=o%20que%20%C3%A9%20um%20listner
	; 
	; entendeu? Nâo? eu também demorei pra entender, sugiro ir ali no link e ler mais uma vez ^^
	; mas então, você informa que toda a vez que aconteça uma ação do tipo $WM_CONTEXTMENU ele 
    ; chama a função "WM_CONTEXTMENU"
    GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU")
	
	; as funções  de $WM_COMMAND são muito legais! eu falo mais sobre elas em outro post
	GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

    ; Loop until the user exits.
	; aqui está o loop para manter a janela ativa
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
EndFunc   ;==>Example

; Handle WM_COMMAND messages
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam
    Switch $wParam
        Case $e_idOpen
            _WinAPI_ShowMsg("Open")
        Case $e_idSave
            _WinAPI_ShowMsg("Save")
        Case $e_idInfo
            _WinAPI_ShowMsg("Info")
    EndSwitch
EndFunc   ;==>WM_COMMAND

; Toda a vez que você clica dentro da janela do AutoIt com botão direito, um evento de $WM_COMMAND é acionado,
; e a função "WM_COMMAND" é chamada
; neste momento eu não tenho conhecimento para dar uma boa explicação sobre os parâmetros $hWnd, $iMsg, $wParam, $lParam
; então não vou me aprofundar sobre estas variáveis
; Mas o que acontece neste momento, é que ele cria um menu popup
; e popula este menu popup com as funções Open, Save e Info
; exibe o menu para você
; e finalmente, destroi o menu

; [ATENÇÃO]
; um elemento _GUICtrlMenu_InsertMenuItem é um elemento de mesma função que um GuiCtrlCreateButton
; pois afinal, você clica nele para executar uma função

; vamos falar diferente, quando você clica no menu de contexto $e_idOpen, você criou um listner $WM_COMMAND
; que toda vez que for acionado, chamará a função "WM_COMMAND"

; chegando no "WM_COMMAND", ele vai fazer um Switch com o $wParam para identificar qual dos parâmetros ($e_idOpen, $e_idSave, $e_idInfo) foi acionado
; encontrando o Case correto, ele executa a função
Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $lParam
    Local $hMenu

    $hMenu = _GUICtrlMenu_CreatePopup()
    _GUICtrlMenu_InsertMenuItem($hMenu, 0, "Open", $e_idOpen)
    _GUICtrlMenu_InsertMenuItem($hMenu, 1, "Save", $e_idSave)
    _GUICtrlMenu_InsertMenuItem($hMenu, 3, "", 0)
    _GUICtrlMenu_InsertMenuItem($hMenu, 3, "Info", $e_idInfo)
    _GUICtrlMenu_TrackPopupMenu($hMenu, $wParam)
    _GUICtrlMenu_DestroyMenu($hMenu)
    Return True
EndFunc   ;==>WM_CONTEXTMENU

#cs
	Perceba que as variáveis para utilizar um menu de contexto, obrigatoriamente tem que ser globais
	e a primeira variável sempre começa com um valor alto
	Cada elemento de GUI (GuiCtrlCreateButton, GuiCtrlCreateLabel, GuiCtrlCreateTreeView, etc) que você usa, recebe um id
	Por isso essa opções do menu de contexto devem começar com valor alto,
	justamente para que não haja o mesmo id de um menu de contexto com um elemento de GUI já criado por você
	Global Enum $e_idOpen = 1000, $e_idSave, $e_idInfo	
#ce
Parabéns jovem gafanhoto, você acaba de criar e entender o seu primeiro menu de contexto, agora vamos para o módulo 2!
[Módulo 2]
No primeiro exemplo, criamos apenas um menu de contexto para a Gui, mas e para outros elementos?
Com o exemplo que vou mostrar agora, é possível criar um menu de contexto para qualquer elemento.
Tá certo que não faz muito sentido criar um menu de contexto para um botão, mas faz sentido para uma TreeView ou ListView.
Mas nada te impede que você crie um menu de contexto para um botão, o conhecimento vale para ambos.
Vamos pegar o mesmo exemplo anterior, e observe as modificações:
#include <GUIConstantsEx.au3>
#include <GuiMenu.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>

Global Enum $e_GuiOpen = 1000, $e_GuiSave, $e_GuiInfo, $e_TvAdd
Global $hGui, $iTreeView, $hTreeView

Example()

Func Example()
	; Create GUI
	$hGui = GUICreate("Menu", 400, 300)

	$iTreeView = GUICtrlCreateTreeView(10, 10, 120, 240)
	$hTreeView = GUICtrlGetHandle($iTreeView)
	GUISetState(@SW_SHOW)

	; Register message handlers
	GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
	GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU")

	; Loop until the user exits.
	Do
	Until GUIGetMsg() = $GUI_EVENT_CLOSE
EndFunc   ;==>Example

; Handle WM_COMMAND messages
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
	#forceref $hWnd, $iMsg, $lParam
	Switch $wParam
		Case $e_GuiOpen
			_WinAPI_ShowMsg("Gui Open")
		Case $e_GuiSave
			_WinAPI_ShowMsg("Gui Save")
		Case $e_GuiInfo
			_WinAPI_ShowMsg("Gui Info")
		Case $e_TvAdd
			_WinAPI_ShowMsg("TreeView Add")
	EndSwitch
EndFunc   ;==>WM_COMMAND

; Handle WM_CONTEXTMENU messages
Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam)
	#forceref $hWnd, $iMsg, $lParam
	Local $hMenu = _GUICtrlMenu_CreatePopup()

	Switch $wParam
		Case $hGui
			_GUICtrlMenu_InsertMenuItem($hMenu, 0, "GUI Open", $e_GuiOpen)
			_GUICtrlMenu_InsertMenuItem($hMenu, 1, "GUI Save", $e_GuiSave)
			_GUICtrlMenu_InsertMenuItem($hMenu, 3, "", 0)
			_GUICtrlMenu_InsertMenuItem($hMenu, 3, "GUI Info", $e_GuiInfo)
		Case $hTreeView
			_GUICtrlMenu_InsertMenuItem($hMenu, 0, "TreeView Add", $e_TvAdd)
	EndSwitch

	_GUICtrlMenu_TrackPopupMenu($hMenu, $wParam)
	_GUICtrlMenu_DestroyMenu($hMenu)
	Return True
EndFunc   ;==>WM_CONTEXTMENU
Há algo muito importante que deve ser observado, quando você cria uma GUI, você utiliza um comando GuiCtrlCreate, e ele retorna o "handle" da janela, algo do tipo 0x00123456.
Quando você cria um elemento (Button, Label, TreeView), no momento da criação ele retorna o id do elemento, algo como 1, 2, 3, 4.
Quando você cria um _GuiCtrlTreeView_Create, _GuiCtrlTreeView_Item, ele retorna um "handle", do tipo 0x00123456.
Percebeu que existe GuiCtrlCreateTreeView e _GuiCtrlTreeView_Create?
Criam a mesma coisa, mas retornam coisas diferentes, um retorna id, outro retorna handle.
Por isso eu coloque no exemplo as linhas.
ConsoleWrite("$hGui[" & $hGui & "] IsPtr[" & IsPtr($hGui) & "]" & @LF)
ConsoleWrite("$iTreeView[" & $iTreeView & "] IsPtr[" & IsPtr($iTreeView) & "]" & @LF)
ConsoleWrite("$hTreeView[" & $hTreeView & "] IsPtr[" & IsPtr($hTreeView) & "]" & @LF)
Quando o IsPtr é 1(um), é um handle, quando o IsPtr é 0(zero), é um id.
Estou chamado a atenção neste momento, um dia você deve ter tentado trabalhar com funções mais avançadas do AutoIt, mas a função exigia um handle, mas você por desconhecimento passava um id.
Não vai funcionar mesmo.
As vezes, nem sempre, a função possui algo do tipo:
If Not IsPtr($handle) Then $handle = GuiCtrlGetHandle($handle)
Por esse motivo, eu criei TreeView com o $iTreeView, e na linha abaixo, eu utilizei:
$hTreeView = GUICtrlGetHandle($iTreeView)
Não cabe agora explicar explicar quando utilizar um id ou handle, cabe a você ler o help da função, e ver que tipo de parâmetro ela necessita para funcionar corretamente.
Todo esse blá, blá, blá, foi para chegar no WM_CONTEXTMENU
Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam)
	#forceref $hWnd, $iMsg, $lParam
	Local $hMenu = _GUICtrlMenu_CreatePopup()

	Switch $wParam
		Case $hGui
			_GUICtrlMenu_InsertMenuItem($hMenu, 0, "GUI Open", $e_GuiOpen)
			_GUICtrlMenu_InsertMenuItem($hMenu, 1, "GUI Save", $e_GuiSave)
			_GUICtrlMenu_InsertMenuItem($hMenu, 3, "", 0)
			_GUICtrlMenu_InsertMenuItem($hMenu, 3, "GUI Info", $e_GuiInfo)
		Case $hTreeView
			_GUICtrlMenu_InsertMenuItem($hMenu, 0, "TreeView Add", $e_TvAdd)
	EndSwitch

	_GUICtrlMenu_TrackPopupMenu($hMenu, $wParam)
	_GUICtrlMenu_DestroyMenu($hMenu)
	Return True
EndFunc   ;==>WM_CONTEXTMENU
Eu inseri um Switch...Case no $wParam, para verificar de qual handle vem o clique, se vem da $hGui ou $hTreeView.
Poderia ser qualquer elemento, um $hButton por exemplo.
E para cada handle diferente, ele exibe um menu de contexto diferente.
Funcionou para você?
Sim né!
Que bom!
Tem certeza de que funcionou?
Você clicou em todos os botões de todos os menus de contexto para ter certeza de que funciona?
Ah... Tem um bugzinho aqui...
Onde?
O menu de contexto da TreeView aparece, mas quando eu clico, sabe a janelinha do "Information"? Não aparece para o TreeView, somente para a Gui.
Sério? "Nussa"! Que mancada!
Eheheheeh, eu não sei explicar, porque o menu de contexto da TreeView não chama o WM_COMMAND, como deveria funcionar com a Gui.
Ele está la, mas o $wParam da $e_TvAdd nunca é acionado.
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
	#forceref $hWnd, $iMsg, $lParam
	Switch $wParam
		Case $e_GuiOpen
			_WinAPI_ShowMsg("Gui Open")
		Case $e_GuiSave
			_WinAPI_ShowMsg("Gui Save")
		Case $e_GuiInfo
			_WinAPI_ShowMsg("Gui Info")
		Case $e_TvAdd
			_WinAPI_ShowMsg("TreeView Add")
	EndSwitch
EndFunc   ;==>WM_COMMAND
Mas há um "hack" que eu descobri lendo a descrição da função _GUICtrlMenu_TrackPopupMenu:
_GUICtrlMenu_TrackPopupMenu ( $hMenu, $hWnd [, $iX = -1 [, $iY = -1 [, $iAlignX = 1 [, $iAlignY = 1 [, $iNotify = 0 [, $iButtons = 0]]]]]] )
O parâmetro $iNotify, esse é o segredo!
Então eu modifiquei um pouco o WM_CONTEXTMENU, ficou assim:
Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam)
	#forceref $hWnd, $iMsg, $lParam
	Local $hMenu = _GUICtrlMenu_CreatePopup()
	Local $iNotify = 0
	Switch $wParam
		Case $hGui
			_GUICtrlMenu_InsertMenuItem($hMenu, 0, "GUI Open", $e_GuiOpen)
			_GUICtrlMenu_InsertMenuItem($hMenu, 1, "GUI Save", $e_GuiSave)
			_GUICtrlMenu_InsertMenuItem($hMenu, 3, "", 0)
			_GUICtrlMenu_InsertMenuItem($hMenu, 3, "GUI Info", $e_GuiInfo)
			_GUICtrlMenu_TrackPopupMenu($hMenu, $wParam)
		Case $hTreeView
			_GUICtrlMenu_InsertMenuItem($hMenu, 0, "TreeView Add", $e_TvAdd)
			$iNotify = _GUICtrlMenu_TrackPopupMenu($hMenu, $wParam, -1, -1, 1, 1, 2)
			_SendMessage($hGui, 273, $iNotify, 0)
	EndSwitch
	_GUICtrlMenu_DestroyMenu($hMenu)
	Return True
EndFunc   ;==>WM_CONTEXTMENU
			$iNotify = _GUICtrlMenu_TrackPopupMenu($hMenu, $wParam, -1, -1, 1, 1, 2)
			_SendMessage($hGui, 273, $iNotify, 0)
Se você observar, no case $hGui, está:
_GUICtrlMenu_TrackPopupMenu($hMenu, $wParam)
E no case $hTreeView:
$iNotify = _GUICtrlMenu_TrackPopupMenu($hMenu, $wParam, -1, -1, 1, 1, 2)
-1, -1, 1, 1 são os parâmetros default da função, e o $iNotify foi alterado de 0 para 2, pois assim a função _GUICtrlMenu_TrackPopupMenu passa a retornar valor em uma variável, eu aproveitei mesmo nome, $iNotify
Na WM_CONTEXTMENU está quase pronto, e para isso eu utilizei um _SendMessage para forçar o listner WM_COMMAND
_SendMessage($hGui, 273, $iNotify, 0)
Você precisa mandar uma mensagem da $hGui, com o $wParam contendo o valor na $iNotify, o $lParam pode ser 0, o problema, era o $iMsg ou o 273...
Mano do céu! Da onde eu ia adivinhar esse valor?
Confesso que eu passei gelei nesse momento...
Mas daí, inseri uma linhazinha marota lá no WM_COMMAND
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
	#forceref $hWnd, $iMsg, $lParam
	ConsoleWrite("WM_COMMAND( $hWnd=" & $hWnd & ", $iMsg=" & $iMsg & ", $wParam=" & $wParam & ", $lParam=" & $lParam & ")" & @LF)
Rodei o script, usei o menu de contexto da $hGui, e touché! $iMsg = 273.
Atualizei o WM_CONTEXTMENU, e funcionou o WM_COMMAND da TreeView.
_SendMessage($hGui, 273, $iNotify, 0)
Deixo claro, que talvez não seja a melhor forma acionar o WM_COMMAND, mas neste momento funciona.
Bem, é isso pe-pessoal! Até mais!

Exemplo final:

#include <GUIConstantsEx.au3>
#include <GuiMenu.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>


Global Enum $e_GuiOpen = 1000, $e_GuiSave, $e_GuiInfo, $e_TvAdd
Global $hGui, $iTreeView, $hTreeView


Example()


Func Example()
	; Create GUI
	$hGui = GUICreate("Menu", 400, 300)
	ConsoleWrite("$hGui[" & $hGui & "] IsPtr[" & IsPtr($hGui) & "]" & @LF)


	$iTreeView = GUICtrlCreateTreeView(10, 10, 120, 240)
	ConsoleWrite("$iTreeView[" & $iTreeView & "] IsPtr[" & IsPtr($iTreeView) & "]" & @LF)
	$hTreeView = GUICtrlGetHandle($iTreeView)
	ConsoleWrite("$hTreeView[" & $hTreeView & "] IsPtr[" & IsPtr($hTreeView) & "]" & @LF)
	GUISetState(@SW_SHOW)


	; Register message handlers
	GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
	GUIRegisterMsg($WM_CONTEXTMENU, "WM_CONTEXTMENU")


	; Loop until the user exits.
	Do
	Until GUIGetMsg() = $GUI_EVENT_CLOSE
EndFunc   ;==>Example


; Handle WM_COMMAND messages
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
	#forceref $hWnd, $iMsg, $lParam
	ConsoleWrite("WM_COMMAND( $hWnd=" & $hWnd & ", $iMsg=" & $iMsg & ", $wParam=" & $wParam & ", $lParam=" & $lParam & ")" & @LF)
	Switch $wParam
		Case $e_GuiOpen
			_WinAPI_ShowMsg("Gui Open")
		Case $e_GuiSave
			_WinAPI_ShowMsg("Gui Save")
		Case $e_GuiInfo
			_WinAPI_ShowMsg("Gui Info")
		Case $e_TvAdd
			_WinAPI_ShowMsg("TreeView Add")
	EndSwitch
EndFunc   ;==>WM_COMMAND


; Handle WM_CONTEXTMENU messages
Func WM_CONTEXTMENU($hWnd, $iMsg, $wParam, $lParam)
	#forceref $hWnd, $iMsg, $lParam
	Local $hMenu = _GUICtrlMenu_CreatePopup()
	Local $iNotify = 0
	Switch $wParam
		Case $hGui
			_GUICtrlMenu_InsertMenuItem($hMenu, 0, "GUI Open", $e_GuiOpen)
			_GUICtrlMenu_InsertMenuItem($hMenu, 1, "GUI Save", $e_GuiSave)
			_GUICtrlMenu_InsertMenuItem($hMenu, 3, "", 0)
			_GUICtrlMenu_InsertMenuItem($hMenu, 3, "GUI Info", $e_GuiInfo)
			_GUICtrlMenu_TrackPopupMenu($hMenu, $wParam)
		Case $hTreeView
			_GUICtrlMenu_InsertMenuItem($hMenu, 0, "TreeView Add", $e_TvAdd)
			$iNotify = _GUICtrlMenu_TrackPopupMenu($hMenu, $wParam, -1, -1, 1, 1, 2)
			_SendMessage($hGui, 273, $iNotify, 0)
	EndSwitch
	_GUICtrlMenu_DestroyMenu($hMenu)
	Return True
EndFunc   ;==>WM_CONTEXTMENU
Edited by Luigi
  • Like 3

Share this post


Link to post
Share on other sites

Pela capacidade de se expressar..

 


No meu entendimento

 

 


Tá, mas o que é um menu de contexto?

 

Luigi é palestrante ou professor..., se não é, devia ser.

 

ótimo tutorial.

  • Like 1

Share this post


Link to post
Share on other sites

Luigi é palestrante ou professor..., se não for, devia ser.

 

ótimo tutorial.

Quando a coca cola usava casco de vidro, eu era aspirante à professor de física, hoje esse mundo não me pertence mais.

Apenas gosto do AutoIt e a melhor forma de aprender, é ensinando.

 

Por exemplo, ontem a noite eu pensei nesse tutorial, mas nem me passou pela cabeça que seria possível utilizar o _SendMessage.

Hoje de manhã escrevendo, tentei usar e deu certo.

 

Aprendi algo mais ensinando! Show!

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now


×