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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

dynamic form creation, how to name, display and destroy? 2

Status
Not open for further replies.

1DMF

Programmer
Jan 18, 2005
8,795
GB
Hi,

I am trying to dynamically create a form , all is going well except I don't seem to be able to name the form , nor display it in form view and clearing the object referencing the form doesn't destroy it either?

I have
Code:
    Dim cTxt As Control
    Dim fForm As Form
    
    ' set up form
    Set fForm = CreateForm
    fForm.Caption = "Email Progress Information"
    fForm.Width = 200
    fForm.Section(0).Height = 200
    fForm.InsideHeight = 200
    fForm.NavigationButtons = False
    fForm.DefaultView = acNormal
    fForm.ScrollBars = 0
    fForm.RecordSelectors = False
    fForm.AutoResize = True
    fForm.AutoCenter = True
    fForm.PopUp = True
    fForm.FitToScreen = False
    
    ' add text box
    Set cTxt = CreateControl(fForm.Name, acTextBox)
    With cTxt
        .Properties("Width") = 5000
        .Properties("Height") = 2000
        .Properties("Name") = "Progress"
    End With

But if I try to use fFrom.Name = "XYZ" it errors saying it is a read only property?

So how do I name the form , also how do I switch from design view into form view?

I basically want this form to only be in existence until I clear the object pointing to it, is this possible?

Or do I have to save the form, open it and delete it when I'm done?

I simply want to have a progress window for a specific class, that is only around for the life of that class object.

Help finalising this is appreciated.

Regards,

1DMF

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
Code:
Public Sub testit()
 Dim frm As Access.Form
 Dim strName As String
 Set frm = CreateForm
 frm.Visible = True
 frm.Caption = "Test It"
 strName = frm.Name
 DoCmd.Close acForm, strName, acSaveYes
 DoCmd.Rename "frmNewName", acForm, strName
 DoCmd.OpenForm "frmNewName", , , , , acDialog
 DoCmd.DeleteObject acForm, "frmNewName"
End Sub
build,save,rename,show,delete
 
BTW, you should not do this. Access is really not designed for dynamic form generation, there are limitations. Just make the form and then open and edit the properties. If you need multiple instances of it then just make multiple instances of it and format each instance.
Why do you need a dynamic form?
 
Thanks MajP,

Only it won't work anyway, I realised later this afteroon, when I roll it out to an ACCDR and it's run under the Access Runtime, creating forms isn't available - D'oh!

I was wondering are UserForms different from Forms, is that an avenue I should persue?

The reason for this dynamic form is as I'm rolling the EmailWrapper class I decided I wanted to encapsulate the object in its entirity including a progress window, aka a form with a textbox that scrolls info to the user as it processes.

I also want to upgrade my TT FAQ providing the refactored EmailWraperII code, so having a fully ecapsulated emailing object with progress window seems a nice idea.

I did spend the last part of the afternoon refactoring the 'progress window' functionlity, so instead you pass in the name of the form you want to use as the progress window and the name of the textbox control and the EmailWrapper will simply open the form if not already open and concatenate it's messages to the end of the provided texbox control.

I can then include my form for those that need it or it's simple for the user to provide the control and form names, this way if they already have an integrated user interface with messaging, it can plug right into it.

Dunno what do you think is the right approach and how would I go about dealing with form names of a subform?

Regards,
1DMF

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
No there is no userforms and forms.
I can then include my form for those that need it or it's simple for the user to provide the control and form names, this way if they already have an integrated user interface with messaging, it can plug right into it.
That is how I would do it

As we have discussed there is no parameter constructor in vba and no overloading. So I fake it with a procedure called "init" since there is an initialize
Code:
private MessageFormName as string
private withevents MessageForm as access.form
private isSubForm as boolean

public sub init (FrmName as string, Optional SubFormControlName as string = "")
  
  MessageFormName = FrmName
  if not currentProject.allforms(MessageFormName).isloaded then
     docmd.openform MessageFormName
  end if

  If SubFormControlName = "" then
     Set MessageForm = forms(MessageFormName)
  else
     set MessageForm = forms(MessageFormName).controls(SubFormControlName).form
     issubform = true
  end if  
