Before I begin, I just want to let you know that this is not a tutorial, but just a thread to explain what I did. I am not a great teacher nor do I claim to be of AHK_L objects. I hope this thread will interest others, and gain notice from the experts that a non-programmer was able to get somewhere with OOP in AHK_L, but would have gone farther if he received more support/better teaching materials. In any case, lets begin.
This is sample of my original work. This was when I first started out in AHK and programming in general.
DesktopReimage()
{
global ;StartTime
Critical, off
Userprompt()
if ErrorLevel
return
else
;StartTime := A_TickCount
Workorder()
Send, desktop rei{ENTER} ;Selects Desktop Reimage template
Sleep, 200
Division()
Timer()
Sleep 200
return
}As you can see, there are four other functions inside of this function. The name of the main function was the ticket I needed to create in our help desk software. Each time I wanted to make a separate function for a ticket, I basically had to make a copy just like the one above to achieve that. This can be both time consuming and heavy in terms of scripting, and if I there was a single change to the way our tickets were made, I would have to make a change to every function!!! This alone made me consider objects. But before I get to my OOP version, here are the four internal functions that each ticket function must have:
Timer()
{
global ;StartTime
WinWait, ahk_id %workorder%,
IfWinNotActive, ahk_id %workorder%, , WinActivate, ahk_id %workorder%,
WinWaitActive, ahk_id %workorder%,
Send {ALTDOWN}vtoo{ALTUP}{ENTER}
Sleep 200
Send {ALTDOWN}ooo{ALTUP}
SendRaw Look for the time prompt!
MsgBox,, %LISTBOX%, Press OK once you have finished resolving the ticket.
;MsgBox %StartTime%
;IfMsgbox Ok
;EndTime := A_Now
;MsgBox %EndTime%
ElapsedTime := A_TickCount - StartTime
;Msgbox %ElapsedTime%
SetFormat, Float, 0.2
ElapsedTime /= 3600000.00
MsgBox,, Elapsed Time, %ElapsedTime%
Sleep 200
WinWait ahk_id %workorder%,,10
IfWinNotActive ahk_id %workorder%,,10
WinActivate ahk_id %workorder%,,10
WinWaitActive ahk_id %workorder%,,10
if ErrorLevel
{
MsgBox, WinWait timed out.
return
}
else
;Sleep 200
;Send, {ALTDOWN}vtoo{ALTUP}{ENTER}
;Sleep 200
;Send {ALTDOWN}ooo{ALTUP}
;SendRaw Look for the time prompt!
Sleep 200
Send {ALTDOWN}oo{ALTUP}
Send %ElapsedTime%
return
}
Division() ;Writes in the division and department of the user
{
global
if DROPDOWN = DSF
Send, {ALTDOWN}uu{ALTUP}d{ENTER}{ALTDOWN}m{ALTUP}d{ENTER} ;Selects DSFNT4 selection
else if DROPDOWN = OSFNS
Send, {ALTDOWN}uu{ALTUP}f{DOWN}{ENTER}{ALTDOWN}m{ALTUP}f{ENTER} ;Selects for OSFNS selection
else if DROPDOWN = CENTRAL
Send, {ALTDOWN}uu{ALTUP}c{ENTER}{ALTDOWN}m{ALTUP}c{ENTER} ;Selects for Central users selection
else if DROPDOWN = PUPIL TRANSPORT
Send, {ALTDOWN}uu{ALTUP}p{DOWN 2}{ENTER}{ALTDOWN}m{ALTUP}p{ENTER} ;Selects for PUPIL TRANSPORT selection
else if DROPDOWN = OPTDEV
Send, {ALTDOWN}uu{ALTUP}a{ENTER}{ALTDOWN}m{ALTUP}o{ENTER} ;Selects for OPTDEV settings
else if DROPDOWN = PSAL
Send, {ALTDOWN}uu{ALTUP}a{DOWN}{ENTER}{ALTDOWN}m{ALTUP}f{ENTER} ;Selects for PSAL selection
else
Send, {ALTDOWN}uu{ALTUP}f{ENTER}{ALTDOWN}m{ALTUP}f{ENTER} ;Selects for OSFNS Field users selection
Sleep 200
Send {ALTDOWN}ii{ALTUP}.{ENTER} ;To select NON-POS user
}
Workorder(pos = 0) ;Creates the work order and opens template selection
{
global
IfWinNotActive Track-It! Technician Client,,3
WinActivate Track-It! Technician Client,,3
WinWaitActive Track-It! Technician Client,,3
if ErrorLevel
{
MsgBox, WinWait timed out.
return
}
else
Sleep, 200
Send, {CTRLDOWN}w{CTRLUP} ;Creates a new work order
WinWait, Work Order - New, ,,,Billing Information
;IfWinNotActive, Work Order - New, ,,,Look for the time prompt!
WinActivate, Work Order - New, ,,,Billing Information
WinWaitActive, Work Order - New, ,,,Billing Information
Sleep 300
WinGet, workorder, ID, Work Order - New
WinWait ahk_id %workorder%,,10
IfWinNotActive ahk_id %workorder%,,10
WinActivate ahk_id %workorder%,,10
WinWaitActive ahk_id %workorder%,,10
if ErrorLevel
{
MsgBox, WinWait timed out.
return
}
else
Sleep, 200
if (pos = "pos")
{
Send, %name% {ENTER}
}
Sleep, 200
Send, {ALTDOWN}ams{ALTUP} ;Function to call up template selection
StartTime := A_TickCount
WinWait Apply Template,,3
IfWinNotActive Apply Template,,3
WinActivate Apply Template,,3
WinWaitActive Apply Template,,3
if ErrorLevel
{
MsgBox, WinWait timed out.
return
}
}
Userprompt() ;Begins the first prompt for user's name
{
global
WinWait, Track-It! Technician Client, ,3
if ErrorLevel
{
Run C:\Documents and Settings\%A_Username%\Start Menu\Programs\Numara Track-It!\Numara Track-It! Technician Client.appref-ms
;MsgBox, TrackIt! is not open.
return
}
else if DROPDOWN = DSF
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of DSF user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$") ;Tests to see if user input has last and first name
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = OSFNS
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of OSFNS user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = OSFNS FIELD
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of OSFNS FIELD user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = PUPIL TRANSPORT
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of OPT user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = OPTDEV
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of OPTDEV user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = PSAL
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of PSAL user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else
{
loop
{
InputBox, name, Enter School Code, Enter custodian school code,
if ErrorLevel
return
;RegExMatch(name, "i)[xkqmr]\d{3}", test)
;if test <> %name%
if !RegExMatch(name, "i)^[xkqmr]\d{3}$")
{
MsgBox,, Error, You did not enter the school code correctly (eg. x123).
continue
}
else
break
}
StringLower, name, name
}
}I had made over 30 regular, as opposed to irregular, tickets using this model. So any change outside of the four functions, I was looking at 30 or more changes at least.
Now onto the OOP conversion, this is the class I used:
class Ticket
{
__New(template, audible = 0)
{
this.template := template
this.audible := audible
global StartTime
this.Userprompt(this.audible)
StartTime := A_TickCount
if ErrorLevel <> 0
return
else
this.Workorder(this.audible)
Send % this.template
Sleep 200
Send {ENTER}
Sleep 200
this.Division(this.audible)
this.Timer(this.audible)
;return
}
Userprompt(audible = 0) ;Begins the first prompt for user's name
{
global
if (audible = "pos")
{
return
}
else
Sleep 200
WinWait, Track-It! Technician Client, ,3
if ErrorLevel
{
Run C:\Documents and Settings\%A_Username%\Start Menu\Programs\Numara Track-It!\Numara Track-It! Technician Client.appref-ms
;MsgBox, TrackIt! is not open.
return
}
else if DROPDOWN = DSF
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of DSF user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$") ;Tests to see if user input has last and first name
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = OSFNS
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of OSFNS user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = OSFNS FIELD
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of OSFNS FIELD user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = PUPIL TRANSPORT
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of OPT user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = OPTDEV
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of OPTDEV user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else if DROPDOWN = PSAL
{
loop
{
InputBox, name, Enter Name of Client, Enter last name first name of PSAL user,
if ErrorLevel
return
if !RegExMatch(name, "^.{1,}\s.{1,}$")
{
MsgBox,, Error, You did not enter the username correctly (eg. Surname Given name).
continue
}
else
break
}
}
else
{
loop
{
InputBox, name, Enter School Code, Enter custodian school code,
if ErrorLevel
return
;RegExMatch(name, "i)[xkqmr]\d{3}", test)
;if test <> %name%
if !RegExMatch(name, "i)^[xkqmr]\d{3}$")
{
MsgBox,, Error, You did not enter the school code correctly (eg. x123).
continue
}
else
break
}
StringLower, name, name
}
}
Workorder(audible = 0) ;Creates the work order and opens template selection
{
global
IfWinNotActive Track-It! Technician Client,,3
WinActivate Track-It! Technician Client,,3
WinWaitActive Track-It! Technician Client,,3
if ErrorLevel
{
MsgBox, WinWait timed out.
return
}
else
Sleep, 200
Send, {CTRLDOWN}w{CTRLUP} ;Creates a new work order
WinWait, Work Order - New, ,,,Billing Information
;IfWinNotActive, Work Order - New, ,,,Look for the time prompt!
WinActivate, Work Order - New, ,,,Billing Information
WinWaitActive, Work Order - New, ,,,Billing Information
Sleep 300
WinGet, workorder, ID, Work Order - New
WinWait ahk_id %workorder%,,10
IfWinNotActive ahk_id %workorder%,,10
WinActivate ahk_id %workorder%,,10
WinWaitActive ahk_id %workorder%,,10
if ErrorLevel
{
MsgBox, WinWait timed out.
return
}
else
Sleep, 200
if (audible != "pos")
{
Send, %name% {ENTER}
}
Sleep, 200
Send, {ALTDOWN}ams{ALTUP} ;Function to call up template selection
StartTime := A_TickCount
WinWait Apply Template,,3
IfWinNotActive Apply Template,,3
WinActivate Apply Template,,3
WinWaitActive Apply Template,,3
if ErrorLevel
{
MsgBox, WinWait timed out.
return
}
}
Division(audible = 0) ;Writes in the division and department of the user
{
global
if (audible = "pos")
{
return
}
else
if DROPDOWN = DSF
Send, {ALTDOWN}uu{ALTUP}d{ENTER}{ALTDOWN}m{ALTUP}d{ENTER} ;Selects DSFNT4 selection
else if DROPDOWN = OSFNS
Send, {ALTDOWN}uu{ALTUP}f{DOWN}{ENTER}{ALTDOWN}m{ALTUP}f{ENTER} ;Selects for OSFNS selection
else if DROPDOWN = CENTRAL
Send, {ALTDOWN}uu{ALTUP}c{ENTER}{ALTDOWN}m{ALTUP}c{ENTER} ;Selects for Central users selection
else if DROPDOWN = PUPIL TRANSPORT
Send, {ALTDOWN}uu{ALTUP}p{DOWN 2}{ENTER}{ALTDOWN}m{ALTUP}p{ENTER} ;Selects for PUPIL TRANSPORT selection
else if DROPDOWN = OPTDEV
Send, {ALTDOWN}uu{ALTUP}a{ENTER}{ALTDOWN}m{ALTUP}o{ENTER} ;Selects for OPTDEV settings
else if DROPDOWN = PSAL
Send, {ALTDOWN}uu{ALTUP}a{DOWN}{ENTER}{ALTDOWN}m{ALTUP}f{ENTER} ;Selects for PSAL selection
else
Send, {ALTDOWN}uu{ALTUP}f{ENTER}{ALTDOWN}m{ALTUP}f{ENTER} ;Selects for OSFNS Field users selection
Sleep 200
Send {ALTDOWN}ii{ALTUP}.{ENTER} ;To select NON-POS user
}
Timer(audible = 0)
{
global ;StartTime
if (audible = "pos")
{
return
}
else
WinWait, ahk_id %workorder%,
IfWinNotActive, ahk_id %workorder%, , WinActivate, ahk_id %workorder%,
WinWaitActive, ahk_id %workorder%,
Send {ALTDOWN}vtoo{ALTUP}{ENTER}
Sleep 200
Send {ALTDOWN}ooo{ALTUP}
SendRaw Look for the time prompt!
MsgBox,, %LISTBOX%, Press OK once you have finished resolving the ticket.
;MsgBox %StartTime%
;IfMsgbox Ok
;EndTime := A_Now
;MsgBox %EndTime%
ElapsedTime := A_TickCount - StartTime
;Msgbox %ElapsedTime%
SetFormat, Float, 0.2
ElapsedTime /= 3600000.00
MsgBox,, Elapsed Time, %ElapsedTime%
Sleep 200
WinWait ahk_id %workorder%,,10
IfWinNotActive ahk_id %workorder%,,10
WinActivate ahk_id %workorder%,,10
WinWaitActive ahk_id %workorder%,,10
if ErrorLevel
{
MsgBox, WinWait timed out.
return
}
else
;Sleep 200
;Send, {ALTDOWN}vtoo{ALTUP}{ENTER}
;Sleep 200
;Send {ALTDOWN}ooo{ALTUP}
;SendRaw Look for the time prompt!
Sleep 200
Send {ALTDOWN}oo{ALTUP}
Send %ElapsedTime%
return
}
Technician(tech = 0)
{
if (tech = "pos")
Send !g.pos{ENTER}
else if (tech = "evens")
Send !gjos{ENTER}
else if (tech = "field")
Send !g.fie{ENTER}
else
return
return
}
}Basically, I put in all my older functions in a class format ready for object deployment. Now all my tickets looked like this:
DesktopUpdateandMaintenance()
{
desktopupdate := new Ticket("04")
}Each new ticket effectively became an object from the class I made. Now if there were any changes to the ticket making process, I would just tinker with the class while leaving the 30 or so objects intact, yay!
What's even cooler is that OOP gave me the ability to control the ticketing software using methods in the class. So I had a feature where I can choose the "Technician" of the ticket, it looked like this:
POSComboSchoolRequest()
{
comborequest := new Ticket("001", "pos")
comborequest.Technician("pos")
}When the new object/ticket is made, I can use a method of that very same object, called Technician in this case, to introduce a parameter to send the name of the technician. Very neat!
Well, this has been a very quick and dirty run-through on what I did with OOP. I was playing around with meta-functions until I gave up on the whole process because I did not feel confident nor knowledgeable about AHK_L objects and its future.
If you have any more questions, feel free to ask. I know this is not the clearest example, but it was the only one that I made, and that worked in the real world. Thanks to everyone in the AHK_L community!




