Zeus Objects

Objects in Zeus are very similar to objects or components in other programming languages.  In Delphi there are "components" such as buttons, edit boxes, etc.  In Visual Basic there are ActiveX "controls" and "COM Objects".  In Microsoft .NET there are .NET "objects".  These are all names for the same concept.  An "object" in Zeus is just a collection of data with properties of the data, and methods that act upon the data.

For example, consider a "button" object.  A button is a visual object, which means you can interact with it with the keyboard and mouse and can see it on the screen.  A button object has properties such as "text", which is the text caption shown on the label, a "color" for the button.  A button has a method called "Click" which simulates clicking the button, performing any action associated with the button.

The core Zeus system comes with many built-in objects.  You can use and interact with these objects just like objects in other programming languages.  In fact, within the scripting language that you are using (such as VBScript), a Zeus object works just like normal COM objects.

For example, in VBScript, you can create a COM object using the "createobject" method:

set Browser = createobject("Shell.Explorer")

Once the object is created, you can access it's properties and call it's methods:

URL = Browser.LocationURL
Browser.Navigate("http://www.zuggsoft.com")

Zeus objects can be handled in the same way.  The distinction is that Zeus objects are not true COM objects.  So, instead of using "createobject" you need to use "core.createobject" like this:

set EditBox = core.createobject("zEdit", "")

You can then access it's properties and call it's methods just like a normal COM object:

EditBox.Text = "this is a test"

Here is a summary of Zeus objects:

Creating Zeus Objects

In the previous section we saw a simple example of creating a Zeus object within your script.  However, Zeus provides more powerful mechanisms for object creation.

In the previous example, the second argument in the core.createobject method was the name of the "parent" control or form that contains the object.  Normal we would want an EditBox to be displayed within a particular window or panel.  So, you would normally do something like this:

set EditBox = core.createobject("zEdit", "mainform")

to put the edit box onto the form called "mainform" in the application you are building.  This is an example of dynamic object creation where you create the object within your script.  In Zeus, it is usually better to create the object as part of your user interface layout.  This is done by adding the object to your ZML file that defines your application.  For example, to put this edit box within the main form, you add the line:

<edit name='EditBox'>this is a test</edit>

somewhere within the <window name='mainform'> window declaration.  Note that the XML tag used for the object is the same as the object class name, with the initial 'z' removed.  So, the class name for core.createobject is "zEdit" but the XML tag for creating the object is just "edit".  The "name" property in the XML tag specifies the name of the object for use in your script.  If you never need to refer to the object in your script then the name property isn't needed.  The text "this is a test" is assigned to the default property of the object, which in the case of the zEdit object is the "text" property.  You can initialize any property of the object within the XML tag.  For example, the XML line:

<edit name='EditBox' color='red' align='left' text='this is a test'/>

is equivalent to the script:

set EditBox = core.createobject("zEdit", "mainwindow")
EditBox.color = "red"
EditBox.align = "left"
EditBox.text = "this is a test"

You can see where defining your objects as XML tags within your ZML application file can be quicker and easier.

Object Scope

There is one important difference between creating your object using the XML tag verses creating it in your script: the scope of the object.  When you create your object within your script, the object is "global".  Once it is created it remains in existence until you explicitly clear it using the script:

EditBox = nothing

which will then remove the object and free up any memory it was using.  Or, if you created this object while within a subroutine, like this:

sub MyRoutine
  set EditBox = core.createobject("zEdit", "mainwindow")
  ...do something with it here...
end sub

then the EditBox is automatically removed and freed at the end of the subroutine.  To force an object created within a subroutine to be global, you use the "dim" statement in VBScript:

dim EditBox
sub MyRoutine
  set EditBox = core.createobject("zEdit", "mainwindow")
  ...do something with it here...
end sub

In this case the EditBox is global and is not removed when the subroutine ends.

When you create an object using an XML tag in your ZML application file, the object is created when the window containing it is created and is destroyed when the window is destroyed.  For example:

<window name='mainwindow'>
  <edit name='EditBox'>this is a test</edit>
</window>

In this case, the EditBox object is only available when the "mainwindow" exists.  Once this window is closed, the EditBox is removed from memory and any reference to it in a script will cause an error.  To create a global object using XML, you put it's tag outside of the <window> tag.  This doesn't make any sense for visual controls, such as edit boxes, but can be very useful for variables using the <var> tag:

<var name='MyOption'>123</var>
<window name='optionwindow'>
  <edit name='EditBox'>=MyOption</edit>
</window>