end sub
 
>I was wondering are UserForms different from Forms, is that an avenue I should persue?


Yes, and yes
 
I was wondering are UserForms different from Forms, is that an avenue I should persue?
Yes and probably not
In acess you can import or dynamically create MS UserForms. If you are not familiar go to Excel and create a UserForm in the VBE. In the Access VBE I do not see a way to create one, but you can use code to create one. That may solve your unique runtime issue. You may be able to create a UserForm dynamically. There are some nuances to doing this and it is not very well supported. You can try going that route but expect issues and work arounds.
 
>In the Access VBE I do not see a way to create one

It is there, just hidden by default. In the IDE, simply right click the menubar and select customise from the popup menu. Select 'Commands' then, under 'Categories' select 'Insert'. You'll now see that UserForm is one of the commands available. Drag it onto any toolbar or menu you fancy (for consistency's sake I'd suggest ... ahem ... somewhere on the Insert menu.
No issues, no nuances, no special coding. Works exactly the same as it does in other Office applications.
 
{quote]
No issues, no nuances, no special coding. Works exactly the same as it does in other Office applications.
[/quote]
If using the IDE it is not an issue, but who cares, you can do that with native forms. Developing them dynamically has nuances. Bottom line no value.
 
Sorry - I should be clearer: no more nuance etc. than in any other Office application. And for the sort of dynamic form 1DMF has suggested is required (i.e. one with no code behind any UI items) it's pretty straightforward. Example:

Code:
[blue]Option Compare Database
Option Explicit

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public Sub spoon()
    Dim myForm As Object  
    Dim Progress As Long
    
    Set myForm = UserForm1 [green]' Assumes we have created a blank UserForm in the IDE. This can be done dynamically, but why bother? However, see second example on how to do this[/green]
    
    myForm.Width = 400
    myForm.Height = 40
    
    myForm.Caption = "Progressbar"
    myForm.Controls.Clear
    myForm.Controls.Add "Forms.Image.1", "Percent"
    myForm.Controls.Add "Forms.Label.1", "lblPercent"
    
    myForm.Percent.BackColor = vbBlue
    With myForm
        myForm.lblPercent.Move 0, 4, .Width, .Height
        .BackColor = RGB(127, 127, 127)
        .Enabled = False [green]' stops user closing using 'X' button[/green]
    End With
    myForm.lblPercent.BackStyle = fmBackStyleTransparent
    myForm.lblPercent.TextAlign = fmTextAlignCenter
    myForm.lblPercent.Font.Bold = True
    myForm.lblPercent.ForeColor = vbWhite
    
    
    myForm.Show vbModeless
 
    For Progress = 1 To 100
        myForm.Percent.Width = myForm.Width * Progress \ 100
        myForm.lblPercent.Caption = Progress & "%"
        DoEvents
        Sleep 50
    Next
    Unload myForm
End Sub[/blue]

And here's the horrendously complex version that creates the form itself from scratch (and note that with this version it is possible to add code to the form and any controls on it, although we don't do that here). I have emboldened the changes ...

