-
[ 1 ] [ 2
] [ 3 ] [ 4 ]
*---------------------------------------------
- *-- Sample for Hook Operation design pattern
- *-- Copyright 1997 by Steven Black
- *-- Version 1.0 May 22 1997
- *---------------------------------------------
-
- *-- Create a hookable form
- oForm= CREATE("Frm")
-
- *-- Describe what the user should do
- oForm.Caption= "RightClick around to execute hooks"
-
- *-- add a hookable textbox
- oForm.Addobject("txt", "Txt")
-
- *-- add a hookable combobox
- oForm.Addobject("Cbo", "Cbo")
- oForm.Cbo.Top= 30
-
- *-- add dropdown and interactivechange behavior to
- *-- combobox by using hooks
- LOCAL loTemp
- loTemp= CREATE("DropDown")
- oForm.Cbo.SetoHook( loTemp)
- loTemp= CREATE("Interactivechange")
- oForm.Cbo.SetoHook( loTemp)
- RELEASE loTemp
- oForm.Cbo.ToolTipText="Make a selection to execute hooks"
- oForm.Cbo.StatusBarText="Make a selection to execute hooks"
-
- *-- Give all controls the Form's Right-click behavior
- oForm.txt.SetoHook( oForm)
- oForm.cbo.SetoHook( oForm)
-
- *-- add a general shared debug utility object
- oForm.Addobject( "Debug", "DebugMenuHook")
- oForm.Debug.Top= 60
-
- *-- Give all controls the debug menu behavior
- *-- (via form, which is already in the hook chain)
- oForm.SetoHook( oForm.Debug)
-
- *-- Show the works, though you wouldn't normally
- *-- make the debug hook object visible
- oForm.Setall("Visible", .T.)
- oForm.Show()
- READ EVENTS
-
- **************************************************
- * Abstract Hook Behavior Class
- **************************************************
- *-- Class: abstracthook
- *-- ParentClass: label
- *-- BaseClass: label
- *-- Baseclass for hooks
- *
- DEFINE CLASS abstracthook AS label
- Caption = "Hook"
- ohook = .NULL.
- width= 150
- BackColor= RGB(0,255,0)
- Name = "abstracthook"
-
- PROCEDURE Init
- *-- Say something smart
- THIS.Caption= THIS.Class
- ENDPROC
-
- PROCEDURE release
- *-- Release from memory.
- RELEASE THIS
- ENDPROC
-
- PROCEDURE GarbageCollect
- *-- Clean up pointers
- THIS.oHook= .NULL.
- ENDPROC
-
- *=== Hooked Events and Methods ====
- * SetoHook( o)
- * RightClick()
- * PopUpMenu()
- * InteractiveChange()
- * DropDown()
-
- PROCEDURE setohook
- *-- Automate the hook setting process. If a hook
- *-- already exists, hook to it, thus adding to the
- *-- hook chain.
- PARAMETERS toPassed
- IF TYPE( "THIS.oHook")= "O" AND ;
- PEMSTATUS( THIS.oHook, "oHook",
5)
- THIS.oHook.SetoHook( toPassed)
- ELSE
- THIS.oHook= toPassed
- ENDIF
- ENDPROC
-
- PROCEDURE RightClick
- IF TYPE( "THIS.oHook")= "O" AND ;
- PEMSTATUS( THIS.oHook, "RightClick",
5)
-
- THIS.oHook.RightClick
- ENDIF
- RELEASE POPUPS Shortcut
- DEFINE POPUP shortcut SHORTCUT RELATIVE FROM MROW(),MCOL()
-
- THIS.PopupMenu()
- IF CNTBAR( "Shortcut") > 0
- ACTIVATE POPUP Shortcut
- ENDIF
- ENDPROC
-
- PROCEDURE popupmenu
- *-- Delegate to the implementation chain
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "PopUpMenu",
5)
- RETURN THIS.oHook.PopupMenu()
- ENDIF
- ENDPROC
-
- *-- Occurs when the user changes the value of a
- *-- control using the keyboard or the mouse.
- PROCEDURE interactivechange
- *-- Delegate to the implementation chain
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "InteractiveChange",
5)
- RETURN THIS.oHook.InteractiveChange()
- ENDIF
- ENDPROC
-
- *-- Occurs when the list portion of a ComboBox
- *-- control is about to drop down after the drop-down ;
- *-- arrow is clicked.
- PROCEDURE dropdown
- *-- Delegate to the implementation chain
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "DropDown",
5)
- RETURN THIS.oHook.DropDown()
- ENDIF
- ENDPROC
- ENDDEFINE
-
- **************************************************
- * Developer's Debug Menu Behavior (partial)
- **************************************************
- *-- Class: debugmenuhook
- *-- ParentClass: abstracthook
- *-- BaseClass: label
- *-- Hook that produces debug choices in the
- *-- current shortcut menu
- *
- DEFINE CLASS debugmenuhook AS abstracthook
- Name = "debugmenuhook"
- PROCEDURE popupmenu
- DoDefault()
- DEFINE BAR 1001 OF shortcut PROMPT "\-"
- DEFINE BAR 1002 OF shortcut PROMPT "Debug"
;
- MESSAGE "Invokes the debug window"
- DEFINE BAR 1003 OF shortcut PROMPT "\<Trace"
;
- MESSAGE "Invokes the trace window"
- DEFINE BAR 1004 OF shortcut PROMPT "\<Cancel"
;
- MESSAGE "Cancel execution"
- DEFINE BAR 1005 OF shortcut PROMPT "\<Suspend"
;
- MESSAGE "Suspend execution"
- ENDPROC
- ENDDEFINE
-
- **************************************************
- * Drop Down Behavior
- **************************************************
- *-- Class: DropDown
- *-- ParentClass: abstracthook
- *-- BaseClass: label
- *-- Hook implementing dropdown eventbehavioor
- *
- DEFINE CLASS DropDown AS abstracthook
- noldbackcolor = 0
- Name = "DropDown"
-
- PROCEDURE Destroy
- _SCREEN.BackColor= THIS.nOldBackColor
- ENDPROC
-
- PROCEDURE Init
- DODEFAULT()
- THIS.nOldBackColor= _SCREEN.BackColor
- ENDPROC
-
- PROCEDURE dropdown
- _SCREEN.BackColor= RAND()*255^3
- ENDPROC
- ENDDEFINE
-
- **************************************************
- * Interactive Change Behavior
- **************************************************
- *-- Class: Interactivechange
- *-- ParentClass: abstracthook
- *-- BaseClass: label
- *-- Hook implementing interactivechange behavior
- *
- DEFINE CLASS Interactivechange AS abstracthook
- Name = "Interactivechange"
-
- PROCEDURE interactivechange
- DoDefault()
- ACTIVATE SCREEN
- ?"Interactive Change Fires"
- ENDPROC
- ENDDEFINE
-
- **************************************************
- * Hookable Combobox
- **************************************************
- *-- Class: cbo
- *-- ParentClass: combobox
- *-- BaseClass: combobox
- *
- DEFINE CLASS cbo AS combobox
- Height = 23
- Width = 200
- *-- Hook reference
- ohook = .NULL.
- Name = "cbo"
-
- PROCEDURE Init
- THIS.AddItem( "FoxTeach")
- THIS.AddItem( "Great Lakes GREAT Database Workshop")
- THIS.AddItem( "Minneapolis User's Confernence")
- THIS.AddItem( "Devcon")
- THIS.AddItem( "German FoxPro User's Conference")
- THIS.AddItem( "Dutch FoxPro User's Conference")
- THIS.AddItem( "Mid-Atlantic FoxPro Conference")
- ENDPROC
-
- PROCEDURE GarbageCollect
- *-- Clean up pointers
- THIS.oHook= .NULL.
- ENDPROC
-
- *-- Releases from memory.
- PROCEDURE release
- RELEASE THIS
- ENDPROC
-
- *=== Hooked Events and Methods ====
- * SetoHook( o)
- * RightClick()
- * PopUpMenu()
- * DblCLick()
- * Click()
- * InteractiveChange()
- * DropDown()
-
- PROCEDURE setohook
- *-- Automate the hook setting process. If a hook
- *-- already exists, hook to it, thus adding to the
- *-- hook chain.
- PARAMETERS toPassed
- IF TYPE( "THIS.oHook")= "O" AND ;
- PEMSTATUS( THIS.oHook, "oHook",
5)
-
- THIS.oHook.SetoHook( toPassed)
- ELSE
- THIS.oHook= toPassed
- ENDIF
- ENDPROC
-
- PROCEDURE RightClick
- *-- Pre-process hook
- IF TYPE( "THIS.oHook")= "O" AND ;
- PEMSTATUS( THIS.oHook, "RightClick",
5)
-
- THIS.oHook.RightClick
- ENDIF
- *-- Define a shortcut menu
- RELEASE POPUPS ShortCut
- DEFINE POPUP shortcut SHORTCUT RELATIVE ;
- FROM MROW(),MCOL()
- *-- Delegate to a shortcut builder
- THIS.PopupMenu()
-
- *-- Activate the shortcut
- IF CNTBAR( "Shortcut") > 0
- ACTIVATE POPUP Shortcut
- ENDIF
- ENDPROC
-
- PROCEDURE popupmenu
- *-- Delegate to the implementation chain
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "PopUpMenu",
5)
- RETURN THIS.oHook.PopUpMenu()
- ENDIF
- ENDPROC
-
- PROCEDURE DblClick
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "DblClick",
5)
- THIS.oHook.DblClick
- ENDIF
- ENDPROC
-
- PROCEDURE Click
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "Click",
5)
- RETURN THIS.oHook.Click()
- ENDIF
- ENDPROC
-
- PROCEDURE DropDown
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "DropDown",
5)
- RETURN THIS.oHook.DropDown()
- ENDIF
- ENDPROC
-
- PROCEDURE InteractiveChange
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "InteractiveChange",
5)
- RETURN THIS.oHook.InteractiveChange()
- ENDIF
- ENDPROC
- ENDDEFINE
-
-
- **************************************************
- *-- Class: frm
- *-- ParentClass: form
- *-- BaseClass: form
- *-- Form with Rightmouse Behavior
- *
- DEFINE CLASS frm AS form
- DoCreate = .T.
- Caption = "Hooked Form"
- ohook = .NULL.
- AutoCenter= .T.
- Name = "frm"
- Showtips= .T.
-
- PROCEDURE Release
- *-- Release from memory
- THIS.GarbageCollect()
- RELEASE THIS
- ENDPROC
-
- PROCEDURE GarbageCollect
- *-- Clean up pointers
- *-- ... recursively
- LOCAL lni
- FOR lni= 1 TO THIS.ControlCount
- THIS.Controls[lni].GarbageCollect()
- ENDFOR
- THIS.oHook= .NULL.
- ENDPROC
-
- PROCEDURE QueryUnload
- *-- Clean up first
- THIS.GarbageCollect()
- ENDPROC
-
- PROCEDURE Destroy
- CLEAR EVENTS
- ENDPROC
-
- *=== Hooked Events and Methods ====
- * SetoHook( o)
- * RightClick()
- * PopUpMenu()
- * InteractiveChange()
- * DropDown()
-
- PROCEDURE setohook
- *-- Automate the hook setting process. If a hook
- *-- already exists, hook to it, thus adding to the
- *-- hook chain.
- LPARAMETERS txPassed
- IF !ISNULL( THIS.oHook)
- THIS.oHook.SetOhook( txPassed)
- ELSE
- THIS.oHook= TXPassed
- ENDIF
- ENDPROC
-
- PROCEDURE RightClick
- *-- Define a shortcut
- RELEASE POPUPS Shortcut
- DEFINE POPUP shortcut SHORTCUT RELATIVE ;
- FROM MROW(),MCOL()
- *-- Delegate to a shortcut specialty method
- THIS.PopupMenu()
- *-- Activate the shortcut
- IF CNTBAR( "Shortcut") > 0
- ACTIVATE POPUP Shortcut
- ENDIF
- ENDPROC
-
- PROCEDURE popupmenu
- *-- 3 sample shortcut menu bars
- DEFINE BAR 100 OF shortcut PROMPT "Properties"
;
- MESSAGE "Display the properties sheet"
- DEFINE BAR 200 OF shortcut PROMPT "Builders"
;
- MESSAGE "Invoke custom builders"
- DEFINE BAR 300 OF shortcut PROMPT "Code" ;
- MESSAGE "Edit underlying code"
- *-- Delegate to the implementation chain
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "PopUpMenu",
5)
- RETURN THIS.oHook.PopupMenu()
- ENDIF
- ENDPROC
-
- PROCEDURE dropdown
- *-- Occurs when the list portion of a ComboBox
- *-- control is about to drop down after the
- *-- drop-down arrow is clicked.
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "DropDown",
5)
- RETURN THIS.oHook.DropDown()
- ENDIF
- ENDPROC
-
- PROCEDURE interactivechange
- *-- Occurs when the user changes the value ;
- *-- of a control using the keyboard or the mouse.
- *-- Fire pre-process hook
- IF ! ISNULL( THIS.oHook) AND ;
- TYPE( "THIS.oHook") = "O"
AND ;
- PEMSTATUS( THIS.oHook, "InteractiveChange",
5)
- RETURN THIS.oHook.InteractiveChange()
- ENDIF
- ENDPROC
- ENDDEFINE
-
- **************************************************
- *-- Class: txt (c:\_workshop\hooks.vcx)
- *-- ParentClass: textbox
- *-- BaseClass: textbox
- *-- Textbox with Rightmouse Behavior
- *
- DEFINE CLASS txt AS textbox
- Height = 23
- Width = 100
- *-- Hook reference
- ohook = .NULL.
- Name = "txt"
-
- PROCEDURE GarbageCollect
- *-- Clean up pointers
- THIS.oHook= .NULL.
- ENDPROC
-
- *-- Releases from memory.
- PROCEDURE release
- RELEASE THIS
- ENDPROC
-
- PROCEDURE popupmenu
- DEFINE BAR _med_cut OF shortcut PROMPT "Cu\<t"
;
- KEY CTRL+X, "Ctrl+X" ;
- MESSAGE ;
- "Removes the selection and places
it onto the Clipboard"
- DEFINE BAR _med_copy OF shortcut PROMPT "\<Copy"
;
- KEY CTRL+C, "Ctrl+C" ;
- MESSAGE "Copies the selection onto the
Clipboard"
- DEFINE BAR _med_paste OF shortcut PROMPT "\<Paste"
;
- KEY CTRL+V, "Ctrl+V" ;
- MESSAGE "Pastes the contents of the
Clipboard"
- DEFINE BAR _med_slcta OF shortcut PROMPT "Se\<lect
All" ;
- KEY CTRL+A, "Ctrl+A" ;
- MESSAGE "Selects all text or items in
the current window"
- DEFINE BAR _med_clear OF shortcut PROMPT "Cle\<ar"
;
- MESSAGE ;
- "Removes the selection and
does not place it onto the Clipboard"
- *-- Delegate to the implementation chain
- loTemp= THIS.oHook
- IF ! ISNULL( loTemp) AND ;
- TYPE( "loTemp") = "O"
AND ;
- PEMSTATUS( loTemp, "PopUpMenu",
5)
- RETURN loTemp.PopupMenu()
- ENDIF
- ENDPROC
-
- PROCEDURE setohook
- *-- Automate the hook setting process. If a hook
- *-- already exists, hook to it, thus adding to the
- *-- hook chain.
- PARAMETERS toPassed
- IF TYPE( "THIS.oHook.oHook")<> "U"
- THIS.oHook.SetoHook( toPassed)
- ELSE
- THIS.oHook= toPassed
- ENDIF
- ENDPROC
-
- PROCEDURE Click
- IF ! ISNULL( This.oHook)
- THIS.oHook.Click
- ENDIF
- ENDPROC
-
- PROCEDURE RightClick
- RELEASE POPUPS ShortCut
- DEFINE POPUP shortcut SHORTCUT RELATIVE ;
- FROM MROW(),MCOL()
- THIS.PopupMenu()
- IF CNTBAR( "Shortcut") > 0
- ACTIVATE POPUP Shortcut
- ENDIF
- ENDPROC
-
- PROCEDURE DblClick
- IF ! ISNULL( This.oHook)
- THIS.oHook.DblClick
- ENDIF
- ENDPROC
- ENDDEFINE
Listing 13. Several objects sharing common shortcut menus using chained hooks.
When you rightclick over the textbox, control is passed to the hook, which
invokes a context sensitive shortcut menu. Some other things to draw from this
example:
The hooked objects and the hooks don’t need to be of the same Baseclass.
Hooks can be lightweight objects, like labels, lines, or even Relations (which
are ultra-lightweight).
Hooks can be shared by more than one object. There is nothing stopping us from
having all the controls on our form pointing to the same hook.
Conclusion
Classes with seeded with hook operations are generally more flexible than those
that aren’t. If you define hook operations consistently and predictably throughout
your application, then it’s usually possible to attach new behavior to satisfy
the needs of a particular instance without subclassing. Moreover, hook operations
can be reckoned and bound at run time.
Interesting also that the hook operation design pattern is applicable in both
object and non-object oriented programming.
[ 1 ] [ 2
] [ 3 ] [ 4 ]