Solved Trouble opening multiple instances of a form

I added some simple formatting to make this visibly understandable. It stacks the pop ups and spaces them.
Code:
Public Function OpenAClient(PartyID As Long, FormName As String)
    'Purpose:    Open an independent instance of a form.
  

    'Open a new instance, show it, and set a caption.
    Dim frm As Form
    Select Case FormName
        Case "frmPersons"
            Set frm = New Form_frmPersons
            frm.ConfigureForm ftDrillDown
            frm.Move 700 * clnClient.Count + 1, 1000 * clnClient.Count + 1, 1440 * 10, 1440 * 7
            frm.txtTitle.Caption = "Drill Down to Related Person: " & GetNameFromID(PartyID)
            frm.txtTitle.FontBold = True
            frm.txtTitle.ForeColor = vbBlack
          
          
        Case "frmOrganisations"
            Set frm = New Form_frmOrganisations
    End Select
  
    frm.Visible = True
    frm.Caption = frm.hWnd & ", opened " & Now()
    frm.Filter = "PartyID = " & PartyID
    frm.FilterOn = True
        
    'Append it to our collection.
    clnClient.Add Item:=frm, Key:=CStr(frm.hWnd)
    TempVars!Drilldown = "yes"
    
    Set frm = Nothing
  
End Function
Public Function GetNameFromID(PartyID As Long) As String
  GetNameFromID = Nz(DLookup("[CurrentTitle] & ' ' & [CurrentFirstName] & ' ' & [CurrentlastName]", "tblPerson", "PartyID = " & PartyID), "")
End Function

multiple.png
 
