Access pattern · popup pass-back
CallCalled Class Module
A popup helper so the calling control’s caption becomes the popup form caption, and a Simulated After Update so the calling form can recalculate when the popup closes. Paste the class into your database. No sample file on this page.
Videos that used to sit on this page may return later. The class and the written explanation are here now.
Class module overview
You can see how the class module gives a popup form some excellent functionality. It grabs the caption of the calling control and uses it as the caption of the popup. Call the same popup from several different controls and you do not have to write that caption code yourself — it is in the class.
Simulated After Update
The class can trigger what I call a Simulated After Update Event. The calling form (the one that opened the popup) can do a calculation as soon as the popup closes. Examples:
- A measurements popup: enter the figures, the sum is written back into the calling control.
- A date range: check that an “after” date is greater than the “before” date.
- Someone’s age: calculate and display it immediately, without waiting for the form’s On Current event.
The popup caption changes depending on which control opened it. All of the work to extract the calling control’s caption is in CallCalled. It can also run code on the calling form — a utility I do not believe is available anywhere else. That is the Simulated After Update.
Popup forms — easy
I used to call this “magic”. When I first saw information moving between objects like this, I was fascinated. I spent a long time working out what happened, and how I could use it in my own coding. I am still nowhere near a master of it. I hope you find the magic I found — it was one of the main reasons I got involved in producing VBA. You can do just about anything with it.
Calendar form code
An earlier version of CallCalled sat under a popup calendar: click a text box or a command button, pick a date, close. Using the class instead of writing your own VBA makes it a simple process to open that calendar from any (several) controls on the form.
Extra functionality: the name of the calling control, gathered from its label, becomes the form caption, so you can see which date you are amending. The class can also check whether the calling form is still open. If someone closed it by mistake, you can stop error messages landing on the user.
That calendar demonstration used Allen Browne’s popup Calendar Form amalgamated with this class.
Since 2009 I have updated the class. You no longer have to pass PassBackRun in OpenArgs.
There is a routine fHASfPassBackRun that tests for fPassBackRun when the class opens.
I did not like the old test, because if the function does not exist it throws an error.
I was always advised never to rely on error messages to operate your code.
Some code written by Allen Browne uses that method, and I thought: if it is good enough for him, it is good enough for me.
To be clear, I spent days trying to detect a missing fPassBackRun without an error code.
OpenArgs is the “correct” way. If you are a stickler for everything being Tickety-Boo, put the OpenArgs method back in.
Latest CallCalled class module
This is the latest version (Drive Doc, April 2021 header).
Paste it into a class module named clsCallCalled in your Microsoft Access database and follow the comments.
There is no sample .accdb download on this page.
The listing is coloured like Visual Studio on a white sheet. Switch the site to Light (top right) if names look faint — keywords stay blue either way.
Option Compare Database Option Explicit 'MORE INFO on My Website HERE:- 'http://www.niftyaccess.com/callcalled-class-module/ '******************************************************************************************************* '*************************************** Declarations Section ***************************************** '******************************************************************************************************* '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< '>>> Database by Tony Hine, alias Uncle Gizmo <<< '>>> Created Oct, 2007 <<< '>>> Last up-dated April, 2021 <<< '>>> Telephone International: +44 7747 018 875 <<< '>>> Telephone UK: 07747 018 875 <<< '>>> e-mail: tonyhine@lay-away.co.uk <<< '>>> Skype: unclegizmo (I seldom Use Skype) <<< '>>> I post at the following forum (mostly) : <<< '>>> http://www.access-programmers.co.uk/forums/ (alias Uncle Gizmo) <<< '>>> If my e-mail don't work, try this website: http://www.tonyhine.co.uk/example_help.htm <<< '>>> This is my public playground Website for MS Access:- <<< '>>> The Nifty Access Website is sales orientated:- <<< '>>> www.niftyaccess.com (A vehicle for me to generate an income from my retirement) <<< '>>> My YouTube Channel HERE:- https://www.youtube.com/user/UncleGizmo <<< '>>> CODE SUPPLIED NOT CHECKED AND TESTED FOR ERRORS!!!! Be Warned <<< '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< '******************************************************************************************************* '************************************** Recent Searches & Notes **************************************** '******************************************************************************************************* 'This Class Can be used to return:- 'The Calling Control Name, 'The Principle Control, 'The Parent Form of the Principle Control, 'Principle Control Caption, 'and more '******************************************************************************************************* '**************************************** Declared Constants ******************************************* '******************************************************************************************************* Const conAppName As String = "Nifty Access - clsCallCalled Class" Const conATH As String = "Database By Tony Hine Tel: +44 7747 018 875" '******************************************************************************************************* '************************ Declare the Private Variable(s) used in this Class *************************** '******************************************************************************************************* Private mobjPrincipleCtrl As Object Private mstrCallingCtrlName As String Private mstrMainFormName As String Private mfrmCallingForm As Form Private mstrPrincipleCtrlCaption As String Private mFlgDevMode As Boolean Private mFlgHASfPassBackRun As Boolean '******************************************************************************************************* '********************************* Custom Properties used in this Class ******************************** '******************************************************************************************************* Property Get prpMainFormName() As String prpMainFormName = mstrMainFormName End Property 'prpMainFormName Get Property Get prpCallingCtrlName() As String prpCallingCtrlName = mstrCallingCtrlName End Property 'prpCallingCtrlName Get Public Property Get prpCallingForm() As Form Set prpCallingForm = mfrmCallingForm End Property 'prpCallingForm Get Property Set prpPrincipleCtrl(oPassedCtrl As Object) Set mobjPrincipleCtrl = oPassedCtrl End Property 'prpPrincipleCtrl Let Property Get prpPrincipleCtrl() As Object Set prpPrincipleCtrl = mobjPrincipleCtrl End Property 'prpPrincipleCtrl Get Property Let prpPrincipleCtrlCaption(strPrincipleCtrlCaption As String) mstrPrincipleCtrlCaption = strPrincipleCtrlCaption End Property 'prpPrincipleCtrlCaption Let Property Get prpPrincipleCtrlCaption() As String prpPrincipleCtrlCaption = mstrPrincipleCtrlCaption End Property 'prpPrincipleCtrlCaption Get Property Let prpFlgDevMode(blnFlgDevMode As Boolean) mFlgDevMode = blnFlgDevMode End Property 'prpFlgDevMode Let Property Get prpFlgDevMode() As Boolean prpFlgDevMode = mFlgDevMode End Property 'prpFlgDevMode Get Property Let prpFlgHASfPassBackRun(blnFlgHASfPassBackRun As Boolean) mFlgHASfPassBackRun = blnFlgHASfPassBackRun End Property 'prpFlgHASfPassBackRun Let Property Get prpFlgHASfPassBackRun() As Boolean prpFlgHASfPassBackRun = mFlgHASfPassBackRun End Property 'prpFlgHASfPassBackRun Get '******************************************************************************************************* '***************************** Class Initialize Event for this Class *********************************** '******************************************************************************************************* Private Sub Class_Initialize() Dim ctrlActiveControl As Control Dim strAssociateCtrl As String '////////// Show Extra info for the Developer prpFlgDevMode = False Let mstrMainFormName = Screen.ActiveForm.Name 'Get the Active Form (Calling Form) Set ctrlActiveControl = Screen.ActiveControl 'Get the Control that is Active on the Form. mstrCallingCtrlName = ctrlActiveControl.Name 'Store the Calling Control Name Set mfrmCallingForm = fGetParentForm(ctrlActiveControl) 'Store the Form the Control is on, (not always/necessarily the active Form). '////////// ATH NOTE 2017_05_04 - the "3" in the following line is the prefix length. change it to your prefered coding practice strAssociateCtrl = fGetAssociateCtrl(prpCallingForm, prpCallingCtrlName, 3) Set mobjPrincipleCtrl = prpCallingForm(strAssociateCtrl) 'Store the Principle Control Let mstrPrincipleCtrlCaption = fGetLabel(prpCallingForm, prpPrincipleCtrl) 'Store the Principle Control's Label's Caption Call fHASfPassBackRun 'Check to see if the Routine "fPassBackRun" exists in the Calling form '////////// For Testing - Show the Principle Control's Label's Caption If prpFlgDevMode Then MsgBox " >>> PrincipleCtrl Caption is:- " & prpPrincipleCtrlCaption, , conAppName If prpFlgHASfPassBackRun Then MsgBox " >>> The Calling Form >>> " & prpCallingForm.Name & _ " Contains a Public Function named fPassBackRun (pass-back-run) ", , conAppName Else MsgBox " >>> The Calling Form >>> " & prpCallingForm.Name & _ " Does NOT Contain a Public Function named fPassBackRun (pass-back-run) ", , conAppName End If End If End Sub 'Class_Initialize '******************************************************************************************************* '****************************** Class Terminate Event for this Class *********************************** '******************************************************************************************************* Private Sub Class_Terminate() Set mobjPrincipleCtrl = Nothing Set mfrmCallingForm = Nothing End Sub 'Class_Terminate '******************************************************************************************************* '*********************** Public Subroutines and Functions used in this Class *************************** '******************************************************************************************************* Public Function fActiveFormLoaded() As Boolean 'Returns true if "prpMainFormName" (Property containing the name of the form to check) is open Dim strSubName As String Dim strModuleName As String strSubName = "fActiveFormLoaded" strModuleName = "Module - clsCallCalled" On Error GoTo Error_Handler 'From:- 'https://docs.microsoft.com/en-us/office/vba/api/access.accessobject.isloaded If CurrentProject.AllForms(prpMainFormName).IsLoaded Then fActiveFormLoaded = True Else MsgBox "The Active Form has been unexpectedly closed. One solution to this problem is to make the Pop-Up form Modal", , conAppName End If Exit_ErrorHandler: Exit Function Error_Handler: 'Version - 1a Dim strErrFrom As String Dim strErrInfo As String strErrFrom = "Error From:-" & vbCrLf & strModuleName & vbCrLf & "Subroutine >>>>>>> " & strSubName strErrInfo = "" & vbCrLf & "Error Number >>>>> " & Err.Number & vbCrLf & "Error Descscription:-" & vbCrLf & Err.Description Select Case Err.Number Case 0.123 'When Required, Replace Place Holder (0.123) with an Error Number MsgBox "Error produced by Place Holder please check your code!" & vbCrLf & vbCrLf & strErrFrom & strErrInfo, , conAppName Case Else MsgBox "Case Else Error" & vbCrLf & vbCrLf & strErrFrom & strErrInfo, , conAppName End Select Resume Exit_ErrorHandler End Function 'fActiveFormLoaded '******************************************************************************************************* '********************** Private Subroutines and Functions used in this Class *************************** '******************************************************************************************************* Private Function fGetParentForm(ctrlActiveControl As Control) As Form Dim strSubName As String Dim strModuleName As String strSubName = "fGetParentForm" strModuleName = "Module - clsCallCalled" On Error GoTo Error_Handler Dim ctlToTest As Control Set ctlToTest = ctrlActiveControl 'Will Always be a "Control? No Not always... " '/////////// CHECK THIS ...No Not always... Dim X As Integer For X = 1 To 20 'This will check to 20 levels If Not fParentIsaForm(ctlToTest.Parent.Name) Then 'Is Parent a Form? 'It's not a form, so it must still be a control so carry on checking a "Control" Set ctlToTest = ctlToTest.Parent 'No --- Then check the next Parent Else 'It is a form, so you have found the form that the control is on. Set fGetParentForm = ctlToTest.Parent 'Yes -- Then Set the Property to The Parent Form Exit For End If Next X 'I cannot foresee a situation with more than 20 levels, but I thought a check on it would be wise If X >= 20 Then MsgBox "Message from clsCallCalled ---" & "ERROR 20 Levels EXCEEDED, change 20 to a higher Figure ---", , conAppName '////////// For Testing - If prpFlgDevMode Then MsgBox " >>> WARNING !!! --- DEVELOPER MODE IS ACTIVE!!!", , conAppName MsgBox "Level Checked to is :- " & X & " Level(s)", , conAppName End If Exit_ErrorHandler: Exit Function Error_Handler: Dim strErrFrom As String Dim strErrInfo As String strErrFrom = "Error From:-" & vbCrLf & strModuleName & vbCrLf & "Subroutine >>>>>>> " & strSubName strErrInfo = "" & vbCrLf & "Error Number >>>>> " & Err.Number & vbCrLf & "Error Descscription:-" & vbCrLf & Err.Description Select Case Err.Number Case 1 'When Required, Replace Place Holder (1) with an Error Number MsgBox "Error produced by Place Holder please check your code!" & vbCrLf & vbCrLf & strErrFrom & strErrInfo, , conAppName Case Else MsgBox "Case Else Error" & vbCrLf & vbCrLf & strErrFrom & strErrInfo, , conAppName End Select Resume Exit_ErrorHandler End Function 'fGetParentForm Private Function fParentIsaForm(strIsaForm As String) As Boolean 'From Access Help 'https://msdn.microsoft.com/en-us/library/office/ff822456.aspx fParentIsaForm = False Dim obj As AccessObject, dbs As Object Set dbs = Application.CurrentProject ' Search for open AccessObject objects in AllForms collection. For Each obj In dbs.AllForms If obj.Name = strIsaForm Then fParentIsaForm = True Next obj End Function 'fParentIsaForm Private Function fGetAssociateCtrl(frmCallingForm As Form, strActiveCtrlName As String, intPrefixLen As Integer) As String 'Looks for any Control with the same name, makes sure there's only one control, and returns that control. Dim strNamePart As String strNamePart = Right(strActiveCtrlName, Len(strActiveCtrlName) - intPrefixLen) 'The active control name without the prefix 'Length of prefix determined by:- intPrefixLen 'Prefix Removed (Naming Convention) Dim strFoundControlName As String Dim Ctrl As Control Dim X As Integer For Each Ctrl In frmCallingForm Select Case Ctrl.ControlType Case acComboBox, acTextBox ', acLabel ', acCommandButton ', acCheckBox, acListBox, acOptionButton, acOptionGroup, acToggleButton If strActiveCtrlName <> Ctrl.Name Then 'Skip if it's the same Control If Right(Ctrl.Name, Len(Ctrl.Name) - intPrefixLen) = strNamePart Then X = X + 1 strFoundControlName = Ctrl.Name End If End If End Select Next Ctrl Dim strCtrlToUse As String Select Case X Case Is = 0 'No Associate Control Found strCtrlToUse = strActiveCtrlName '////////// For Testing - If prpFlgDevMode Then MsgBox "NO ASS CTRL", , conAppName Case Is = 1 'One Associate Control Found strCtrlToUse = strFoundControlName Case Is > 1 'More than one Associate Control Found MsgBox "From Function: fGetAssociateCtrl in the Form: frmExample. More than " & _ "one Control Found with the Same Name. The Control " & Chr(34) & strActiveCtrlName & Chr(34) & _ " will be made the Principle Control. Correct the Conflicting names to Continue.", , conAppName strCtrlToUse = strActiveCtrlName Case Else MsgBox "From Function: fGetAssociateCtrl in the Form: frmExample. Unforeseen " & _ "Error in Case Statement. The Control " & Chr(34) & strActiveCtrlName & Chr(34) & _ " will be made the Principle Control. Please find the Fault before Continuing.", , conAppName strCtrlToUse = strActiveCtrlName End Select fGetAssociateCtrl = strCtrlToUse End Function 'fGetAssociateCtrl Private Function fHasLabel(oFormPassed As Form, strCtrlName As String) As Boolean 'This function Returns True if the control "Name" entered has an associated label. 'Used in "fGetLabel" Dim Ctrl As Control For Each Ctrl In oFormPassed If Ctrl.ControlType = acLabel Then If Ctrl.Parent.Name = strCtrlName Then fHasLabel = True End If Next End Function 'fHasLabel Private Function fGetLabel(oFormPassed As Form, oCtrl As Control) As String 'Extract the caption from the Associate Controls label... If fHasLabel(oFormPassed, oCtrl.Name) Then fGetLabel = oCtrl.Controls(0).Caption Else fGetLabel = "" End If End Function 'fGetLabel Private Sub fHASfPassBackRun() 'Test to see if the function "fPassBackRun" (Pass-back-run) exists in the Calling Form 'If it does then sets the property "prpFlgHASfPassBackRun" to true. Dim strSubName As String Dim strModuleName As String strSubName = "fHASfPassBackRun" strModuleName = "Module - clsCallCalled" On Error GoTo Error_Handler prpFlgHASfPassBackRun = True 'Call the Function fPassBackRun to Test to see if it Exists prpCallingForm.fPassBackRun ("# ~ Never Use this in the fPassBackRun Case Statement #~#~3£&8* ") 'If the Function fPassBackRun does not exist it Triggers Error 2465 which is handled below Exit_ErrorHandler: Exit Sub Error_Handler: 'Version - 1a Dim strErrFrom As String Dim strErrInfo As String strErrFrom = "Error From:-" & vbCrLf & strModuleName & vbCrLf & "Subroutine >>>>>>> " & strSubName strErrInfo = "" & vbCrLf & "Error Number >>>>> " & Err.Number & vbCrLf & "Error Descscription:-" & vbCrLf & Err.Description Select Case Err.Number Case 2465 'Application-defined or object-defined error 'UnCheck This Message for Testing 'MsgBox "Error Caused because - fPassBackRun does not exist" & vbCrLf & vbCrLf & strErrFrom & strErrInfo, , conAppName prpFlgHASfPassBackRun = False 'Flag that the Function fPassBackRun does not exist Err.Number = 0 'An Expected Error, - so Reset Resume Next 'Resume as if no Error Occured Case Else MsgBox "Case Else Error" & vbCrLf & vbCrLf & strErrFrom & strErrInfo, , conAppName End Select Resume Exit_ErrorHandler End Sub 'fHASfPassBackRun