Code:
[blue]Public Sub spoon2()
    Dim myForm As Object
    [b]Dim myDesignerForm As VBComponent [green]' requires reference to Microsoft Visual Basic for Applications Extensibility library[/green][/b]
    Dim myPercent As MSForms.Control
    [b]Dim myItem As Object[/b]
    
    Dim Progress As Long
    
    [b]Set myDesignerForm = Application.VBE.ActiveVBProject.VBComponents.Add(vbext_ct_MSForm)
    VBA.UserForms.Add myDesignerForm.Name [green]' Contents of UserForms collection present the interface we want[/green] 
    For Each myItem In UserForms [green]'assuming we might have more than one member, else we can go with a simple Set myForm = UserForms(0)[/green]
        If myItem.Name = myDesignerForm.Name Then
            Set myForm = myItem
            Exit For
        End If
    Next[/b]
 
    myForm.Width = 400
    myForm.Height = 40
    
    myForm.Caption = "Progressbar"
    myForm.Controls.Clear
    myForm.Controls.Add "Forms.Image.1", "Percent"
    myForm.Controls.Add "Forms.Label.1", "lblPercent"
    
    myForm.Percent.BackColor = vbBlue
    With myForm
        myForm.lblPercent.Move 0, 4, .Width, .Height
        .BackColor = RGB(127, 127, 127)
        .Enabled = False [green]' stops user closing using 'X' button[/green]
    End With
    myForm.lblPercent.BackStyle = fmBackStyleTransparent
    myForm.lblPercent.TextAlign = fmTextAlignCenter
    myForm.lblPercent.Font.Bold = True
    myForm.lblPercent.ForeColor = vbWhite
    
    
    myForm.Show vbModeless
 
    For Progress = 1 To 100
        myForm.Percent.Width = myForm.Width * Progress \ 100
        myForm.lblPercent.Caption = Progress & "%"
        DoEvents
        Sleep 50
    Next
    Unload myForm
    [b]Application.VBE.ActiveVBProject.VBComponents.Remove myDesignerForm[/b]
End Sub[/blue]

 
I think giving the coder the option to use a default form or provide their own interface for messaging is a better solution as it is more flexible and doesn't force a dynamic form on the users screen. I'd already included a 'ShowProgress' flag so there is an option to bypass the messaging window altogether, but it still populates the message collection so the messages are always available via a getter property.

Incidently is there a method / function such as Class_Initialize, that is called prior to an object being destroyed?

In perl it is
Code:
sub DESTROY { }
, I want to be able to close the form when the EmailWrapper object is destroyed / set to nothing.

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
The code is fine, I just decided not to have the model shove a view in the users face.

I'm sure I'll be using your progress bar indicator for something else though ;-)

Even my solution breaks MVC prinicples as the model is directly updating the view.

I've been pondering what is the best wrong way to do it [lol]

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
It is possible to get too hung up on some of these paradigms, you know ... ;-)
 
I know, and I am seeing how academically correct and real word application needs can conflict.

I've decided to code the model with a compromise, it includes methods for performing tasks such as clearing the recipient collections, but I haven't hidden the collection or made it immutable, so if the coder decides to screw around with the objects state directly, that's their own lookout!

I was told by the Catalyst community that paradigms such as demeter's law are really something the programmer should try to stick to while coding, not something you hard code into the model and physically enforce. So I am not going to worry about cloning the object before passing it back via the getter.

It's not easy trying to take academic knowledge from university and applying it to real word applications, but there is also no point in not putting into practice the knowledge I have learned, especialy as the saying goes 'Use it or lose it!'. Though I'm still finding me feet with the process of implementing this gained knowledge.

As you say, you can end up tying yourself in knots trying to be anal about implementing these paradigms.

What do you use as a yard stick?

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"

Free Dance Music Downloads
 
I applaud you for your efforts in trying to use the best coding practices, but remember this is vba not a real OO language so don't bang your head to hard. There are some serious limitations:
No inheritance
No polymorphism
No constructors
No overloading
No structured error handling
No delegate types
No generic types
etc..

So as you found in order to implement a lot of good design and OOP practices, requires some serious and often limited work arounds. So do not get too hung up.

On a side note. I tend to write a clone function for most of my custom classes especially for the ones going into a custom "collection". Then a clone function in the custom collection. It just seems you eventually end up needing it either public or private to the class.

Going back to the original question providing an Access form or MSForm along with the project seems fine to me. I just could not see the need for a dynamic form. In VBA dynamic forms are problematic in my opinion and rarely see the need. My point was not really MSForm or Access form, but dynamic versuse provided with the project. If you need to tailor the form at runtime then tailor it. If you might need 6 textboxes or 20 textboxes, then place 20 textboxes on the form and show/hide/format as necessary. But provide the "place holder" form either. If your vba application absolutely requires a dynamic form then reconsider your design. Although not your case, most time I see people need an Access dynamic form or dynamic controls is that there database is poorly designed and requires this as a clumsy workaround.
 
Well, you get interface inheritance ... which in turn leads to interface-based polymorphism. And we can do constructors through factory classes ...


 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top