Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Forms! vs. Form_ 2

Status
Not open for further replies.

lameid

Programmer
Jan 31, 2001
4,207
US
Searching through the forum I saw several posts with the Form_ method of referencing a form instead of using the Forms! method.

I am accustomed to the Forms!Formname syntax as opposed to the Form_Formname syntax. So much so that I never registered seeing the Form_ method.

It looks like the Form_ method is hardly used but still supported at least in Access 2013.

Is this a legacy syntax that is all but deprecated or does it serve a specific purpose? What if anything am I missing?
 
When a form is opened it is added to the forms collection if opened using the docmd.Openform method. In other words a pointer is added to the Forms collection and that is an easy way to get a reference to an open form. However you can instantiate the object directly.
Code:
Private myFrm as form_someform
Sub SomeSub()
  Set myFrm as new form_someform
  MyFrm.visible=true
end Sub

When you instantiate the object it opens the form. This is the only way to open multiple instances of the same form.
Code:
Private myFrm as form_someform
Private myFrm2 as form_Someform
Sub SomeSub()
  Set myFrm as new form_someform
  Set myFrm2 as new Form_someForm
  MyFrm.visible=true
  myFrm2.visible=true
end Sub

You have to dimension the form as a module level object if not it will go out of scope and close once the procedure finishes. This is in truth the normal way to open a form as in VB.net, VB, and sort of Excel.
 
Form_ is not a method but a prefix for opening an instance of the form. The docmd.openform is just a wrapper for instantiating and opening a form. The forms collection holds references only to open form instances and not all form objects.
 
Right not a method language element but a methodology of syntax.

So the "Form_" is an implicit prefix to every form (I want to say class in a meta sense not the Form Class module) that allows it to be instantiated.

That makes sense but then use of "Form_FormName" to reference an open instance like the below would be less than ideal, correct? One should have the form object to reference directly like Myfrm in your/Mail's example or the more familiar to me Forms!FormName

Form_FormName.controlname = "Value
 
I was wrong about two things. When you open a form using the below method it does get a pointer added to the Forms collection. Also i thought that Form_ was part of the class name, but according to the Access Desktop Developer it is not. They describe it as syntax specifying you want to open an instance or get a reference to the open instance.
Code:
Public Sub testForm()
  'This code causes the form to instantiate and instance if not already open or return a reference to the instance if it is open
  'Also in this format it persists even after the code completes
  Form_Products.Visible = True
  Debug.Print Form_Products.Caption
  Form_Products.Caption = "New Caption"
  Debug.Print Form_Products.Caption
End Sub

The only issue I could see would be that you could inadvertently open a form just by calling a property and/or leave it hidden. However, that could be more a feature than a problem because normally if you call it and it is not open then you want to open it. Using this method you never have to check if the form is open because if it is not open it will open it. But using the docmd.openform has a lot of capabilities.
"Form_FormName" to reference an open instance like the below would be less than ideal, correct?
So as far as I can tell there is nothing wrong with the above code. It just seems a little strange for those people use to OOP because it is doing things behind the scenes and the syntax is little strange since it looks like you are directly calling a class. As long as you do not open multiple instances of a form this syntax should be fine because you will always get a reference to the correct form.

The below seems more logical to me because I see exactly how the instance is instantiated and the syntax looks traditional where I set a variable to the instance of the class.
Code:
Private myFrm As Form_Products
Private myFrm2 as Form_Products
Public Sub testForm2()
  Set myFrm = New Form_Products
  myFrm.Visible = True
  myFrm.Caption = "Form1"
  myFrm.Modal = True
  Debug.Print Forms.Count
  Set myFrm2 = New Form_Products
  myFrm2.Visible = True
  myFrm2.Caption = "Form 2"
  Debug.Print Forms.Count
End Sub

Not sure why I do not do this more because there is one very big advantage.
forms("SomeForm") or Forms!SomeForm does not give intellisense
But
Form_SomeForm. give intellisense
 
Form_SomeForm is a document class, like document in word or workbook/worksheet in excel visible in VBE project explorer window. In opposite to word or excel, name of this class can't be changed manually (not visible in properties), it is managed by access and changes when the form name is changed.
Called from vba exposes form's features, as in excel vba can be done by calling worksheet: Sheet1. (here Sheet1 is code name, in opposite to sheet's name visible in excel UI, initially both names are the same, but can be changed independently).
BTW, change of Form_SomeForm by code destroys vba project structure.

combo
 
