Chapitre 12. Introduction aux classes et à la programmation orientée objet

Table des Matières

1. Introduction
1.1. L'attribut id
2. Héritage
3. Attributs
4. Plus sur l'héritage
5. Placer des vues dans des classes
5.1. Placer des vues en utilisant l'attribut de placement
5.2. Placer des vues en utilisant l'attribut de placement par défaut de la classe

1. Introduction

LZX est un langage orienté objet, basé prototype, qui permet la création de classes personnalisées et réutilisables en un minimum de code.

Ce tutorial vous montre comment définir et instancier des classes, mais également comment les utiliser. La balise <class> est utilisée pour définir des classes. Les classes sont instanciées quand les balises sont utilisées.

Exemple 12.1. Exemple de classe simple

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

La classe est définie en utilisant la balise <class>, et la balise <MyClass> l'instancie. Tout ce qui est défini dans la définition de la classe est hérité par chaque instance créée. Ainsi, l'instance de MyClass hérite d'une largeur (width) de 80, d'une hauteur (height) de 25 , d'une couleur d'arrière plan (bgcolor) ainsi que d'un texte. L'instance s'appelle "myFirstInstance", de la même façon que nous pourrions nommer une vue (<view>) ou une fenêtre (<window>)

En fait, quand nous écrivons (<window>), nous instançions en fait la classe window, qui est une classe prédéfinie.

Dans cet exemple, il n'y a qu'un élément dans la classe (l'élément <text>). Mais les classes peuvent contenir de nombreaux objets; par exemple, les vues peuvent contenir beaucoup de sous-vues.

1.1. L'attribut id

Il est important de remarquer que vous ne devez pas définir un attribut id dans une définition de classe. Chaque id doit être unique; les ids sont visibles globalement et si vous définissiez un id dans une définition de classe, créer plusieurs instances de cette classe reviendrait à créer plusieurs vues avec le même id, entraînant un comportement imprévisible.

2. Héritage

Comme nous l'avons vu précédemment, les instances de <MyClass> vont en hériter. Le fait de ne pas avoir spécifié de coordonnées x et y dans la définition de la classe ne signifie pas que nous ne pouvons pas les donner à ses instances.

La balise <class> a permis de définir la classe, et la balise <MyClass> a permis de l'instancier. Tout ce qui était dans la définition de la classe est hérité par ses instances. C'est à dire que les instances de <MyClass> héritent d'une largeur (width) de 80, d'une hauteur (height) de 25, d'une couleur d'arrière plan (bgcolor), ainsi que d'un texte. L'instance a pour nom "myFirstInstance", de la même façon que nous pourrions nommer une vue (<view>) ou une fenêtre (<window>).

Les instances se comportent exactement comme les vues. En fait, c'est parce que nous étendons la classe vue. Par défaut, la balise <class> étend la classe vue :

<class name="MyClass">

est équivalent à :

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

Ainsi vous pouvez étendre n'importe quelle classe :

Exemple 12.2. Etendre la classe 'button'

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

Comme la balise <button> a un noeud fils de type text qui définit son texte ('text'), la classe <SpecialButton> qui l'étend hérite aussi de ce noeud 'text'. La méthode changeLabel() est également héritée par l'instance.

De la même façon qu'avec les attributs, les méthodes peuvent être surchargées dans les instances :

Exemple 12.3. Surchargement de méthodes

<canvas width="500" 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>

La réécriture de méthodes peut être très pratique quand vous utilisez vos propres classes de composants ou celles prédéfinies, mais s'avère peu pratique quand vous avez une classe pour laquelle chaque instance a besoin d'un argument particulier.

3. Attributs

Nous avons déjà utilisé des attributs (par exemple width="180"), mais ils faisaient tous partie de la classe que nous étendions. Comme précisé précédemment, il est pratique de faire passer à une instance de classe un argument au moment de sa création :

Exemple 12.4. Passage d'arguments à des instances de classes

<canvas width="500" height="80">
  <class name="SpecialButton" extends="button" onclick="changeLabel()">
    <attribute name="changeToLabel" value="Clicked!" type="string"/>
    <method name="changeLabel">
      var newLabel = this.getAttribute('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>

Si nous donnons une valeur à l'attribut, cela devient sa valeur par défaut sans que nous n'ayons besoin de la définir explicitement.

4. Plus sur l'héritage

Vous pouvez étendre une classe plusieurs fois. Par exemple, une application pourrait avoir plusieurs types de boutons :

  • Un bouton standard de couleur bleue qui devient vert quand on passe dessus. Ce bouton affiche le nom d'un animal de compagnie.
  • Un bouton spécial de couleur rouge qui devient également vert quand on passe dessus. Ce bouton affiche le nom d'un jour de la semaine.

Exemple 12.5. Etendre une classe plusieurs fois

<canvas width="800" height="300" debug="true">
  <debug x="175"/>
  <resource name="standardButton">
    <frame src="../resources/button_blue.gif"/>
    <frame src="../resources/button_green.gif"/>
  </resource>
  
  <resource name="specialButton">
    <frame src="../resources/button_blue.gif"/>
    <frame src="../resources/button_red.gif"/>
  </resource>
  
  <class name="MyButton" resource="standardButton" 
         onclick="doAction()" onmouseover="doOver()" onmouseout="doOut()">
    <method name="doAction">
      Debug.write('Dog');
    </method>
    <method name="doOver">
      this.setResourceNumber(2);
    </method>
    <method name="doOut">
      this.setResourceNumber(1);
    </method>
  </class>
  
  <class name="MySpecialButton" extends="MyButton" resource="specialButton">
    <method name="doAction">
      Debug.write('Monday');
    </method>
  </class>
  
  <view name="buttons" x="125" y="5">
    <simplelayout axis="y" spacing="10"/>
    <MyButton/>
    <MySpecialButton/>
  </view>
</canvas>

Ici nous avons seulement changé la méthode doAction() et les ressources. Les méthodes doOver() et doOut() sont les mêmes car il n'y avait pas besoin de les redéfinir dans la définition de la classe MySpecialButton.

5. Placer des vues dans des classes

Comme nous écrivons souvent des classes qui étendent des vues, à un moment ou un autre nous devrons placer une vue dans l'instance d'une classe que nous venons de créer. Par exemple, nous pourrions vouloir écrire une classe fenêtre et mettre un champ texte dans sa barre des titres. Nous pourrions aussi vouloir placer un contenu au milieu de la fenêtre. Il y a deux façons de faire cela : en définissant pour les vues filles l'attribut de placement ( placement), ou en définissant dans la classe un attribut de placement par défaut ( defaultplacement).

5.1. Placer des vues en utilisant l'attribut de placement

Si vous aviez une vue et vouliez la placer à l'intérieur d'une sous-vue particulière d'une classe, vous pouvez utiliser l'attribut de placement (placement) de cette vue.

La barre des titres d'une fenêtre est un exemple : il n'est pas courant de mettre des choses dans la barre des titres d'une fenêtre, il est donc normal d'avoir à définir l'attribut placement pour la sous-vue que vous voulez mettre dans la barre des titres.

5.2. Placer des vues en utilisant l'attribut de placement par défaut de la classe

Si vous voulez que toutes les sous-vues d'une classe soient placées au même endroit, alors vous pouvez définir un attribut de placement par défaut (defaultplacement).

Par exemple le contenu de la classe window. Si vous deviez écrire votre propre classe fenêtre (voir le tutoriel sur les fenêtres), vous auriez probablement une zone définissant le contenu de la fenêtre. Vous pourriez mettre de nombreuses sous-vues dans cette fenêtre sans vouloir positionner chacune d'elles.