Why does DoCmd.OpenForm cause bouncing

E

Edward

I have two forms, say A and B. A is set to open at start and it has a button
to allow the user to open form B (without closing Form A). In my live
solution I have problems I've been unable to fathom but the code is too long
to make debugging easy.

So, I created a very simple database that does nothing more than "Msgbox"
the path taken through the Open>Load>Activate>Current events.

That shows Form_A results in this sequence of events:
Open>Load>Activate>Current, which is exactly as it should be according to the
Access documentation.
However, when I click the "Open Form B" button the events occur in this
sequence:
Form_B_Open >Form_B_Load >Form_A_Deactivate >Form_B_Activate >Form_B_Current
Form_B_Open >Form_B Load >Form_B Deactivate >Form_B_Activate >Form_B_Current>

It's OK up to the ">Form_B_Current" but I can't understand why it goes on to
repeat the >Form_B Load >Form_B Deactivate >Form_B_Activate >Form_B_Current>
events.

The following code will fathfully reproduce it, please try it and put me out
of my misery, Thanks, Ted:

Form_A event code:
Option Explicit

Private Sub Admin_Click() ' This is a button on Form_A pointing to this
click event
DoCmd.OpenForm Form_Form_B.Name
End Sub

Private Sub Form_Activate()
MsgBox Me.Name & " Activate"
End Sub

Private Sub Form_Current()
MsgBox Me.Name & " Current"
End Sub

Private Sub Form_Deactivate()
MsgBox Me.Name & " De-Activate"
End Sub

Private Sub Form_Load()
MsgBox Me.Name & " Load"
End Sub

Private Sub Form_Open(Cancel As Integer)
MsgBox Me.Name & " Open"
End Sub

Form_B event code:
Option Compare Database

Private Sub Form_Activate()
MsgBox Me.Name & " Activate"
End Sub

Private Sub Form_Current()
MsgBox Me.Name & " Current"
End Sub

Private Sub Form_Deactivate()
MsgBox Me.Name & " DeActivate"
End Sub

Private Sub Form_Load()
MsgBox Me.Name & " Load"
End Sub

Private Sub Form_Open(Cancel As Integer)
MsgBox Me.Name & " Open"
End Sub
 
D

dch3

I'm willing to bet that Focus is being returned to the First Form. Which
control on which form has the focus after the form opens? Try playing around
with putting code in the GotFocus and LostFocus events for the Form.
 
E

Edward

I'm trying what you suggested though at the moment it's adding to my
confusion, not least because I've noticed that the second (spurious) Open
event for Form_B actually creates an identical instance of Form_B, which is
intriguing in itself but not what I want to see.

I'll persevere but in the meantime if you can think of anything else I'd
appreciate it.

Thanks for your help.
 
E

Edward

Obviously DoCmd.OpenForm doesn't work as described on the tin; it fires
events off all over the place and is impossible to nail down to any logical
sequence. If you run my code you'll see what I mean. And futhermore, If you
replace the DoCmd.OpenForm with Form_Form_B.SetFocus, you will see that even
though the form is neither opened or loaded, it actually opens the form and
runs the events in the correct order.

I challenge anyone to explain why my original code posted in this string
didn't work and why/how using .SetFocus can open an unloaded form.

It doesn't make any sense to me but I'm hopeful that dropping DoCmd.Openform
in favour of .SetFocus in my production database will let me move on, but I'm
not happy that my original solution should have worked and didn't and the use
of .SetFocus shouldn't work but does!!

The code I posted earlier is very simple so please, someone, take a close
look at it and put me on the straight and narrow.

Regards,

Ted
 
D

Dirk Goldgar

Edward said:
Obviously DoCmd.OpenForm doesn't work as described on the tin; it fires
events off all over the place and is impossible to nail down to any
logical
sequence. If you run my code you'll see what I mean. And futhermore, If
you
replace the DoCmd.OpenForm with Form_Form_B.SetFocus, you will see that
even
though the form is neither opened or loaded, it actually opens the form
and
runs the events in the correct order.

I challenge anyone to explain why my original code posted in this string
didn't work and why/how using .SetFocus can open an unloaded form.


I've no time at the moment to analyze your code to see why it didn't work,
but I can answer the second part of your challenge.

You need to understand what a reference like "Form_FormName" really is.
That is a reference to the form's class object. When you make any reference
to a form's class object -- it doesn't have to be a call to the form's
SetFocus method -- Access will try to resolve it by finding a loaded
instance of that class. If only one instance of that class is loaded, it
will return a reference to that instance. If more than one instance is
loaded, it will just pick one of them. I don't know if you can predict
which one; whether it is always the default instance (opened by
DoCmd.OpenForm), or the first one that was loaded, or what.

But here's the interesting thing. If there is no instance of that class
loaded, then Access will create one. That means opening the form, and all
the events associated with that process will fire. However, the form will
be opened hidden, so it won't appear on the screen unless you unhide it.
This is one reason why using the "Form_FormName" type of reference is a bad
idea -- you don't know which instance of a form is being referred to, and
you may open a new instance of a form when you didn't intend to. Also, it
will be a non-default instance, so you can't use its name as an index into
the Forms collection.

Consider this sequence of statements, as executed in the Immediate window:

?Form_Form1.HasModule
True
?Forms.Count
1
DoCmd.OpenForm "Form1"
?Forms.Count
2
DoCmd.Close acForm, "Form1"
?Forms.Count
1
DoCmd.Close acForm, "Form1"
?Forms.Count
0

As you can see, the reference to Form_Form1 causes an instance of Form1 to
be loaded. If there were event procedures code for that form's Open and
Load events, they would have fired. Interestingly, the Activate event also
fires, even though this instance is hidden. At this point, there is 1 form
in the Forms collection, but you'll find you can't reference this one by
name: ?Forms("Form1").HasModule will give error 2450 ("Can't find the form
referred to in a macro expression or VBA code").

Then the DoCmd.OpenForm statement opens another instance of the form and
makes that instance visible. The events fire for that instance. Now there
are 2 forms in the Forms collection. This second form is a default
instance, so using its name as an index into the Forms collection will not
raise an error.

Then each successive DoCmd.Close statement for this form closes one of the
instances, until none is left.

By contrast, look at this sequence of statements:

DoCmd.OpenForm "Form1"
?Forms.Count
1
?Form_Form1.HasModule
True
?Forms.Count
1
DoCmd.Close acForm, "Form1"
?Forms.Count
0

In this case, the form is opened normally, before the first reference to its
class module. Therefore, no second instance is created.
 
D

dch3

So the long and the short of it is to always open an object explicity by
name? I knew that you could call a sub one on form from another, but didn't
realize that a form was a Class...lets not discuss that out of 35 people who
started out in Intro to Java, I was one of 5 left at the end of the semester.
 
E

Edward

Thanks for not only enabling me to apply what I need to my live project but
also for opening another chapter of knowledge for me. Very much appreciated!!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top