In this example, a global variable object called "MyOption" is created with an initial value of 123.  When the EditBox is created within the window, it's Text property is set to the current value of "MyOption" using the syntax "=MyOption".  This creates an internal link between the EditBox and the MyOption variable.  When the user enters new text into the edit box, that text is stored in the global "MyOption" variable, replacing the previous value of 123.  This global variable remains even when the "optionwindow" window is closed.  If the application then opens a new "optionwindow" at a later time, the initial value of the EditBox in that window will be whatever value was last saved to the MyOption variable.  In other words, this allows the "optionwindow" EditBox to remember the previous value that was typed into it.

Overriding Zeus Objects

One of the most powerful features of Zeus is the ability to override any object within the Zeus system.  Because Zeus objects work just like normal COM objects, you can replace any Zeus object with a COM object that implements the same interface.

For example, let's consider a case where you have your own ActiveX object that implements a Edit Box.  Maybe instead of making a rectangular text box it makes an oval text box instead.  In order to override the built-in edit box, you just create your own using the normal "createobject" scripting method.  For example, here is what the default application might look like that uses the built-in zEdit edit box:

<window name='mainwindow'>
  <edit name='EditBox' align='top' color='red'>this is a test</edit>
  ...the rest of the application goes here
</window>

To override this with your special OvalTextBox ActiveX object you would just change the code to this:

<window name='mainwindow'>
  <script>
    set EditBox = createobject("myLib.OvalTextBox")
    EditBox.Parent = MainWindow.Handle
    EditBox.Align = "top"
    EditBox.Color = "red"
    EditBox.Text = "this is a test"
  </script>
  ...the rest of the application goes here
</window>

The rest of your application will not notice the change.  As long as your "OvalTextBox" implements the necessary properties, such as "color" and "text" just like the built-in edit box, then the rest of the application will work fine.

Now, in the case of external ActiveX controls like this, there is even an easier way to override an existing object using the <activex> XML tag.  The above code could have also been written like this:

<window name='mainwindow'>
  <activex name='EditBox' classname='myLib.OvalTextBox' align='top' color='red' text='this is a test'/>
  ...the rest of the application goes here
</window>

The advantage of using this method for visual ActiveX controls is that Zeus handles setting the Parent of the control so that it is displayed in the proper place within the window.  Also, Zeus will implement properties such as "align", "left", "top", "width", "height" for you so that the ActiveX control itself doesn't have to implement these properties (and these properties of the ActiveX control are ignored in this case).

Again: as long as your replacement object has the same properties and methods as the default object, the rest of the application won't notice the replacement.

From a technical point of view, this means that Zeus is not performing any type checking.  When you access the "EditBox.Text" property somewhere in your application, Zeus doesn't check to see if EditBox has this property or not.  Zeus assumes that you know what you are doing.  If EditBox does not have a Text property, you will get a runtime error when you try to access it.  All of the COM objects in Zeus use "late binding".

This means that technically, your COM object doesn't even have to implement the same exact "interface" of the Zeus object (in the formal COM sense of interfaces).  Your object just has to have the same property names and methods as the Zeus object.  For methods, your methods need to accept the same type of arguments as the builtin Zeus object.  But you only need to implement those properties or methods that you actually use.  For example, if you never accessed the "color" property of your EditBox anywhere in your application, then you don't need to implement this property in your OvalTextBox object.  Zeus doesn't care about anything that you don't access.

Overriding objects within a script

It's even easier to override a built-in Zeus object within a script.  For example, if the existing script looks something like this:

Set EditBox = core.createobject("zEdit", "mainwindow")
EditBox.Text = "this is a test"

then you could substitute your custom OvalTextBox by simply changing the code to:

Set EditBox = createobject("myLib.OvalTextBox")
EditBox.Parent = mainwindow.Handle
EditBox.Text = "this is a test"

The extra line for setting the Parent of your custom object is only needed for visual objects.  This example assumes that your object has a "Parent" property which points to the Windows Handle of the parent control.  You fetch the Windows Handle of the "mainwindow" form and assign it to the Parent property of your object to force your object to be displayed within that form.  Once you have set the Parent of your visual control, then accessing other properties, such as the "Text" property is just the same as before.

Summary

The major points of this article are:

  1. Zeus objects work just like normal COM objects in scripts.
  2. Zeus objects can be created using the core.createobject routine within a script, or, preferably, by using the XML <class...> tag within your ZML application file.
  3. You can override any Zeus object with any external ActiveX or COM object that you have available.
  4. When overriding Zeus objects, you only need to implement those properties or methods that you actually use in your application