Jump to content

Recommended Posts

Posted (edited)

Hi,

This example demonstrates how to replace the default context menu in an edit control with your own

Uses _WinAPI_CallWindowProc, a good function that requires more examples :ILA:

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

; modified from help example: _WinAPI_CallWindowProc

$hGui = GUICreate("Custom context menu for Edit Control example", 489, 354, -1, -1)
$editBox = GUICtrlCreateEdit("", 8, 40, 473, 305)
GUICtrlSetData(-1, "New text")
$checkBox = GUICtrlCreateCheckbox("Use our own context menu", 8, 8, 241, 17)
GUICtrlSetState($checkBox, $GUI_CHECKED)

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;!! subclass for $editBox
$w_editBoxProcNew = DllCallbackRegister("_MyWindowProc", "ptr", "hwnd;uint;long;ptr")
$w_editBoxProcOld = _WinAPI_SetWindowLong(GUICtrlGetHandle($editBox), $GWL_WNDPROC, DllCallbackGetPtr($w_editBoxProcNew))
_WinAPI_SetWindowLong(GUICtrlGetHandle($editBox), $GWL_WNDPROC, DllCallbackGetPtr($w_editBoxProcNew))

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;!! our context menu for $editBox
$DummyMenu = GUICtrlCreateDummy()
$ContextMenu = GUICtrlCreateContextMenu($DummyMenu)
$TestMenuItem = GUICtrlCreateMenuItem("Our Custom Context Menu", $ContextMenu)
GUICtrlSetState($TestMenuItem, $GUI_DEFBUTTON)
GUICtrlCreateMenuItem("", $ContextMenu)
$UndoMenuItem = GUICtrlCreateMenuItem("&Undo", $ContextMenu)
GUICtrlCreateMenuItem("", $ContextMenu)
$CutMenuItem = GUICtrlCreateMenuItem("&Cut", $ContextMenu)
$CopyMenuItem = GUICtrlCreateMenuItem("&Copy", $ContextMenu)
$PasteMenuItem = GUICtrlCreateMenuItem("&Paste", $ContextMenu)
$DeleteMenuItem = GUICtrlCreateMenuItem("&Delete", $ContextMenu)
GUICtrlCreateMenuItem("", $ContextMenu)
$SelectAllMenuItem = GUICtrlCreateMenuItem("&Select all", $ContextMenu)
GUICtrlCreateMenuItem("", $ContextMenu)
$InsertDateMenuItem = GUICtrlCreateMenuItem("&Insert Date and Time", $ContextMenu)

GUISetState(@SW_SHOW)

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        ; toggle our context menu on / off
        Case $checkBox
            If BitAND(GUICtrlRead($checkBox), $GUI_CHECKED) = $GUI_CHECKED Then
                _WinAPI_SetWindowLong(GUICtrlGetHandle($editBox), $GWL_WNDPROC, DllCallbackGetPtr($w_editBoxProcNew))
            Else
                _WinAPI_SetWindowLong(GUICtrlGetHandle($editBox), $GWL_WNDPROC, $w_editBoxProcOld)
            EndIf

        Case $GUI_EVENT_CLOSE
            ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            ;!! we must free the callback before exit !!
            _WinAPI_SetWindowLong(GUICtrlGetHandle($editBox), $GWL_WNDPROC, $w_editBoxProcOld)
            DllCallbackFree($w_editBoxProcNew)
            Exit
    EndSwitch
WEnd

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;!! process our context menu messages
Func MenuItem($iSelected)
    Switch $iSelected
        Case $TestMenuItem
            _GUICtrlEdit_AppendText($editBox, @CRLF & "Our Custom Context Menu")
        Case $UndoMenuItem
            _GUICtrlEdit_Undo($editBox)
        Case $CutMenuItem
            MenuItem($CopyMenuItem)
            MenuItem($DeleteMenuItem)
        Case $CopyMenuItem
            Local $aSel, $sText
            $aSel = _GUICtrlEdit_GetSel($editBox)
            If ($aSel[0] <> $aSel[1]) Then
                $sText = StringMid(_GUICtrlEdit_GetText($editBox), $aSel[0] + 1, ($aSel[1] - $aSel[0]) + 1)
                ClipPut($sText)
            EndIf
        Case $PasteMenuItem
            Local $sText = ClipGet()
            If (Not @error) Then _GUICtrlEdit_ReplaceSel($editBox, $sText, True)
        Case $DeleteMenuItem
            _GUICtrlEdit_ReplaceSel($editBox, "", True)
        Case $SelectAllMenuItem
            _GUICtrlEdit_SetSel($editBox, 0, -1)
        Case $InsertDateMenuItem
            _GUICtrlEdit_ReplaceSel($editBox, @CRLF & @YEAR &"/"& @MON &"/"& @MDAY &" "& @HOUR &":" & @MIN &":" & @SEC)
    EndSwitch