@MajP
Ok, I am trying your way.
The only thing about this method (we as far as I have implemented it, is that I am duplicating code? :(

At the moment, only for two buttons, but you get the picture.
At least with the open args it was written once and code for that form was contained within that form?

Code:
Private Sub cmdMonthly_Click()
    DoCmd.OpenForm "frmPeriod", , , , ,  "Monthly"
    Forms!frmPeriod.RecordSource = "qryMonthly"
    DoCmd.GoToRecord acDataForm, "frmPeriod", acLast

End Sub

Private Sub cmdWeekly_Click()
    DoCmd.OpenForm "frmPeriod", , , , , , "Weekly"
    Forms!frmPeriod.RecordSource = "qryWeekly"
    DoCmd.GoToRecord acDataForm, "frmPeriod", acLast
End Sub

Also doing it this way, I get to see all the records before the goto record happens, just in a flash, but still.
In the old method, that is not seen.

See frmDailyEntry.
 

Attachments

I am not suggesting you never use openargs, but understand its limitations and you do not have to use openargs it if it is easier not to. In this case what you are doing is relatively simple.

However if doing this I probably do something like this especially if I want to pass in additional parameters besides just the period. I would get rid of the current on load if doing it this way.

Code:
Public Enum ptPeriodType
  ptDaily = 0
  ptWeekly = 1
  ptMonthly = 2
End Enum

Public Sub ConfigureForm(PeriodType As ptPeriodType, Optional OtherParameters as object)
  Select Case PeriodType
  Case ptDaily
    Me.RecordSource = "qryDaily"  'does not exist, but did not know what goes here
  Case ptWeekly
    Me.RecordSource = "qryWeekly"
  Case ptMonthly
    Me.RecordSource = "qryMonthly"
  End Select
  Me.Recordset.MoveLast
'do something with other parameters
End Sub


Then call it like this

Code:
Private Sub cmdMonthly_Click()
    DoCmd.OpenForm "frmPeriod"
    Forms!frmPeriod.ConfigureForm ptMonthly
End Sub

Private Sub cmdWeekly_Click()
    DoCmd.OpenForm "frmPeriod"
    Forms!frmPeriod.ConfigureForm ptWeekly
End Sub
 
Thank you.
Daily is just a Datasheet form.

I have implemented your code, but that flashing between full recordset displayed then last record is still quite noticable.
Not too much a problem for this DB as it is obviously just for my usage, but I would not have liked to present that effect to my users?

You will also notice in the Form Load of frmPeriod I have
Code:
Me.lblTitle.Caption = Me.lblTitle.Caption & Me.OpenArgs

How would I get the same display for the form caption?, as the Enums are numeric?
Is it a case of switching them back to text with perhaps a Select Case?, or is there a better way. I have never used Enums.
 
Last edited:
I have never used Enums.
You have used them all the time, you have never made your own custom ones.

The nice thing about making/using enums they come up in intellisense.
intell.png


VB and Access have a ton of enums. And sometimes you can reuse them in your code
If I wrote a function and I want the calling code to pass in an operator like "less than", "Equal To"
I can simply use the built in enum

Public SomeFunction (Operator as acFormatConditionOperator)

end function

Then I can pass in any of these with intellisense to support.

Enum.png


You will find this really simplifies code writing. You do not have to think about what are the possible values to pass.

The flashing is a benefit of OpenArgs. Because you can load the qry and move in the load event prior to other events. In this method you are doing things after all opening events finish.

Again this is another tool in the toolbox and not a one way or the other.
I assumed you simply turn off the echo before moving
Code:
  Application.Echo false
    Me.Recordset.MoveLast
  Application.Echo True
End Sub
Unfortunately scrolling as it moves to the last record is not effected. So you still see it move.

If you wanted to avoid this the only way I thought of would be to create the recordset. Then movelast. Then bind it.

Code:
Public Sub ConfigureForm(PeriodType As ptPeriodType)
  Dim rs As DAO.Recordset
  Dim source As String
  Select Case PeriodType
  Case ptDaily
    ' source = "qryDaily"
     Exit Sub
  Case ptWeekly
    source = "qryWeekly"
    Me.lblTitle.Caption = "Weekly Intake Totals"
  Case ptMonthly
    source = "qryMonthly"
    Me.lblTitle.Caption = "Monthly Intake Totals"
  End Select
  Set rs = CurrentDb.OpenRecordset(source, dbOpenDynaset)
  If Not rs.EOF Then rs.MoveLast
  Set Me.Recordset = rs
  Me.Move 2 * 1440, 0, 10 * 1440, 8 * 1440
End Sub

I also resized the form, because I could not get it to restore the set size. Also made it Pop up.
Again this is just another option, and in your case the openargs is probably simpler for what you need.
 
I think you should only rewden from multiple form instances if those instances are open AT THE SAME TIME. When done one after the other, these are just different designs of one instance each.

A form is a class. You can use any number of instances of a class at the same time. However, instructions like OpenForm from the DoCmd object (replicating the commands from the menu) don't have much to do with object-oriented programming (OOP). If you really have multiple instances, you should say goodbye to OpenForm and OpenArgs and use the classic methods there.
At the risk of repeating myself, the Northwind Developer Edition template implements this very solution. Feel free to use the classes and code in it for your own projects.
 
You have used them all the time, you have never made your own custom ones.

The nice thing about making/using enums they come up in intellisense.
View attachment 112056

VB and Access have a ton of enums. And sometimes you can reuse them in your code
If I wrote a function and I want the calling code to pass in an operator like "less than", "Equal To"
I can simply use the built in enum

Public SomeFunction (Operator as acFormatConditionOperator)

end function

Then I can pass in any of these with intellisense to support.

View attachment 112058

You will find this really simplifies code writing. You do not have to think about what are the possible values to pass.

The flashing is a benefit of OpenArgs. Because you can load the qry and move in the load event prior to other events. In this method you are doing things after all opening events finish.

Again this is another tool in the toolbox and not a one way or the other.
I assumed you simply turn off the echo before moving
Code:
  Application.Echo false
    Me.Recordset.MoveLast
  Application.Echo True
End Sub
Unfortunately scrolling as it moves to the last record is not effected. So you still see it move.

If you wanted to avoid this the only way I thought of would be to create the recordset. Then movelast. Then bind it.

Code:
Public Sub ConfigureForm(PeriodType As ptPeriodType)
  Dim rs As DAO.Recordset
  Dim source As String
  Select Case PeriodType
  Case ptDaily
    ' source = "qryDaily"
     Exit Sub
  Case ptWeekly
    source = "qryWeekly"
    Me.lblTitle.Caption = "Weekly Intake Totals"
  Case ptMonthly
    source = "qryMonthly"
    Me.lblTitle.Caption = "Monthly Intake Totals"
  End Select
  Set rs = CurrentDb.OpenRecordset(source, dbOpenDynaset)
  If Not rs.EOF Then rs.MoveLast
  Set Me.Recordset = rs
  Me.Move 2 * 1440, 0, 10 * 1440, 8 * 1440
End Sub

I also resized the form, because I could not get it to restore the set size. Also made it Pop up.
Again this is just another option, and in your case the openargs is probably simpler for what you need.
Thank you @MajP,
I have learnt something regardless.
Due to the display of data before seeing the last record, I went back to the OpenArgs method that I had, but without the acDialog.
It was annoying me too much. :)
 
Due to the display of data before seeing the last record, I went back to the OpenArgs method that I had, but without the acDialog.
It was annoying me too much. :)
It might be overkill, but for demonstration purpose the last method I did got rid of any visible movement. May be useful somewhere else.
 
