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!

How to dynamicaly create the object ? 9

Status
Not open for further replies.

Dule

Programmer
Jun 14, 2000
2
YU
Is there any way to dynamicaly (run-time) create objects, such as Label or TextBox?
 
Hi Dule,<br><br>It is quite easy to add a control to a form at run-time.<br>The following code will add a text box to a form (the form is called Form1).<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Form1.Controls.Add &quot;VB.TextBox&quot;, &quot;txtBox1&quot;, Me<br>&nbsp;&nbsp;&nbsp;&nbsp;With Form1!txtBox1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Visible = True<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Width = 4000<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Height = 285<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Left = 200<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Top = 200<br>&nbsp;&nbsp;&nbsp;&nbsp;End With<br><br>This adds the textbox to the controls collection of the form. As shown above, the various run-time properties can be setup easily in a 'With' block.<br><br>Regards,<br>Tim
 
Btw, you can get all the controls that can be dynamically added to the form by using the Object Browser (hit F2 in the IDE)

Also, if you have a control array (say, of checkboxes) you can also simply add new ones with Load, then position them as above and make them visible.

Also, if you dynamically add controls that are not in your project (say you add a treeview, but you didn't add the common controls to your toolbar) you will get an error. To fix that, simply go into your project properties, go to the make tab and uncheck &quot;Remove information about unused Active-X controls&quot;

Lastly, if you want to place a dynamically generated object inside of a frame or other container object, simply say form1.[dynamic control].container = [Container Object]
 
One of the advantages with using Load to add controls to a control array is that you can process events which they generate. This is not possible using Controls.Add.

Getting around this issue is a pain, but possible and involves writing a custom control which replaces the control that you want to add and a callback class. Here is an example callback class:

Class: TextBoxEventDispatcher
Code:
Option Explicit

Public Event Change (ControlName as String)
Public Event LostFocus (ControlName as String)
Public Event MouseDown(ControlName as String, Button As Integer, Shift As Integer, X As Single, Y As Single)
  ' Repeat for all textbox events

Public Sub Change(ControlName as String)
  RaiseEvent Change(ControlName)
End Sub

  ' repeat for all events

The next step is to create a custom control which will be used in place of the TextBox. It needs to expose all of the methods and properties that the TextBox exposes if it is to be used as a complete replacement, or alternatively just the methods/properties that you need.

As well as this, the control needs to have a Public Property Set method for the TextBoxEventDispatcher defined above.

Code:
Private gEventDispatcher as TextBoxEventDispatcher

Private Property Get EventDispatcher() as TextBoxEventDispatcher
  Set EventDispatcher = gEventDispatcher
End Property

Public Property Set EventDispatcher(EventDispatcher as TextBoxEventDispatcher)
  Set gEventDispatcher = EventDispatcher
End Property

You then need to propogate the src control events through the EventDispatcher, i.e.

Code:
Private Sub TextBox_Change()
  If Not EventDispatcher Is Nothing Then EventDispatcher.Change(Name)
End Sub

' Repeat for all events

Both the control and the EventDispatcher class can be in the same project.

Finally, in the main application, you can use the following:

Code:
Private WithEvents gTextBoxEvents as TextBoxEventDispatcher

    Set gTextBoxEvents = new TextBoxEventDispatcher

    Controls.Add &quot;Class.Control&quot;, &quot;txtBox1&quot;, Me
    With Form1!txtBox1
        .Visible = True
        .Width = 4000
        .Height = 285
        .Left = 200
        .Top = 200
        Set .EventDispatcher = gTextBoxEvents
    End With

Private Sub gTextBoxEvents_Change(CommandName as String)
  Debug.Print CommandName & &quot; has changed&quot;
End Sub

This is obviously not a complete example, but should be expanded to provide the functionality you require.

Chaz
 

The following is a brief example of how to use controls.add and still handle events without having to write reams of code:

Option Explicit

Dim WithEvents txtObject As TextBox


Private Sub Command1_Click()
Set txtObject = Form1.Controls.Add(&quot;VB.TextBox&quot;, &quot;txtbox1&quot;)
txtObject.Visible = True
txtObject.Text = &quot;Dynamic Textbox&quot;
End Sub


Private Sub txtObject_Click()
MsgBox &quot;Dynamic textbox clicked&quot;
End Sub
 
Thats fine if you already know what you are planning to create (and if that is the case, why use Controls.Add) but the reams of code are useful when you need to create an arbitrary number of controls at run-time.

An example would be if you wanted to create a form based on an XML schema. You don't know what fields you need to create, nor their type, but you may want to do field validation prior to submitting the form. Well, now you can.
 

But the version you illustrate also assumes you know what you want to create, since you need to define the event dispatcher class and event propogation...

Or am I missing something?
 
You need to know what to create, but you can create many instances of that thing and still handle all of the events.

It would be easy to create event dispatchers and UserControl equivalents for all of the standard VB controls (they are effectively just wrappers). This is a one off job as the library would then be reuseable. Not a small job to do it right, granted.

As an aside, I have used this technique to provide a plug-in architecture for my current development. As long as a usercontrol implements my Interface (which includes setting the event dispatcher) then it can be used by the app.

In this case, the app is a scheduler. Each custom control defines a job. Each job is an instance of the IJobType interface.

Each control raises events to notify the calling program of their current state - off, idle, running, %complete, etc. All of the jobs are displayed simultaneously on a scrollable panel and are all updated continuously.

I was just downsizing this idea to the standard VB controls to provide the same effect.
 
Ah! Yes, that was what I was missing - the many instances issue.

Frankly, it is a shame that Dim WithEvents cannot take an array...
 
The adding of labels or text boxes dynamically is pretty easy. Does anyone have any code to dynamically create a control array of text boxes or labels? (With a simple loop)



Example:

lblTime(1)
lblTime(2)
lblTime(3)

Of course, the maximum number of them would be dynamic as well.

Ex: (This code DOES NOT WORK, IT IS JUST AN EXAMPLE)

For lLoop = 1 To 20
Set lblObject = Me.Controls.Add(&quot;VB.label&quot;, &quot;lblTime(&quot; & lLoop & &quot;)&quot;) 'Create label dynamically
lblObject(lLoop).Visible = True
lblObject(lLoop).Caption = &quot;Dynamic Label #&quot; & lLoop
Next
 
You can only add controls to an existing array.
The syntax is:
Code:
'To add a control
Load controlname(index)
'To remove a control  
Unload controlname(index)
There is an error if you try to use Load with an index that is already in the array

So you would first have to create a label called lblObject at design time and give it an index of 0.
Then use something like:
Code:
For lLoop = 1 To 20
  Load lblObject(lLoop)
  lblObject(lLoop).Visible = True
  lblObject(lLoop).Caption = &quot;Dynamic Label #&quot; & lLoop
Next
 
Sorry lblObject should say lblTime in the above.
(Why can't you edit posts on this forum!)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top