EndFunc   ;==>ShowMenu

; auxilary function to update menu item states, not required
Func UpdateMenuStates()
    Local $aSel = _GUICtrlEdit_GetSel($editBox)
    Local $iLen = _GUICtrlEdit_GetTextLen($editBox)
    _GUICtrlEnabled($UndoMenuItem, _GUICtrlEdit_CanUndo($editBox))
    _GUICtrlEnabled($CutMenuItem, ($aSel[0]<>$aSel[1]))
    _GUICtrlEnabled($CopyMenuItem, ($aSel[0]<>$aSel[1]))
    _GUICtrlEnabled($PasteMenuItem, (StringLen(ClipGet())>0))
    _GUICtrlEnabled($DeleteMenuItem, ($aSel[0]<>$aSel[1]))
    _GUICtrlEnabled($SelectAllMenuItem, ($iLen>0) And ($iLen<>$aSel[0]+$aSel[1]))
EndFunc   ;==>SetMenuTexts

; auxilary function to enable / disable controls, not required
Func _GUICtrlEnabled($CtrlID, $fTrue = True)
    If $fTrue Then
        GUICtrlSetState($CtrlID, $GUI_ENABLE)
    Else
        GUICtrlSetState($CtrlID, $GUI_DISABLE)
    EndIf
EndFunc

;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;!! our window subclass for $editBox
Func _MyWindowProc($hWnd, $uiMsg, $wParam, $lParam)
    Switch $uiMsg
        Case $WM_CONTEXTMENU
            If $hWnd = GUICtrlGetHandle($editBox) Then
                ; show our context menu
                UpdateMenuStates()
                Local $iSelected = _GUICtrlMenu_TrackPopupMenu(GUICtrlGetHandle($ContextMenu), $hWnd, -1, -1, 1, 1, 2)
                MenuItem($iSelected)
                Return 0
            EndIf
    EndSwitch
    ;pass the unhandled messages to default WindowProc
    Return _WinAPI_CallWindowProc($w_editBoxProcOld, $hWnd, $uiMsg, $wParam, $lParam)
EndFunc   ;==>_MyWindowProc

Have a good day

Edited by maillady
Posted (edited)

Excellent demonstration of example, killing the following sentence:

"Note: You can not create context menus for controls That Already have context menus system, ie input or edit controls."

The final must be in the following sequence:

Case $GUI_EVENT_CLOSE
            ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            ;!! we must free the callback before exit !!
            _WinAPI_SetWindowLong(GUICtrlGetHandle($editBox), $GWL_WNDPROC, $w_editBoxProcOld)
            DllCallbackFree($w_editBoxProcNew)
            Exit

***** stars!

Regards,

João Carlos.

Edited by JScript

http://forum.autoitbrasil.com/ (AutoIt v3 Brazil!!!)

Somewhere Out ThereJames Ingram

somewh10.png

dropbo10.pngDownload Dropbox - Simplify your life!
Your virtual HD wherever you go, anywhere!

Posted (edited)

I made something similar nearly 2 years ago.

I deactivated unnecessary things for demonstration.

I will have a look at your solution. Thanks for sharing!

;Universal Variable Table
;2010 Nov 25

;~ #include "libnodave.au3"
#Include 
#include 
#include 
#include 
#include 
#include 
#Include 

;~ Opt("GUIResizeMode", 1)
Opt("GUIOnEventMode", 1)

Global $sTitle = "UniVarTab für SIMATIC S7-300 und S7-400 über TCP/IP"
Global $Ini = @ScriptDir & "UniVarTab.ini"
Global $hProc = DllCallBackRegister("_WindowProc", "int", "hwnd;uint;wparam;lparam")
Global $OriginalWindowProc
Global $aGridLines[1]
Global $Socket_SPS, $di_SPS, $dc_SPS
Global $LastID

FileInstall("UniVarTab.ini", $Ini, 0)

Global $aSPS = IniReadSection($Ini, "SPS")

Global $hGui = GUICreate($sTitle, 800, 605)
GUISetOnEvent(-3, "_Exit")
GUIRegisterMsg(0x4E, "_WM_NOTIFY")

Global $hCombo = GUICtrlCreateCombo("", 10, 5, 200, 60, 0x3)
For $i = 1 To $aSPS[0][0]
    GUICtrlSetData(-1, $aSPS[$i][0], $aSPS[1][0])
Next

Global $hBtnConnect = GUICtrlCreateButton("Verbinden", 220, 5, 100, 20)
GUICtrlSetOnEvent(-1, "_Connect")

Global $hBtnView = GUICtrlCreateCheckbox("Beobachten", 330, 5, 100, 20, 0x1000)
GUICtrlSetOnEvent(-1, "_View")
GUICtrlSetState(-1, 128)

