470,822 Members | 1,260 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Share your developer knowledge by writing an article on Bytes.

Class Module to Handle Opening Forms Hierarchically

32,311 Expert Mod 16PB

This article shows how to set up and use a Class Module, as well as, more specifically, how to open forms such that they appear as a hierachical menu structure. Form A opens Form B and, while Form B is still open, remains hidden from view. As and when Form B terminates, Form A comes back into view and reassumes the focus.

The code for classForm below includes examples of setting class properties as well as various methods. Of particular interest among the methods is the encapsulated event handler frmCalled_Close(), which is able to be triggered due to the WithEvents keyword used in line #19 (See code below).

Module Code

Expand|Select|Wrap|Line Numbers
  1. Option Compare Database
  2. Option Explicit
  4. '21/1/2004  Added Private Set & Public Get code for frmTo.
  5. '21/9/2004  Removed ResumeTo functionality. _
  6.             Now handled by the OnTimer() subroutine in the calling form _
  7.             checking for (Visible) which indicates the called form is finished.
  8. '24/2/2005  Added function Uninitialised to show if instance of this object _
  9.             has yet been initialised with the callers info. _
  10.             It also checks this before it tries to open a new form.
  11. '31/3/2008  Added varOpenArgs as optional parameter to ShowForm.  Simply to be _
  12.             passed directly to the opened form using DoCmd.OpenForm(). _
  13.             Also set .OpenForm() to treat Cancel of the open as NOT an error.
  15. Private Const conUnInitMsg As String = _
  16.                   "Object uninitialised - unable to show form."
  18. Private frmParent As Form
  19. Private WithEvents frmCalled As Form
  21. Public Property Set frmFrom(frmValue As Form)
  22.     Set frmParent = frmValue
  23. End Property
  25. Private Property Get frmFrom() As Form
  26.     Set frmFrom = frmParent
  27. End Property
  29. Private Property Set frmTo(frmValue As Form)
  30.     Set frmCalled = frmValue
  31. End Property
  33. Public Property Get frmTo() As Form
  34.     Set frmTo = frmCalled
  35. End Property
  37. 'Uninitialised returns True if frmFrom not yet initialised.
  38. Public Function Uninitialised() As Boolean
  39.     Uninitialised = (frmParent Is Nothing)
  40. End Function
  42. 'ShowForm opens form strTo and hides the calling form.  Returns True on success.
  43. Public Function ShowForm(strTo As String, _
  44.                          Optional strFilter As String = "", _
  45.                          Optional varOpenArgs As Variant = Null) As Boolean
  46.     ShowForm = True
  47.     'Don't even try if caller hasn't initialised Form object yet
  48.     If Uninitialised() Then
  49.         ShowForm = False
  50.         Call ShowMsg(strMsg:=conUnInitMsg, strTitle:="classForm.ShowForm")
  51.         Exit Function
  52.     End If
  53.     Call DoCmd.Restore
  54.     'Handle error on OpenForm() only.
  55.     On Error GoTo ErrorSF
  56.     Call DoCmd.OpenForm(FormName:=strTo, _
  57.                         WhereCondition:=strFilter, _
  58.                         OpenArgs:=varOpenArgs)
  59.     On Error GoTo 0
  60.     Set frmTo = Forms(strTo)
  61.     frmFrom.Visible = False
  62.     Exit Function
  64. ErrorSF:
  65.     ShowForm = False
  66.     ' If open is cancelled (either by user or code) then simply exit
  67.     If Err.Number <> 2501 Then _
  68.         Call ErrorHandler(strName:=strTo, _
  69.                           strFrom:=frmFrom.Name & ".ShowForm", _
  70.                           lngErrNo:=Err.Number, _
  71.                           strDesc:=Err.Description)
  72. End Function
  74. '************************* Contained Object Method(s) *************************
  75. 'For these subroutines to be activated the contained object must have the
  76. ''On Close' property set to a valid subroutine within the contained object.
  77. Private Sub frmCalled_Close()
  78.     frmFrom.Visible = True
  79.     Call DoCmd.Restore
  80.     Set frmTo = Nothing
  81. End Sub
  82. '******************************************************************************

