Chapter 12. Introduction to Classes and Object Oriented Programming

Table of Contents

1. Introduction
1.1. The id attribute
2. Inheritance
3. Attributes
4. More Inheritance
5. Placing views inside of classes
5.1. Placing views using the placement attribute
5.2. Placing views by defining class with a defaultplacement attribute

1. Introduction

LZX is an object-oriented, prototype-based language that allows you to create custom, reusable classes to streamline and minimize code.

This tutorial shows you how to define and instantiate classes, as well as where to use them. The <class> tag is used to define classes. Classes are instantiated when the tag is used.

Example 12.1. Simple Class Example

<canvas width="100%" height="80">
  <class name="MyClass" width="80" height="25" bgcolor="#CFD9AB">
    <text align="center" valign="middle">Hello, World!</text>
  </class>
  
  <MyClass name="myFirstInstance"/>
</canvas>

The <class> tag defined the class, and the <MyClass> tag instantiated it. Everything that was in the definition of the class is inherited by each instance of it that is created. That is, the instance of MyClass inherits a width of 80, a height of 25, a background color, as well as some text. The instance is named "myFirstInstance", in the same way we might name a <view> , or a <window> .

In fact, when we write <window>, we are actually instantiating the window class, which is a pre-defined class.

In this example, there is only one element within the class (the <text> element). But classes can contain many objects; for example, views can contain many subviews.

1.1. The id attribute

It's important to note that you should not assign an id attribute in a class definition. Each id should be unique; ids are global and if you were to include an id assignment in the class definition, then creating several instances of a class would several views with the same id, which would cause unpredictable behavior.

2. Inheritance

As mentioned above, instances of <MyClass> are going to inherit from it. Just because we didn't specify x and y coordinates in the class definition doesn't mean we can't give them to the instance:

The <class> tag defined the class, and the <MyClass> tag instantiated it. Everything that was in the definition of the class is inherited by the instance of it that we have created. i.e. The instance of <MyClass> inherits a width of 80, a height of 25, a background color, as well as some text. The instance is named "myFirstInstance", in the same way we might name a view, or a <window>.

The instances behave just like views. In fact, that's because we are extending the view class. By default, the <class> tag extends the view class, so:

<class name="MyClass">

… is the same as…

<class name="MyClass" extends="view">

It follows that you can extend any class you want:

Example 12.2. Extending the 'button' class

<canvas width="100%" height="80">
  <class name="SpecialButton" extends="button" onclick="changeLabel()">
    <method name="changeLabel">
      this.setAttribute('text', 'Clicked! ');
    </method>
  </class>
  
  <SpecialButton>Not clicked</SpecialButton>
</canvas>

Since the <button> can take a text childnode that becomes its label, the <SpecialButton> class that extends it can also take the text childnode. The method changeLabel() is also inherited by the instance.

Just as with attributes, methods can be overridden in instances:

Example 12.3. Overwriting methods

<canvas width="100%" height="80">
  <class name="SpecialButton" extends="button" onclick="changeLabel()">
    <method name="changeLabel">
      this.setAttribute('text', 'Clicked!');
    </method>
  </class>
  
  <simplelayout axis="y" spacing="10"/>
  <SpecialButton>Not clicked</SpecialButton>
  <SpecialButton>
    Click Me Now
    <method name="changeLabel">
      this.setAttribute('text', 'Smashing!');
    </method>
  </SpecialButton>
</canvas>

Rewriting methods can be very handy when using both your own and pre-defined classes components, but it's not practical for when you have a class for which every instance may need a particular argument.

3. Attributes

We've used attributes before (e.g. width="160"), but these have been attributes that are present in the class we are extending. As mentioned above, it is useful to be able to pass an instance of a class an argument when it is created:

Example 12.4. Passing an argument to a class instance

<canvas width="100%" height="80">
  <class name="SpecialButton" extends="button" onclick="changeLabel()">
    <attribute name="changeToLabel" value="Clicked!" type="string"/>
    <method name="changeLabel">
      var newLabel = this.changeToLabel;
      this.setAttribute('text', newLabel);
    </method>
  </class>
  
  <simplelayout axis="y" spacing="10"/>
  <SpecialButton>Not clicked</SpecialButton>
  <SpecialButton changeToLabel="Thank You!">Please click me!</SpecialButton>
</canvas>

If we give the attribute a value, then that will be its default value, and will get assigned if we don't explicitly set it.

4. More Inheritance

You can extend a class more than once. For example, an application might contain more than one kind of button:

  • A standard button that is blue, then switches to green when we roll over it. Clicking this button writes out the name of a pet.

  • A special button, that is red, but also switches to green when we roll over it. Clicking this button writes out a day of the week.

Example 12.5. Extending a class more than once

<canvas width="100%" height="180">
  <resource name="standardButton">
    <frame src="resources/button_blue.gif"/>
    <frame src="resources/button_green.gif"/>
  </resource>

  <resource name="specialButton">
    <frame src="resources/button_red.gif"/>
    <frame src="resources/button_green.gif"/>
  </resource>

  <class name="MyButton" resource="standardButton" onclick="doAction()" onmouseover="doOver()" onmouseout="doOut()">
    <method name="doAction"> pet.addText("dog "); </method>
    <method name="doOver"> this.setAttribute('frame', 2); </method>
    <method name="doOut"> this.setAttribute('frame', 1); </method>
  </class>

  <class name="MySpecialButton" extends="MyButton" resource="specialButton">
    <method name="doAction"> weekday.addText("Monday "); </method>
  </class>

  <view name="buttons" x="5" y="5">
    <simplelayout axis="y" spacing="10"/>
    <MyButton/>
    <text id="pet"/>
    <MySpecialButton/>
    <text id="weekday"/>
  </view>
</canvas>

Here we only changed the doAction() method and the resource. The doOver() and doOut() methods remained the same, so there was no need to redefine them in the MySpecialButton definition.

5. Placing views inside of classes

Since we frequently write classes that extend view, at some stage we're going to need to place a view inside an instance of a class that we have created. For example, we may want to write a window class and put a text field inside of its title bar. Or we may want to put some content inside the middle of our window. There are two ways to do this: giving the subviews placement attributes, or giving the class the defaultplacement attribute.

5.1. Placing views using the placement attribute

If you had one view and you specifically wanted to place it in a particular subview of a class, you would use the placement attribute of that view.

An example is the title bar of a window: It's unlikely that you would need to place several things in the title bar of a window, so it's OK to have to add the placement attribute to the subview of the class that you want to place in the title bar.

5.2. Placing views by defining class with a defaultplacement attribute

If you want every subview of a class to be placed in the same location, then you give the class definition a defaultplacement attribute.

An example is the contents of a window class. If you built your own window class (see the window tutorial), you might well have an area for all window content. You might well place numerous subviews in that window, and you don't want to explicitly position each one.