Creating multiple instances of a form

  • Thread starter Thread starter John Cosmas
  • Start date Start date
J

John Cosmas

How would I launch Form2 from Form1, where I can have more than 1 copy of
Form2 opened by clicking on the open button in Form1? Do I create Form2 as
an object? Please include sample code.

TIA
John Cosmas
 
John,

'Declarations section
Private frm As Form_myOtherForm

If you want to use frmOtherForm's events, then declare it like so:
Private WithEvents frm As Form_frmOtherForm

'Perhaps in a button Click() event:
Set frm = New Form_frmOtherForm

'In the form's Close or UnLoad event:
Set frm = Nothing

Regards,
Graham R Seach
Microsoft Access MVP
Sydney, Australia

Microsoft Access 2003 VBA Programmer's Reference
http://www.wiley.com/WileyCDA/WileyTitle/productCd-0764559036.html
 
You need to assign a seperate object reference for each new copy of Form2
that you open. And you need those references to be global to Form1's code
module, because if they are local to the Click event, they will go out of
scope when the Click event exits, and the referenced form(s) will disappear
at that point.

Try this (untested):

' Form1 declaration section.
dim fForm2 (1 to 10) as form, nForm2 as integer
....
private sub cmdBlah_Click()
nform2 = nform2 + 1
if nform2 > 10 then ' spit the dummy or resize the array.
set fForm2 (nform2) = new Form_Form2
fForm2 (nform2).visible = true
end sub

' then in Form1's form_close or form_unload event, set each fForm2() entry
to Nothing.

HTH,
TC
 
John,

I've been giving some more thought to your question, and it occurred to me
that you might want to control these forms from Form1, and who's to say how
many you want to instantiate. So I fiddled around a bit and came up with the
following solution. You might find it a bit complex at first, but when you
take an in-depth look at it, you'll see it's really not that hard. With this
strategy, you can instantiate as many Form2's as you like, plus you can
automate them as you please.

The first thing is that we need to uniquely identify each instance of Form2,
so I decided to use GUIDs.

'************************
'Place the following code into a standard module.
'************************

Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type

Declare Function CoCreateGuid Lib "OLE32.DLL" (pGuid As GUID) As Long

Public Const S_OK = 0 ' return value from CoCreateGuid

Public Function GetGUID() As String
Dim lResult As Long
Dim lGUID As GUID
Dim sGUID As String
Dim sGUID1 As String
Dim sGUID2 As String
Dim sGUID3 As String
Dim iDataLen As Integer
Dim sStringLen As Integer
Dim iCtr As Integer

On Error GoTo GetGUID_Err

GetGUID = "00000000" 'Return zeros if the function is unsuccessful
lResult = CoCreateGuid(lGUID)

If lResult = S_OK Then
sGUID1 = Hex$(lGUID.Data1)
sStringLen = Len(sGUID1)
iDataLen = Len(lGUID.Data1)
sGUID1 = LeadingZeros(2 * iDataLen, sStringLen) & _
sGUID1 'First 4 bytes (8 hex digits)

sGUID2 = Hex$(lGUID.Data2)
sStringLen = Len(sGUID2)
iDataLen = Len(lGUID.Data2)
sGUID2 = LeadingZeros(2 * iDataLen, sStringLen) & _
Trim$(sGUID2) 'Next 2 bytes (4 hex digits)

sGUID3 = Hex$(lGUID.Data3)
sStringLen = Len(sGUID3)
iDataLen = Len(lGUID.Data3)
sGUID3 = LeadingZeros(2 * iDataLen, sStringLen) & _
Trim$(sGUID3) 'Next 2 bytes (4 hex digits)

For iCtr = 0 To 7
sGUID = sGUID & Format$(Hex$(lGUID.Data4(iCtr)), "00")
Next iCtr

'sGUIDn contains the last 8 bytes of the GUID (16 hex digits)
GetGUID = sGUID1 & sGUID2 & sGUID3 & sGUID
End If

Exit_GetGUID:
Exit Function

GetGUID_Err:
DoCmd.Beep
MsgBox "Error " & Err.Number & vbCrLf & vbCrLf & _
Err.Description, vbOKOnly + vbExclamation, _
"Could not retrieve GUID"
Resume Exit_GetGUID
End Function

Function LeadingZeros(iExpectedLen As Integer, iActualLen As Integer) As
String
LeadingZeros = String(iExpectedLen - iActualLen, "0")
End Function