At the risk of repeating myself, the Northwind Developer Edition template implements this very solution. Feel free to use the classes and code in it for your own projects.
That is good information. However, the OP's specific problem had nothing to do with managing or opening form instances. The OP already was doing that without problem. The issue was with configuring the instances differently and the use of openargs in trying to do that. The issue was that a new instance was referencing the original instance Openargs. How that is possible I do not know, but the solution was to bypass all use of open args.
 
... opening form instances. The OP already was doing that without problem
I don't see that.

OpenArgs is something like a universal property of the form that is kept in stock, which then has to be specifically evaluated because of its universality. This, in conjunction with OpenForm, is something of a tired veneer of OOP.

With OpenForm you cannot securely open or manage different instances of the same form that exist at the same time. Especially not in acDialog mode.

If you open an instance of a class in the classic way, you can use its public properties and methods specifically; you don't need the crutch of a universal property to pass it on.
@MayP's suggestions also go in this direction.
 
That is good information. However, the OP's specific problem had nothing to do with managing or opening form instances. The OP already was doing that without problem. The issue was with configuring the instances differently and the use of openargs in trying to do that. The issue was that a new instance was referencing the original instance Openargs. How that is possible I do not know, but the solution was to bypass all use of open args.
Thank you. I will try that tomorrow.
 
I don't see that
sort of. The first instance the OP opened with a Docmd.open form, but the subsequent instances where opened and managed as form instances. So a mix.
 
It might be overkill, but for demonstration purpose the last method I did got rid of any visible movement. May be useful somewhere else.
Not for me, just as bad, if not a little worse. :(

We will stop there @MajP
Thanks again.
Code:
Public Enum ptPeriodType
  ptDaily = 0
  ptWeekly = 1
  ptMonthly = 2
End Enum

Public Sub ConfigureForm(PeriodType As ptPeriodType)
  Dim rs As DAO.Recordset
  Dim source As String
  Select Case PeriodType
  Case ptDaily
    ' source = "qryDaily"
     Exit Sub
  Case ptWeekly
    source = "qryWeekly"
    Me.lblTitle.Caption = "Weekly Intake Totals"
  Case ptMonthly
    source = "qryMonthly"
    Me.lblTitle.Caption = "Monthly Intake Totals"
  End Select
  Set rs = CurrentDb.OpenRecordset(source, dbOpenDynaset)
  If Not rs.EOF Then rs.MoveLast
  Set Me.Recordset = rs
  'Me.Move 2 * 1440, 0, 10 * 1440, 8 * 1440
End Sub

Private Sub Form_Load()
' Add which period we are showing to form title label
'If Not IsNull(Me.OpenArgs) Then
'    Me.lblTitle.Caption = Me.lblTitle.Caption & Me.OpenArgs
'    Me.RecordSource = "qry" & Me.OpenArgs
'End If
'DoCmd.GoToRecord acDataForm, Me.Name, acLast
End Sub

Code:
Private Sub cmdWeekly_Click()
    DoCmd.OpenForm "frmPeriod", , , , , , "Weekly"
    Forms!frmPeriod.ConfigureForm ptWeekly
End Sub
 
Not for me, just as bad, if not a little worse.
Weird, I get nothing. I know you are on an older version of Access, but should not make a difference.
 

Users who are viewing this thread

Back
Top Bottom