Chapitre 7. Introduction aux Vues

Table des Matières

1. Introduction
2. Constraintes et Modificateurs
3. Gestionnaires de mise en page et vues conteneurs

1. Introduction

Les vues sont l'élément visuel basique des applications OpenLaszlo. Elles permettent de préciser comment les éléments doivent intéragir les uns par rapport aux autres. Dans le tutoriel sur les Bases d'OpenLaszlo, nous avons vu comment préciser une organisation de haut en bas des éléments de texte. Dans ce tutoriel, vous allez apprendre comment créer des interactions plus complexes et plus puissantes entre les éléments visuels. 

Voici le code du tutoriel précédent :

Exemple 7.1. Simple fenêtre

<canvas height="300" width="500">
    <window x="20" y="20" width="200" height="250" 
            title="Simple Window" resizable="true">
        <simplelayout axis="y" spacing="10"/>
        <text>Here is some text.</text>
        <text>I could ramble for hours.</text>
        <button>My Button</button>
    </window>
</canvas>

Nous avons ajouté un bouton (My Button) juste pour se rappeler comment <simplelayout> affecte les éléments.

Ce bouton serait mieux s'il était centré. Il y a un attribut que nous pourrions utiliser pour faire cela, mais juste pour mieux comprendre comment fonctionne lZX, centrons le bouton de façon programmative. Cela vous donnera un bon aperçu de la façon dont fonctionnent les contraintes et les modificateurs et vous permettra de concevoir des programmes plus complexes.

2. Constraintes et Modificateurs

Une contrainte est un objet qui s'occupe de garder la propriété d'un vue fixée à une certaine valeur. Suivant le type de contrainte, la valeur peut être la 'position x de la souris' ou 'la largeur de la vue mère' ou bien d'autres choses. Dans ce cas, nous allons créer une contrainte entre une propriété et la largeur de la vue mère. 

Exemple 7.2. Contrainte entre la position du bouton et la fenêtre

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
          title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${immediateparent.width / 2}" >
      My Button
    </button>
  </window>
</canvas>

Ce que nous avons demandé ici est "lier la position x du bouton avec la moitié de son parent". En fait, nous avons même précisé "parent immédiat" ("immediateparent"), ce qui est généralement ce qu'on entend par parent (vous devez simplement ajouter ces 9 caractères supplémentaires). Dans ce cas, le parent immédiat (immediateparent) est le contenu de la fenêtre (la zone blanche). En résumé, nous avons ici dû utiliser is the window's content area (the white bit). In short we had to use immediateparent parce que la fenêtre (<window>) est une classe, et que quand vous l'instanciez et ajoutez du contenu à l'intérieur, vous devez utiliser la référence immediateparent depuis les éléments contenus pour la référencer.

Le modificateur ici est l'opérateur "divise par deux". 

Remarquez que ce code ne centre pas le bouton. Cependant, il contraint la position du bouton sur le milieu de la fenêtre. Le problème est que la position d'une vue est déterminée par son coin supérieur gauche. Pour centrer le bouton, nous devons le déplacer de la moitié de sa largeur. Une façon de faire cela serait de donner au bouton une largeur déterminée, et de décaler la contrainte de la moitié. 

Exemple 7.3. Centrage du bouton

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
        title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button width="160" x="${immediateparent.width / 2 - 80}">
      My Button
    </button>
  </window>
</canvas>

Cela fonctionne mais n'est pas une solution générique. Nous voulons que le bouton soit toujours au milieu de la fenêtre même si sa largeur varie. Voici comment faire :

Exemple 7.4. Un bouton qui reste centré

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
          title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2) 
                       - (this.width / 2)}">
      My Button
    </button>
  </window>
</canvas>

Cela va centrer le bouton quelle que soit sa taille. Les parenthèses ont été ajoutées pour clarifier la séquence d'exécution du code. 

Pour prouver cela, nous allons ajouter un script 'onclick' au bouton.