'************************
'Now create two forms; one called frmForm1,
'and the other called frmForm2, and place a
'command button on each (both named Command0).
'On frmForm1, 'add a textbox called Text1.
'************************
'Now add the following code to frmForm1
'************************
Private frm As Form_frmForm2 'The form to multi-instantiate
Private colForm2 As Collection 'The form collection

Private Sub Command0_Click()
'Instantiate the new form instance
Set frm = New Form_frmForm2

'Make it visible
frm.Visible = True

'Set a circular reference to frmForm1
Set frm.ParentForm = Me

'Destroy the local reference
Set frm = Nothing
End Sub

Public Sub NotifyFormOpen(GUID As String)
'This sub is called from frmForm2's Close event
'Add the newly created form to the forms collection
colForm2.Add frm, GUID
Refresh the counter to show how many we current have
Me.Text1 = colForm2.Count
End Sub

Public Sub NotifyFormClose(GUID As String)
'This sub is called from frmForm2's Open event
On Error Resume Next

'Release the form's circular reference to frmForm1
Set colForm2(GUID).ParentForm = Nothing

'Remove the form from the collection
colForm2.Remove GUID

'Refresh the counter
Me.Text1 = colForm2.Count
End Sub

Private Sub Form_Load()
'Instantiate the form collection
Set colForm2 = New Collection
End Sub

Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next

'Release the form reference
Set frm = Nothing
'Release the Collection object and all the objects it contains
Set colForm2 = Nothing
End Sub

'************************
'Now add the following code to frmForm2
'************************
Private sGUID As String 'The form's unique GUID (identifier)
Private oParent As Form 'An object variable to contain a
'circular reference to the calling form

Private Sub Command0_Click()
'Cose the current form instance
DoCmd.Close
End Sub

Private Sub Form_Load()
'Get the GUID and store it locally
sGUID = GetGUID
End Sub

Public Sub Form_Unload(Cancel As Integer)
On Error Resume Next

'Call the parent form's NotifyFormClose event
oParent.NotifyFormClose sGUID

'Release the local object reference
Set oParent = Nothing
End Sub

Public Property Get GUID() As String
'Set the GUID
GUID = sGUID
End Property

Public Property Set ParentForm(fm As Form)
'Instantiate the local circular reference to the calling form
Set oParent = fm

'If we've just created the reference, call the parent form's
'NotifyFormOpen event
If Not oParent Is Nothing Then
oParent.NotifyFormOpen sGUID
End If
End Property

'************************
'Whenever you want to do anything with one of the instances of frmForm2,
'you can refer to it through the Collection object, like so:
' colForm2(sGUID).public_method_or_object

I hope this helps.

Graham R Seach
Microsoft Access MCP, MVP
Sydney, Australia

Microsoft Access 2003 VBA Programmer's Reference
http://www.wiley.com/WileyCDA/WileyTitle/productCd-0764559036.html
 
John,

I didn't think about this until after I'd gone to bed. To ensure you can
open and use Form2 independently of Form1, replace Form2's code with this
lot:

Private bIsObject As Boolean 'True if the form has been instantiated
remotely
Private sGUID As String 'The form's unique GUID (identifier)
Private oParent As Form 'An object variable to contain a
'circular reference to the calling form

Private Sub Command0_Click()
'Cose the current form instance
DoCmd.Close
End Sub

Public Sub Form_Unload(Cancel As Integer)
On Error Resume Next

'Call the parent form's NotifyFormClose event
If bIsObject Then oParent.NotifyFormClose sGUID

'Release the local object reference
Set oParent = Nothing
End Sub

Public Property Get GUID() As String
'Set the GUID
GUID = sGUID
End Property

Public Property Set ParentForm(fm As Form)
'Instantiate the local circular reference to the calling form
Set oParent = fm

If Not bIsObject Then
'Get the GUID and store it locally
sGUID = GetGUID

'The first time this property is called,
'call the parent form's NotifyFormOpen event
oParent.NotifyFormOpen sGUID
End If

'Set the flag to indicate that the form has been
'instantiated remotely
bIsObject = True
End Property

Graham R Seach
Microsoft Access MCP, MVP
Sydney, Australia

Microsoft Access 2003 VBA Programmer's Reference
http://www.wiley.com/WileyCDA/WileyTitle/productCd-0764559036.html
 
Back
Top