Calling and Using Code

Expand|Select|Wrap|Line Numbers
  1. Option Compare Database
  2. Option Explicit
  4. Private clsTo As New classForm
  6. Private Sub Form_Open(Cancel As Integer)
  7.     Set clsTo.frmFrom = Me
  8. End Sub
  10. Private Sub cmdWhatever_Click()
  11.     Call clsTo.ShowForm(strTo:="frmWhatever")
  12. End Sub
  14. Private Sub cmdExit_Click()
  15.     Call DoCmd.Close
  16. End Sub
  18. Private Sub Form_Close()
  19.     'Method must exist in order for container to handle event.
  20. End Sub
Line #4 indicates the declaration for the classForm object.
Line #7 indicates the basic setting up of the object. This tells the class which form is the caller for returning to after any called form terminates.
Line #11 indicates calling another form. At this point in the code the class takes over and hides the calling form as well as showing the called form.
Lines #18 through #20 indicate a stub of an event handler that must exist if the class is to be able to capture the called form terminating. This is necessary for the class to re-show the caller form.
Sep 26 '11 #1
7 6410
1,263 Expert 1GB
That looks like a very useful class. Thanks for the post. :)
Sep 27 '11 #2
Shouldn't a couple of the properties in the class module be Public rather than Private?
Expand|Select|Wrap|Line Numbers
  1. Private Property Get frmFrom() As Form
will stop you being able to use
Expand|Select|Wrap|Line Numbers
  1. Set clsTo.frmFrom = Me
May 1 '18 #3
32,311 Expert Mod 16PB
Are you sure?

I haven't got a copy to hand ATM but it works so I'm not sure what you say makes sense.

If you can show it doesn't work then I'll happily spend the time looking into it, but if you're just confused and want me to do the checking for you then that doesn't work for me.
May 3 '18 #4
Sorry, I should have worded it differently - no, not confused as such just not checking how the code works properly.

My confusion resulted from Private Property Get frmFrom() As Form being declared as Private which caused the intellisense not to suggest frmFrom when I added the Form_Open event.

frmTo is only used within the class module though, so can be Private. This then raises the question of whether it is the better practice to use frmFrom(Property)or frmParent(Member Variable?) within the class - I've no idea, and may be beyond the scope of this question?

Either way - the code works as intended.

Hopefully that made sense.
May 3 '18 #5
32,311 Expert Mod 16PB
Darren Bartrup:
This then raises the question of whether it is the better practice to use frmFrom(Property)or frmParent(Member Variable?) within the class - I've no idea, and may be beyond the scope of this question?
Not beyond the scope. I'm very happy to answer that.

With OOP (Object Oriented Programming) it's very much about boundaries. Manipulating {Instance}.{Property} is generally frowned upon, as this allows the using process uncontrolled access to the class instance. Generally speaking, in OOP, where a class designer wants a using process to have access to elements of the class instance they will (should) provide Property Gets and Property Sets to support that controlled access.

Obviously, it's not always strictly necessary, but it's generally considered good practice, or at least so I understand. Particularly when there is any desire to restrict how the values can be set. I really can't claim to be the best expert at OOP mind you.
May 3 '18 #6
That makes perfect sense, thanks for the pointers.
May 4 '18 #7
32,311 Expert Mod 16PB
Darren Bartrup:
Thanks for the pointers.
No. They're Class Instances! (J/k).

Glad I was able to help :-)
May 4 '18 #8

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

42 posts views Thread by WindAndWaves | last post: by
2 posts views Thread by windandwaves | last post: by
1 post views Thread by Alasdair | last post: by
5 posts views Thread by Shawn Hogan | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.