Pour l'instant, vous n'avez pas besoin de comprendre comment cela fonctionne. Observez simplement que quand vous cliquez sur le bouton, sa taille augmente. Nous reverrons ce sujet dans le tutoriel d'introduction à la programmation de scripts. 

Exemple 7.5. Bouton qui grossit

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
            title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2) 
                         - (this.width / 2)}"
      onclick="this.setAttribute('width', this.getAttribute('width') + 10);" >
        My Button
      </button>
   </window>
</canvas>

Remarquez que pendant que le bouton grossit, il reste centré. 

Dans l'exemple précédent, nous utilisons deux méthodes pour référencer les propriétés d'une vue. Par exemple, nous utilisons this.getAttribute('width') et this.width. Elles sont différentes, et il y a des situations particulières dans lesquelles vous pourrez ou ne pourrez pas utiliser la syntaxe this.width. De façon sommaire, this.width peut seulement être utilisé dans des expressions de contraintes.

3. Gestionnaires de mise en page et vues conteneurs

Maintenant comment faire pour définir une rangée de boutons en haut de notre fenêtre ? Nous pouvons essayer d'ajouter quelques boutons en haut :

Exemple 7.6. Boutons alignées verticalement

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
          title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
    <button>1</button>
    <button>2</button>
    <button>3</button>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2) 
                       - (this.width / 2)}"
            onclick="this.setAttribute('width', this.getAttribute('width') + 10);">
      My Button
    </button>
  </window>
</canvas>

Nous ne pouvons pas changer la balise We can't change the <simplelayout>, car cela désorganiserait les autres éléments de la fenêtre. A la place, nous pouvons ajouter les trois boutons à leur propre vue, la vue devenant alors un seul élément pour la fenêtre.

Nous pouvons alors définir le type de mise en page / positionnement que nous voulons à la vue des boutons :

Exemple 7.7. Regroupement des boutons dans une vue

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
          title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
      <view bgcolor="#ff0000">
      <simplelayout axis="x" spacing="5"/>
      <button>1</button>
      <button>2</button>
      <button>3</button>
    </view>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2)
                       - (this.width / 2)}"
            onclick="this.setAttribute('width', this.getAttribute('width') + 10);">
      My Button
    </button>
  </window>
</canvas>

C'est mieux. En utilisant l'attribut That's better. By using the attributebgcolor (couleur d'arrière plan) nous pouvons voir la taille de la vue; elle est juste de la taille nécessaire. Nous n'avons précisé ni la hauteur ni la largeur, elle est juste assez large pour afficher les boutons. 

Et si nous voulions que la rangée ressemble aux barres d'outils en haut des navigateurs - une couleur uniforme, qui s'étire de part en part ? 

Nous pourrions contraindre la largeur de la vue rouge sur la largeur de son parent. 

Exemple 7.8. Contrainte d'une largeur à la largeur du parent

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
            title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
    <view bgcolor="#ff0000"
          width="${parent.width}">
      <simplelayout axis="x" spacing="5"/>
      <button>1</button>
      <button>2</button>
      <button>3</button>
    </view>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2) - (this.width / 2)}"
            onclick="this.setAttribute('width', this.getAttribute('width') + 10);">
      My Button
    </button>
  </window>
</canvas>

Maintenant la vue s'étire sur toute la largeur mais si vous regardez les barres d'outils, vous remarquerez qu'elles sont un peu plus hautes que les boutons qu'elles contiennent. Pour donner la même apparence, nous pourrions définir une hauteur absolue, mais rendons-la dépendante de l'un des boutons :

Exemple 7.9. Contrainte d'une vue par rapport à la hauteur d'un fils

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
            title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
    <view bgcolor="#ff0000"
                  width="${parent.width}"
                  height="${this.refButton.height + 8}">
      <simplelayout axis="x" spacing="5"/>
      <button name="refButton">1</button>
      <button>2</button>
      <button>3</button>
    </view>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2) - (this.width / 2)}" 
            onclick="this.setAttribute('width', this.getAttribute('width') + 10);">
      My Button 
    </button>
  </window>