Global $hInput = GUICtrlCreateInput("", 0, 0, 0, 0, 0x280)
GUICtrlSetState(-1, $GUI_HIDE)

Global $HeaderX = 10, $HeaderY = 40

GUICtrlCreateLabel("", $HeaderX, $HeaderY, 30, 20, -1, 0x1)

Global $hHeader = _GUICtrlHeader_Create($hGui)
_GUICtrlHeader_SetUnicodeFormat($hHeader, True)

Global $aHeaderWidth[6] = [30, 120, 340, 100, 100, 90]

_GUICtrlHeader_AddItem($hHeader, "", $aHeaderWidth[0])
_GUICtrlHeader_AddItem($hHeader, "Operand", $aHeaderWidth[1])
_GUICtrlHeader_AddItem($hHeader, "Kommentar", $aHeaderWidth[2])
_GUICtrlHeader_AddItem($hHeader, "Anzeigeformat", $aHeaderWidth[3])
_GUICtrlHeader_AddItem($hHeader, "Statuswert", $aHeaderWidth[4])
_GUICtrlHeader_AddItem($hHeader, "Steuerwert", $aHeaderWidth[5])

ControlMove($sTitle, "", "SysHeader321", $HeaderX, $HeaderY, 780)

Global $aHeaderPos[6]
For $i = 0 To 5
    $aHeaderPos[$i] = _GUICtrlHeader_GetItemRect($hHeader, $i)
Next

Local $hDummy = GUICtrlCreateDummy()
Global $FormatContext = GUICtrlCreateContextMenu($hDummy)
Global $aMenu[5][2] = [["Binär"], ["Bool"], ["Dezimal"], ["Hexadezimal"], ["Gleitpunkt"]]
For $i = 0 To UBound($aMenu) - 1
    $aMenu[$i][1] = GUICtrlCreateMenuItem($aMenu[$i][0], $FormatContext)
    GUICtrlSetOnEvent(-1, "_WriteFormat")
Next

$aGridLines[0] = _NewGridLine()

GUISetState()

While 1
    Sleep(20000)
WEnd

Func _View()
    If GUICtrlRead(@GUI_CtrlId) = 1 Then
;~         AdlibRegister("_GetData", 1000)
;~         _GetData()
    Else
;~         AdlibUnRegister("_GetData")
    EndIf
EndFunc

Func _Connect()
    Local $Index = GUICtrlSendMsg($hCombo, 0x147, 0, 0)
    Local $aParam = StringSplit($aSPS[$Index+1][1], ";", 2)
    If GUICtrlRead(@GUI_CtrlId) = "Verbinden" Then
;~         _daveTCPConnect($aParam[0], $Socket_SPS, $di_SPS, $dc_SPS, $aParam[1], $aParam[2], $aSPS[$Index+1][0])
        If @error Then
            MsgBox(16, "Error " & @error, "Verbindung zur SPS konnte nicht hergestellt werden.")
        Else
            GUICtrlSetState($hCombo, 128)
            GUICtrlSetState($hBtnView, 64)
            GUICtrlSetData(@GUI_CtrlId, "Trennen")
        EndIf
    Else
;~         $ViewMode = 0
;~         $ViewActive = 0
;~         _daveTCPDisconnect($Socket_SPS, $di_SPS, $dc_SPS)
        GUICtrlSetData(@GUI_CtrlId, "Verbinden")
        GUICtrlSetState($hBtnView, 128)
        GUICtrlSetState($hCombo, 64)
    EndIf
EndFunc

;~ Func _GetData()
;~ ConsoleWrite("Lesen" & @cr)
;~     Local $aTemp = $aGridLines[0]
;~     Local $sAdresse = GUICtrlRead($aTemp[1])
;~     Local $Area = _GetArea($sAdresse)
;~     Local $DB = _GetDB($sAdresse)
;~     Local $StartByte = _GetByte($sAdresse)
;~     _daveReadBytes($dc_SPS, $Area, $DB, $StartByte, 4)
;~     GUICtrlSetData($aTemp[4], _daveGetFloat($dc_SPS))
;~ EndFunc

;~ Func _GetDB($sAdresse)
;~     If StringLeft($sAdresse, 2)  'DB' Then Return 0
;~     Return StringTrimLeft(StringLeft($sAdresse, StringInStr($sAdresse, '.') -1), 2)
;~ EndFunc

;~ Func _AdresseGetBit($sAdresse)
;~     Return StringRight($sAdresse, 1)
;~ EndFunc

;~ Func _GetByte($sAdresse)
;~     Local $string = StringRegExp($sAdresse, '(d+).*d*z', 3)    ; Dank an Oscar von Autoit.de für diesen regulären Ausdruck
;~     Return $string[0]
;~ EndFunc

