tonedeaf Posted December 9, 2005 Posted December 9, 2005 (edited) This discussion follows Part I of following previous post:Creating/Managing Multiple Forms in AutoIt - Part IAutoIt by default does not create forms in a specific structure. All forms as well as the controls on the form are declared as global variables.This situation becomes worse if we have multiple forms with many controls. We then have to come up with unique names for each and every control so that control names do not clash between different forms. Moreover, so many global variables become difficult to manage after the code becomes complex.I'm trying to address some common issues by putting solutions which I think are flexible enough to handle such situations. Of course, these are always open to discussion/improvements.In this part, the following issues are discussed:> Trapping control events of form data types.> Handling parent/child windows.In my previous post I've discussed creating form data structures using arrays in AutoIt. We created a dialog box which is supposed to allow user to reset some password. In this part I'll build upon the application.The Reset Password form is a subform for an application which allows you to reset Local Computer User account passwords (for Windows 2000/XP). Here is the screenshot of the main form (frmUserManager) and the subform (frmResetPassword). In Part I, we created a form data type for frmResetPassword. The code is reproduced here:Func CreateForm_frmResetPassword(ByRef $afrmNew) Dim $afrmNew[5][2] $afrmNew[0][0] = "$frmResetPassword" $afrmNew[0][1] = GUICreate("Reset Password", 318, 111, 390, 279) GUICtrlCreateLabel("New passsword:", 11, 13, 131, 13) $afrmNew[1][0] = "$txtNewPwd" $afrmNew[1][1] = GUICtrlCreateInput("", 143, 11, 165, 23) GUICtrlCreateLabel("Confirm new passsword:", 11, 44, 131, 13) $afrmNew[2][0] = "$txtConfirmPwd" $afrmNew[2][1] = GUICtrlCreateInput("", 143, 41, 165, 23) $afrmNew[3][0] = "$cmdOK" $afrmNew[3][1] = GUICtrlCreateButton("OK", 152, 75, 75, 23) $afrmNew[4][0] = "$cmdCancel" $afrmNew[4][1] = GUICtrlCreateButton("Cancel", 233, 75, 75, 23) EndFuncSince frmResetPassword is a child window to frmUserManager window, we make some modifications in the above code:Func CreateForm_frmResetPassword(ByRef $afrmNew, $frmParent) Dim $afrmNew[6][2] $afrmNew[0][0] = "$frmResetPassword" $afrmNew[0][1] = GUICreate("Reset Password", 318, 107, (@DesktopWidth-100)/2, (@DesktopHeight-115)/2, _ $WS_CAPTION, -1, $frmParent) $afrmNew[1][0] = "$frmParent" $afrmNew[1][1] = $frmParent GUICtrlCreateLabel("New passsword:", 11, 13, 131, 13) $afrmNew[2][0] = "$txtNewPwd" $afrmNew[2][1] = GUICtrlCreateInput("", 143, 11, 165, 23, $ES_PASSWORD) GUICtrlCreateLabel("Confirm new passsword:", 11, 44, 131, 13) $afrmNew[3][0] = "$txtConfirmPwd" $afrmNew[3][1] = GUICtrlCreateInput("", 143, 41, 165, 23, $ES_PASSWORD) $afrmNew[4][0] = "$cmdOK" $afrmNew[4][1] = GUICtrlCreateButton("OK", 152, 75, 75, 23) $afrmNew[5][0] = "$cmdCancel" $afrmNew[5][1] = GUICtrlCreateButton("Cancel", 233, 75, 75, 23, $BS_DEFPUSHBUTTON) EndFuncModifications:1. The CreateForm_frmResetPassword() function now takes a parameter to $frmParent. This parameter is used to create this form as a child window in the GuiCreate() function on the 3rd line.2. There is an extra variable in the form array - $frmParent which stores the parent window handle.3. The style $ES_PASSWORD is added to both text boxes to make them behave as password text boxes.Similarily we create the Form Data Type for frmUserManager which is the main window of the application.Func CreateForm_frmUserManager(ByRef $afrmNew) Dim $afrmNew[4][2] $afrmNew[0][0] = "$frmUserManager" $afrmNew[0][1] = GUICreate("User Accounts", 396, 274, (@DesktopWidth-396)/2, (@DesktopHeight-274)/2) GUICtrlCreateGroup("User Accounts:", 8, 8, 380, 73) $afrmNew[1][0] = "$icoUsers" $afrmNew[1][1] = GUICtrlCreateIcon("shell32.dll", 50, 22, 32) GUICtrlCreateLabel("Select a local user account and click Reset Password. " & _ "You must have the required priviledges to reset passwords.", 70, 33, 301, 31) GUICtrlCreateLabel("Users for this computer:", 8, 90, 115, 17) $afrmNew[2][0] = "$lvwUserAccounts" $afrmNew[2][1] = GUICtrlCreateListView("Name |Full Name", 8, 110, 380, 121, _ BitOR($LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_NOSORTHEADER), BitOR($LVS_EX_FULLROWSELECT, $WS_EX_CLIENTEDGE)) $afrmNew[3][0] = "$cmdResetPwd" $afrmNew[3][1] = GUICtrlCreateButton("Reset &Password...", 273, 240, 115, 25) EndFuncSince this is the main form, the function to create this form does not require a parameter of a parent window.We also have these two functions from Part I:Func _GetCtrl($sCtrlName, $afrmArray) For $i = 0 to UBound($afrmArray, 1) - 1 If $afrmArray[$i][0] = $sCtrlName Then Return $afrmArray[$i][1] EndIf Next ; Error Handler If $i > UBound($afrmArray, 1) - 1 Then UserManager_ErrorHandler("Control reference invalid ", _ "Control Name: " & $sCtrlName & @CRLF & _ "Form Name: " & $afrmArray[0][0], "Fatal") SetError(1) EndIf EndFunc ; Application wide central message handler. ; Displays an error msg and exits the application if the error is fatal. Func UserManager_ErrorHandler($sError, $sSolution, $sImpact) If $sImpact = "Non-Fatal" Then MsgBox(8256, "User Manager", $sError & @CRLF & @CRLF & $sSolution) ElseIf $sImpact = "Fatal" Then MsgBox(8208, "User Manager", $sError & @CRLF & @CRLF & $sSolution) Exit EndIf EndFuncThe only thing which has changed is that that Application_ErrorHandler() function name is replaced with UserManager_ErrorHandler(), since this application is about managing user accounts.Continuing on the same lines as Part I discussion, lets make the code functional:expandcollapse popup#include <GUIConstants.au3> Global $afrmUserManager Global $afrmResetPassword CreateForm_frmUserManager($afrmUserManager) CreateForm_frmResetPassword($afrmResetPassword, $afrmUserManager[0][1]) GUISetState(@SW_SHOW, $afrmUserManager[0][1]) While 1 $msg = GuiGetMsg(1) Select Case $msg[1] = $afrmUserManager[0][1] Select Case $msg[0] = $GUI_EVENT_CLOSE GUIDelete($afrmUserManager[0][1]) GUIDelete($afrmResetPassword[0][1]) Exit Case $msg[0] = _GetCtrl("$cmdResetPwd", $afrmUserManager) ; Show frmResetPassword GUISwitch($afrmUserManager[0][1]) GUISetState(@SW_DISABLE) GUISwitch($afrmResetPassword[0][1]) GUISetState(@SW_SHOW) EndSelect Case $msg[1] = $afrmResetPassword[0][1] Select Case $msg[0] = _GetCtrl("$cmdCancel", $afrmResetPassword) GUISwitch(_GetCtrl("$frmParent", $afrmResetPassword)) GUISetState(@SW_ENABLE) GUISwitch($afrmResetPassword[0][1]) GUISetState(@SW_HIDE) EndSelect EndSelect Wend Exit Func CreateForm_frmUserManager(ByRef $afrmNew) Dim $afrmNew[4][2] $afrmNew[0][0] = "$frmUserManager" $afrmNew[0][1] = GUICreate("User Accounts", 396, 274, (@DesktopWidth-396)/2, (@DesktopHeight-274)/2) GUICtrlCreateGroup("User Accounts:", 8, 8, 380, 73) $afrmNew[1][0] = "$icoUsers" $afrmNew[1][1] = GUICtrlCreateIcon("shell32.dll", 50, 22, 32) GUICtrlCreateLabel("Select a local user account and click Reset Password. " & _ "You must have the required priviledges to reset passwords.", 70, 33, 301, 31) GUICtrlCreateLabel("Users for this computer:", 8, 90, 115, 17) $afrmNew[2][0] = "$lvwUserAccounts" $afrmNew[2][1] = GUICtrlCreateListView("Name |Full Name", 8, 110, 380, 121, _ BitOR($LVS_SINGLESEL, $LVS_SHOWSELALWAYS, $LVS_NOSORTHEADER), BitOR($LVS_EX_FULLROWSELECT, $WS_EX_CLIENTEDGE)) $afrmNew[3][0] = "$cmdResetPwd" $afrmNew[3][1] = GUICtrlCreateButton("Reset &Password...", 273, 240, 115, 25) EndFunc Func CreateForm_frmResetPassword(ByRef $afrmNew, $frmParent) Dim $afrmNew[6][2] $afrmNew[0][0] = "$frmResetPassword" $afrmNew[0][1] = GUICreate("Reset Password", 318, 107, (@DesktopWidth-100)/2, (@DesktopHeight-115)/2, _ $WS_CAPTION, -1, $frmParent) $afrmNew[1][0] = "$frmParent" $afrmNew[1][1] = $frmParent GUICtrlCreateLabel("New passsword:", 11, 13, 131, 13) $afrmNew[2][0] = "$txtNewPwd" $afrmNew[2][1] = GUICtrlCreateInput("", 143, 11, 165, 23, $ES_PASSWORD) GUICtrlCreateLabel("Confirm new passsword:", 11, 44, 131, 13) $afrmNew[3][0] = "$txtConfirmPwd" $afrmNew[3][1] = GUICtrlCreateInput("", 143, 41, 165, 23, $ES_PASSWORD) $afrmNew[4][0] = "$cmdOK" $afrmNew[4][1] = GUICtrlCreateButton("OK", 152, 75, 75, 23) $afrmNew[5][0] = "$cmdCancel" $afrmNew[5][1] = GUICtrlCreateButton("Cancel", 233, 75, 75, 23, $BS_DEFPUSHBUTTON) EndFunc Func _GetCtrl($sCtrlName, $afrmArray) For $i = 0 to UBound($afrmArray, 1) - 1 If $afrmArray[$i][0] = $sCtrlName Then Return $afrmArray[$i][1] EndIf Next ; Error Handler If $i > UBound($afrmArray, 1) - 1 Then UserManager_ErrorHandler("Control reference invalid ", _ "Control Name: " & $sCtrlName & @CRLF & _ "Form Name: " & $afrmArray[0][0], "Fatal") SetError(1) EndIf EndFunc ; Application wide central message handler. ; Displays an error msg and exits the application if the error is fatal. Func UserManager_ErrorHandler($sError, $sSolution, $sImpact) If $sImpact = "Non-Fatal" Then MsgBox(8256, "User Manager", $sError & @CRLF & @CRLF & $sSolution) ElseIf $sImpact = "Fatal" Then MsgBox(8208, "User Manager", $sError & @CRLF & @CRLF & $sSolution) Exit EndIf EndFuncOutput:frmUserManager:frmResetPassword:Clicking on the "Reset Password..." button shows frmResetPassword as a modal window and clicking the "Cancel" button hides the frmResetPassword and enables frmUserManagerThe application does not look like the finished application yet. In Part III of this discussion the application will be completely functional.Code review:The important thing to keep in mind is that the form handles are always stored as the Array[0][1] element of the Form Datatype array.So to refer to the form handle for frmUserManager, I've used $afrmUserManager[0][1] and similarily for frmResetPassword, I've referred to $afrmResetPassword[0][1]In the beginning of the script, a new global array variable is created for the form datatype of frmUserManager and the CreateForm_frmUserManager() function is used to populate this array with variable names and their corresponding control handles which mimics a FORM Datatype.Global $afrmUserManager Global $afrmResetPassword CreateForm_frmUserManager($afrmUserManager) CreateForm_frmResetPassword($afrmResetPassword, $afrmUserManager[0][1])The important part in this code is that after creating the frmUserManager Form Array, the function CreateForm_frmResetPassword() is called with $afrmUserManager array variable in the second argument. This makes frmUserManager the parent window to frmResetPassword.The main window frmUserManager is made visible by the following line:GUISetState(@SW_SHOW, $afrmUserManager[0][1])The rest of the code is the WHILE loop:While 1 $msg = GuiGetMsg(1) Select Case $msg[1] = $afrmUserManager[0][1] Select Case $msg[0] = $GUI_EVENT_CLOSE GUIDelete($afrmUserManager[0][1]) GUIDelete($afrmResetPassword[0][1]) Exit Case $msg[0] = _GetCtrl("$cmdResetPwd", $afrmUserManager) ; Show frmResetPassword GUISwitch($afrmUserManager[0][1]) GUISetState(@SW_DISABLE) GUISwitch($afrmResetPassword[0][1]) GUISetState(@SW_SHOW) EndSelect Case $msg[1] = $afrmResetPassword[0][1] Select Case $msg[0] = _GetCtrl("$cmdCancel", $afrmResetPassword) GUISwitch(_GetCtrl("$frmParent", $afrmResetPassword)) GUISetState(@SW_ENABLE) GUISwitch($afrmResetPassword[0][1]) GUISetState(@SW_HIDE) EndSelect EndSelect WendThe WHILE loop starts with calling GuiGetMsg() in the advanced mode $msg = GuiGetMsg(1)which returns an array with the form handle as the Array[1] element.This Array[1] element is compared against the form handles for frmUserManager and frmResetPassword.Based on which form the event is coming from, the code branches to that SELECT CASE section which determines next the control on the form which has caused the event.These events are:Form: frmUserManagerEvent: $GUI_EVENT_CLOSEfrmUserManager is the main form. A close event will exit the application. All the forms are deleted and the application exits.Case $msg[0] = $GUI_EVENT_CLOSE GUIDelete($afrmUserManager[0][1]) GUIDelete($afrmResetPassword[0][1]) ExitForm: frmUserManagerEvent: $cmdResetPwdUser clicked the "Reset Password..." button which will show frmResetPwd windowCase $msg[0] = _GetCtrl("$cmdResetPwd", $afrmUserManager) ; Show frmResetPassword GUISwitch($afrmUserManager[0][1]) GUISetState(@SW_DISABLE) GUISwitch($afrmResetPassword[0][1]) GUISetState(@SW_SHOW)To show frmResetPwd as a modal dialog window, its necessary to disable the parent window (frmUserManager first.Form: frmResetPasswordEvent: $cmdCancelUser clicked the "Cancel" button which hides the frmResetPassword windowCase $msg[0] = _GetCtrl("$cmdCancel", $afrmResetPassword) GUISwitch(_GetCtrl("$frmParent", $afrmResetPassword)) GUISetState(@SW_ENABLE) GUISwitch($afrmResetPassword[0][1]) GUISetState(@SW_HIDE)Before hiding the frmResetPassword window, it's necessary to enable the parent window first. Otherwise the active window focus will move to some other window.Although the code is more logically arranged, its already becoming large.In Part III I'll suggest ways to split a large AutoIt project with multiple forms into separate .au3 files.Any comments/suggestions/improvements are always welcome. Edited December 9, 2005 by tonedeaf
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