VCP: Trick 2 – Creating components at runtime by Hormon

Most users create templates in an old fashioned way. They take the scene, place required controls and components on template form and write some code. Although it’s nothing wrong with that (I do it all the time) sometimes I’m really frustrated. Mostly because I have to do copy and paste for the tenth time for a similar scene but with some new functionality added. I’m really lazy, so at some point I started to think of a way to construct some kind of a mechanism to do this work for me.

Creating components dynamically

Some of you may have noticed that Content Pilot vbscript implements two interesting methods which allow user to create components while the template is running: CreateVTWComponent and ConnectVTWEvent. If we look into Predefined Function List we get this usage:

CreateVTWComponent(ComponentType, Owner)
ConnectVTWEvent([_scripter], Component, EventName, ScriptEvent)

So we can say it provides us with all we need to dynamically create any supported component from our code. The only thing we should do is to write our functions. It took me just few minutes to end up with following ones:

Following function creates desired component in our template:

Function CreateChildComponent(control_type, top, left, width, height, owner)
  Dim newCtrl
  newCtrl = CreateVTWComponent(control_type, [_template])
  newCtrl.Parent = owner

  If (top > -1) Then
     newCtrl.Top = top
  End If
  If (left > -1) Then
     newCtrl.Left = left
  End If
  If (width > -1) Then
     newCtrl.Width = width
  End If
  If (height > -1) Then
     newCtrl.Height = height
  End If
  CreateChildComponent = newCtrl
End Function

Following function removes component from template:

Function DeleteComponent(ctrl_name)
  Dim ctrl
  ctrl = FindComponent(ctrl_name)
  On Error Resume Next
  If (Err = 0) Then
    ctrl.Free
    DeleteComponent = true
  Else
    DeleteComponent = false
  End If
End Function

For my template I use Option Explicit statement at the top of my code. As you can see if I want to create i.e. a Button I just have to invoke first function like this:

Dim myButton
myButton = CreateChildComponent("TTWUniButton", 5, 5, 150, 40, myParentControl)
myButton.Name = "btnTest"
myButton.Caption = "Test"

where myParentControl is either [_template] or any other container control (like Panel) which already exists in template. Now let’s quickly have a click event connected to this button. The only thing we should do is use ConnectVTWEvent function. So let’s assume we have a btnTestClick(Sender) subroutine already written. Now:

dummy = ConnectVTWEvent([_scripter], myButton, "OnClick", "btnTestClick")

and we’re done :-).

How can we make our templates more flexible?

For now everything looks great but what’s the point of all of this? Well I’ll give you one example which I actually use a lot. One of the auditions which we air every day in our virtual set often changes it’s appearance. Most changes are very small – additional directors are added to the stage and I have to provide control for them. The base functionality never changes, so it’s just a copy and paste scenario. All I did (till now) was placing three buttons (Back, Previous and Continue) on template, and attached proper click events to them. But once we know how to create components dynamically we can pass this work to the template itself ( laziness is bliss :-) ).

So I talked with artist and told them that whenever they need additional director to be controlled from template they should give it the name starting with “DYN_” prefix. Next I wrote a small function which queries the scene to get the directors from stage which names start with this prefix. It looks like this:

Sub GetDynamicDirectors()
  Dim cmd
  cmd = SCENE_NAME & "*STAGE*DIRECTOR GET"

  Dim ans, cnt
  cnt = 0

  Dim directors
  ans = SendSingleCmd(txtComp01.UTF8Text, cmd, true)
  If (InStr(ans, "ERROR") > 0)  Then
    MsgBox(ans)
    Exit Sub
  End If

  ans = Mid(ans, InStr(ans, " ") + 1)
  directors = Split(ans, " ")

  For Each dir In directors
    If (dir <> "") Then
      If (InStr(dir, dynPrefix) = 1) Then
        cnt = cnt + 1
        If (cnt > 1) Then
           dynamicDirectors = dynamicDirectors & " "
        End If
        dynamicDirectors = dynamicDirectors & dir
      End If
    End If
  Next

End Sub

What it does is get the list of all directors from scene and then filter those which name doesn’t begin with “DYN_” (stored in global variable dynPrefix). The list of directors which met this criteria is stored inside dynamicDirectors variable declared as global. Last thing I did was to place the call to this function in SC_OnVariantChange event handler. Once I get the list of additional functionality directors, for each of them I created proper controls on my template.

Have a look at the final result below.

Lower panel contains additional functionality directors. This list is refreshed when user changes selected Variant.

That’s it for now. Hope you’ll find it usefull.

GHTime Code(s): 55344 

Leave a comment

Your comment