;~ Func _GetArea($sAdresse)
;~     Switch StringLeft($sAdresse, 1)
;~     Case 'D'
;~         Return $daveDB
;~     Case 'E', 'I'
;~         Return $daveInputs
;~     Case 'A', 'O'
;~         Return $daveOutputs
;~     Case 'M', 'F'
;~         Return $daveFlags
;~     Case 'T'
;~         Return $daveTimer
;~     Case 'Z'
;~         Return $daveCounter
;~     Case Else
;~         Return 0
;~     EndSwitch
;~ EndFunc

Func _WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode
    Local $tNMHDR, $tNMHEADER

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    $tNMHEADER = DllStructCreate($tagNMHEADER, $ilParam)
    Switch $hWndFrom
        Case $hHeader
            Switch $iCode
                Case -321
                    _Reset_HeaderWidth(DllStructGetData($tNMHEADER, "Item"))
            EndSwitch
    EndSwitch

    Return "GUI_RUNDEFMSG"
EndFunc   ;==>_WM_NOTIFY


Func _Reset_HeaderWidth($iIndex)
    _GUICtrlHeader_SetItemWidth($hHeader, $iIndex, $aHeaderWidth[$iIndex])
EndFunc

Func _WriteFormat()
    GUICtrlSetData($LastID, GUICtrlRead(@GUI_CtrlId, 1))
EndFunc

Func _NewGridLine()
    Local $aLabel[6], $aPos, $iTemp
    For $i = 0 To 5
        $aPos = $aHeaderPos[$i]
        Switch $i
            Case 0
                $aLabel[$i] = GUICtrlCreateLabel("*>", $aPos[0] + $HeaderX, $aPos[3] + $HeaderY, $aPos[2] - $aPos[0], $aPos[3] - $aPos[1], -1, 0x1)
                GUICtrlSetOnEvent(-1, "_AddNewGridLine")
            Case 4
                $aLabel[$i] = GUICtrlCreateLabel("", $aPos[0] + $HeaderX, $aPos[3] + $HeaderY, $aPos[2] - $aPos[0], $aPos[3] - $aPos[1], -1, 0x1)
                GUICtrlSetBkColor(-1, 0xcfcfcf)
            Case Else
                $aLabel[$i] = GUICtrlCreateEdit("", $aPos[0] + $HeaderX, $aPos[3] + $HeaderY, $aPos[2] - $aPos[0], $aPos[3] - $aPos[1], 0, 0x1)
        EndSwitch
        $iTemp = $aPos[3] - $aPos[1]
        $aPos[1] += $iTemp
        $aPos[3] += $iTemp
        $aHeaderPos[$i] = $aPos
    Next
    $OriginalWindowProc = _WinSubclass(GUICtrlGetHandle($aLabel[3]), DllCallbackGetPtr($hProc))
    Return $aLabel
EndFunc

Func _AddNewGridLine()
    If UBound($aGridLines) = 5 Then Return
    ReDim $aGridLines[UBound($aGridLines) + 1]
    $aGridLines[UBound($aGridLines) - 1] = _NewGridLine()
EndFunc

Func _Exit()
    GUISetState(@SW_HIDE, $hGui)
;~     _daveTCPDisconnect($Socket_SPS, $di_SPS, $dc_SPS)
;~     _DaveDeInit()
    _GUICtrlHeader_Destroy($hHeader)
    GUIDelete()
    DllCallBackFree($hProc)
    Exit
EndFunc

Func _ShowFormatMenu()
;~      _GUICtrlMenu_TrackPopupMenu(GUICtrlGetHandle($FormatContext), $hGui)
    DllCall("user32.dll", "int", "TrackPopupMenuEx", "hwnd", GUICtrlGetHandle($FormatContext), "int", 0, "int", MouseGetPos(0), "int", MouseGetPos(1), "hwnd", $hGui, "ptr", 0)
EndFunc

Func _WindowProc($hWnd, $uiMsg, $wParam, $lParam)
   ; Disable the context menu and show your own menu
    Local $aTemp
    Switch $uiMsg
        Case $WM_CONTEXTMENU
            For $i = 0 To UBound($aGridLines) - 1
                $aTemp = $aGridLines[$i]
                If $hWnd = GUICtrlGetHandle($aTemp[3]) Then
                    $LastID = $aTemp[3]
                    _ShowFormatMenu()
                    Return 0
                EndIf
            Next
    EndSwitch
    Return _WinAPI_CallWindowProc($OriginalWindowProc, $hWnd, $uiMsg, $wParam, $lParam)
EndFunc

Func _WinSubclass($hWnd, $lpNewWindowProc)
    Return _WinAPI_SetWindowLong($hWnd, $GWL_WNDPROC, $lpNewWindowProc)
EndFunc

Edit: Ini-File should look like this:

[SPS]
Name=IP;Rack;Slot
Edited by funkey

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...