Form_SomeForm is a document class
As far as I know there is no such term as a "document class". Never seen that used in any literature. Do you have a reference to this?
BTW, change of Form_SomeForm by code destroys vba project structure.
Does not. Absolutely does nothing.
The below code using VBA extensibility changes the name of form1 class module from Form_Form1 to "Dog"
Code:
Public Sub ChangeName()
  Dim VBAEditor As VBIDE.VBE
  Dim VBProj As VBIDE.VBProject
  Dim VBComp As VBIDE.VBComponent
  Dim CodeMod As VBIDE.CodeModule
 
  Set VBAEditor = Application.VBE
  Set VBProj = VBAEditor.ActiveVBProject
  Set VBComp = VBProj.VBComponents("Form_Form1")
  Set CodeMod = VBComp.CodeModule
  VBComp.Name = "Dog"
End Sub

So this now tells me I was correct in the first Place "Form_" is just the full name of the class. The fact that the visible form name property is different from the Class name is irrelevant. Same as what you can do in Excel, Word, ... The visible portion has a name property that is different from the class name. To prove this once I renamed the class "dog" I can instantiate it and open it with below code
Code:
Public Sub OpenDog()
  'Open Form1 with a class name of Dog
  Dog.Visible = True
End Sub

form instead of using the Forms! method
One more thing, that is also not a method but a property. It is actually short hand for a returning a reference from the Forms library collection using bang notation instead of dot notation. It is equivalent to
dim frm as access form
set frm = Forms.item("FormName")
since Item is the default property of all collections you can omit it to simply
set frm = forms("FormName")
or Frm = forms(1) ' where FormName is the second form in the collection
or frm = forms!FormName
 
Access 2016.

VBIDE VBComponent type (vbext_ComponentType) for access form is vbext_ct_Document. It's neither standard module nor class module.

In my case for database with single form with module after programmatic name change I get VBA projest structure as in attached image. Calling the form (any of the two displayed items) results message "Module not found". (code that changed form's name in VBE executed on closed form, this may matter).

combo
 
 http://files.engineering.com/getfile.aspx?folder=7e082224-b11a-4579-850b-93c342633121&file=VBE.png
Yes, do not think you ever want to do this in real life. It works until you reopen the form in design view, and Access then renames the code module back to Form_FormName and strands the renamed class.
 
>Also i thought that Form_ was part of the class name, but according to the Access Desktop Developer it is not. They describe it as syntax specifying you want to open an instance or get a reference to the open instance.

They can describe it that way if they like, but you were right, and they were ... inaccurate ... What happens is just like in classic VB; for every form you create VB makes a hidden global declaration for the underlying class representing the form, using the name you gave the form class. So if you create a Form in VB6 called MyForm, then VB6 does this in the background:

Public MyForm as New MyForm

This then acts exactly as you'd expect if you'd made such a declaration yourself.

The only difference in Access is that if you create an Access Form called MyForm it makes the classname Form_MyForm (and you can't do anything about that, as per combo's comments above); it then makes the same hidden global declaration that VB6 does:

Public Form_MyForm As New Form_MyForm

and we end up with a self-instantiating object with the same name as the class

(to be fair there is a tiny bit more housekeeping going on behind the scenes than the declaration, but nothing to trouble us too much)

Instantiated forms are added to the Forms collection - where they are indexed by the form name, not the class or object name (one minor repercussion of this is that we might end up with several forms with the same name in the Forms collection if we instantiate several forms from the same class, and you can only retrieve the first of those via the Forms!Formname method)
 
Code:
several forms with the same name in the Forms collection if we instantiate several forms from the same class, and you can only retrieve the first of those via the Forms!Formname method)
If working with multiple form instances often you would also want to build a custom collection class to manage the forms. Just like the built in Forms collection except you have to write the code so that they add and remove from the collection as the forms open and close. When you add them you provide a unique key to the collection. Then you can uniquely refer to them by your unique key value.
 
Very interesting stuff here...

So in conclusion / Summary...

It seems like everything built under the Access.Application object is based on the assumption of single instance of a form class. You are not limited to that but you also break the built in iteration by name if you multi-instance a form.

The Form_FormName syntax is a class name and if used as an object will instantiate the Access default instance of the form or find the first instance of that class in the Forms collection.

[red]Form_FormName syntax is materially different from Forms!FormName syntax in that it will open / instantiate the form if it is not already open where as the latter is a normal iterator for the object amongst the collection. This is neither good nor bad but is the fundamental difference you had better understand between the two.[/red]



Ok... I think I understand the nuances of what I was looking at... Now I have to decide what I think about it (an auto shutdown warning form... I think the user can close it so the Form_ syntax may be necessary to avoid testing if it exists... globals are also in the mix so may need Tempvars instead). More importantly, I think you guys have just made the definitive syntax reference for this topic something that was lacking from the Internet. Kudos.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top