</canvas>

Pour être capable de référencer un bouton particulier, nous devons lui donner un nom avec l'attribut name.

Maintenant les boutons sont alignés en haut - ils devraient être centrés au milieu de la barre rouge. Vous rappelez-vous ce que nous avons dit plus haut, à savoir qu'il existait un attribut pour aligner les éléments au centre ? Nous allons l'utiliser :

Exemple 7.10. Utilisation de l'attribut 'valign'

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
          title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
      <view bgcolor="#ff0000"
            width="${parent.width}"
            height="${this.refButton.height + 8}">
        <simplelayout axis="x" spacing="5"/>
        <button name="refButton" valign="middle">
          1
        </button>
        <button>2</button>
        <button>3</button>
      </view>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2) - (this.width / 2)}" 
            onclick="this.setAttribute('width', this.getAttribute('width') + 10);">
      My Button 
    </button>
  </window>
</canvas>

L'attribut valign centre la vue par rapport à la hauteur de la vue mère. Il peut seulement prendre les valeurs top(haut), center(centre) ou bottom(bas). Il y a de même un attribut align pour aligner des vues suivant l'axe x. Le seul problème là dedans est que nous devrions préciser pour chaque bouton un attribut align.

La solution est d'encapsuler tous les boutons dans une vue. Alors nous pouvons appliquer l'attribut valign à l'ensemble.

Example 7.11. Applying 'valign' to container view

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
          title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
    <view bgcolor="#ff0000"
          width="${parent.width}"
          height="${this.buttons.refButton.height + 8}">
      <simplelayout axis="x" spacing="5"/>
      <view name="buttons" valign="middle">
        <button name="refButton">1</button>
        <button>2</button>
        <button>3</button>
      </view>
    </view>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2) - (this.width / 2)}" 
            onclick="this.setAttribute('width', this.getAttribute('width') + 10);">
      My Button 
    </button>
  </window>
</canvas>

Bien, il semble que nous ayons perdu les boutons un et deux, nous reviendrons là-dessus. Vous remarquerez que nous avons donné à la nouvelle vue un nom : "buttons". Nous avons aussi dû changer la référence sur la hauteur du bouton de OK, we seem to have lost buttons one and two, but let's come back to that. You'll notice that we gave the new view a name: "buttons". We also had to change the address to the button's height from this.refButton.height à this.buttons.refButton.height. C'était nécessaire car refButton est maintenant à l'intérieur de buttons, lui-même à l'intérieur de la vue rouge.

Maintenant faisons revenir les boutons un et deux ! Dans la vue "buttons", il n'y a rien qui précise à l'environnement d'exécution d'OpenLaszlo comment il doit espacer les boutons. Pourquoi ? Parce que nous avons oublié de transférer la balise Now to get buttons one and two back! In the "buttons" view, there is nothing to tell the OpenLaszlo Runtime that it should space them out. Why not? Because we forgot to transfer the <simplelayout> dans la vue buttons.

Example 7.12. Using <simplelayout> to align buttons

<canvas height="300" width="500">
  <window x="20" y="20" width="200" height="250" 
          title="Simple Window" resizable="true">
    <simplelayout axis="y" spacing="10"/>
      <view bgcolor="#bdbdbd"
            width="${parent.width}"
            height="${this.buttons.refButton.height + 8}">
        <view name="buttons" valign="middle">
          <simplelayout axis="x" spacing="5"/>
          <button name="refButton">1</button>
          <button>2</button>
          <button>3</button>
        </view>
      </view>
    <text>Here is some text.</text>
    <text>I could ramble for hours.</text>
    <button x="${(immediateparent.width / 2) - (this.width / 2)}" 
            onclick="this.setAttribute('width', this.getAttribute('width') + 10);">
      My Button 
    </button>
  </window>
</canvas>

Nous avons changé la couleur de la vue pour lui donner une meilleure apparence.