OpenLaszloでマルチデバイス対応RIAを作ろう

第11回OpenLaszloのオブジェクト指向プログラミング

OpenLaszloのアプリ開発言語LZXはオブジェクト指向プログラミング言語です。オブジェクト指向の技法を使うとコーディングの効率化が図れたり、コンポーネントの改造や自作が可能になります。

クラス作成とインスタンス化

クラスとは、オブジェクト指向言語でよく出てくる言葉で、わかりやすくいうとひな型とかテンプレートの意味です。インスタンスとは、ひな型を実際に利用できる形にしたものをいいます。

まず、オブジェクト指向を使わない場合と使った場合でのサンプルコードを2つ示して解説します。もちろんどちらも同じ動作結果になるものです。

リスト1のサンプルは、全く同じ黄色い四角を3つ並べたもので、オブジェクト指向ではないコーディングです。

リスト1
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <view height="50" width="100" bgcolor="yellow" />
  <view height="50" width="100" bgcolor="yellow" />
  <view height="50" width="100" bgcolor="yellow" />
</canvas>
リスト1 サンプル

リスト1の問題点は、同じ記述を繰り返さないといけないという非効率さと、今後設定を変えるときのメンテナンス性の悪さですね。もちろんサンプル自体は簡単な例にすぎません。これが本格的なアプリだと問題の大きさは膨大になります。これをオブジェクト指向プログラミングで解決することができます。

まず黄色い四角のひな型=クラスを作成します。クラスを作成するためのタグは<class>です。では、リスト1の<view>をクラス化してみましょう。まずタグ名をviewからclassに変更します。次にnameでクラス名を付けます。ここではmyViewと名付けています。クラス名の命名規則としては、既存のクラス名と重複できないなど一般的な制約はありますが、特に厳密な制約はなく割と自由です。これでクラスの作成は完了です。

リスト2
<view height="50" width="100" bgcolor="yellow" />
                  ↓
<class name="myView" height="50" width="100" bgcolor="yellow" />

クラス作成はタグのひな型を定義するだけのもので、それだけではなにも動作しません。動作させるにはクラスをインスタンス化します。インスタンス化するといってもLZXの場合はクラス名でのタグを記述するだけです。ここではmyViewクラスを作成したので、そのインスタンスは<myView>というタグになります。

リスト3では、<myView>タグを3つ記述しています。するとリスト1のサンプルと同じように黄色い四角が3つ表示されます。表示している実体は<myView>です。

リスト3
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <!--myViewクラス-->
  <class name="myView" height="50" width="100" bgcolor="yellow" />
  <!--myViewインスタンス-->
  <myView />
  <myView />
  <myView />
</canvas>
リスト3 サンプル

実はこれまでに頻繁に出てきた<text>や<button>、<window>などのタグもすべてLZXのクラスとしてOpenLaszlo側であらかじめ定義されていて、プログラムを書くとき(=タグを書くとき)に無意識のうちにそれぞれをインスタンス化していたことになります。

それでは、仕様変更のシミュレーションとしてmyViewクラスを改造してみましょう。<class>の中に<view>を1つ追加し、それを親タグよりも縦横4ピクセル小さくして縦横中央に配置することで、赤い枠線付きの黄色い四角に改造しました。インスタンスとしての<myView>の記述には何も変更がありません。このようにひな型であるクラスを変更するだけで一気にアプリ全体の該当タグの挙動を変更することができます。

リスト4
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <class name="myView" height="50" width="100" bgcolor="red" >
    <view width="${parent.width-4}" height="${parent.height-4}"
      align="center" valign="middle" bgcolor="yellow" />
  </class>
  <myView />
  <myView />
  <myView />
</canvas>
リスト4 サンプル

自作のタグ<myView>は普通の<view>と同じように扱えますので、個別に属性を設定をすることができます。リスト5は幅、高さ、色の変更や、子タグの追加をしてみた例です。

リスト5
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <class name="myView" height="50" width="100" bgcolor="red" >
    <view width="${parent.width-4}" height="${parent.height-4}"
      align="center" valign="middle" bgcolor="yellow" />
  </class>
  <myView height="100" />
  <myView bgcolor="blue"/>
  <myView width="200" >
    <text align="center" valign="middle">自作クラスサンプル</text>
  </myView>
</canvas>
リスト5 サンプル

クラスの継承

クラスを作成するとき、既存のクラスの全設定を引き継いで新しいクラスを作成することになります。これを継承と呼びます。<class>のextends属性で継承元クラスを指定します。extendsのデフォルトは<view>なので、これまでのサンプルで作成したmyViewクラスの継承元クラスは実は<view>でした。つまり、自作myViewクラスは<view>の持つすべての属性・メソッド・イベントハンドラを備えていることになります。

myViewクラスを継承して、枠線付きボックスという性質はそのままで、新しく正方形という性質を持つクラスを作成してみましょう。リスト6では、width値をheight値と同じにする、という設定を付け加えることで正方形になるmySquareクラスを作成してみた例です。

リスト6
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <!--myViewクラス-->
  <class name="myView" height="50" width="100" bgcolor="red" >
    <view width="${parent.width-4}" height="${parent.height-4}"
      align="center" valign="middle" bgcolor="yellow" />
  </class>
  <!--myViewクラスを元に作ったmySquareクラス-->
  <class name="mySquare" width="${this.height}" extends="myView">
  </class>
  <!--mySquareインスタンス-->
  <mySquare />
</canvas>
リスト6 サンプル

属性の設定

リスト6の正方形クラスにはひとつ問題があります。mySquareタグでheightを設定したときは必ず正方形になりますが、widthを設定すると正方形になりません。これでは失敗ですね。

そこで属性を定義するためのタグ<attribute>を使って改善してみましょう。<attribute>はwidth、heightなどの既存の属性を扱うこともできますが、新たな属性名を指定した場合、属性を新規作成することになります。

リスト7のmySquareクラスでは、sizeという名前の属性を定義し、widthとheightにsize属性値を代入するようにしました。つまり、size属性を1つ設定するだけで縦横の設定を同時にでき、正方形になるということです。mySquareインスタンスでは、四角のサイズをwidth/heightではなくsizeで設定します。

リスト7
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <!--myViewクラス-->
  <class name="myView" height="50" width="100" bgcolor="red" >
    <view width="${parent.width-4}" height="${parent.height-4}"
      align="center" valign="middle" bgcolor="yellow" />
  </class>
  <!--myViewクラスを元に作ったmySquareクラス-->
  <class name="mySquare" width="${this.size}" height="${this.size}" extends="myView">
    <attribute name="size" value="80"/>
  </class>
  <!--mySquareインスタンス(1)-->
  <mySquare />
  <!--mySquareインスタンス(2)-->
  <mySquare size="120" />
</canvas>
リスト7 サンプル

イベントハンドラ

イベントハンドラは継承されます。

リスト8では、myViewクラスにonmouseoverとonmouseoutの2つのイベントハンドラを定義しています。実際の動作としては、マウスカーソルが四角の上を出たり入ったりするときに枠線の色が変わります。

myViewを継承したmySquareクラスではさらにonclickイベントハンドラを追加で定義し、size値を5ピクセルずつ増加させています。実際の動作としては、四角をクリックするたびに少しずつ大きくなります。mySquareでもマウスカーソルの出入りで枠線の色が変わるので、onmouseoverとonmouseoutの定義を継承しているのがわかります。

リスト8
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <class name="myView" height="50" width="100" bgcolor="red" >
    <handler name="onmouseover">
      this.setAttribute('bgcolor',"blue");
    </handler>
    <handler name="onmouseout">
      this.setAttribute('bgcolor',"red");
    </handler>
    <view width="${parent.width-4}" height="${parent.height-4}"
      align="center" valign="middle" bgcolor="yellow" />
  </class>
  <class name="mySquare" width="${this.size}" height="${this.size}" extends="myView">
    <attribute name="size" value="40"/>
    <handler name="onclick">
      this.setAttribute('size',this.size+5);
    </handler>
  </class>
    
  <myView />
  <mySquare />
</canvas>
リスト8 サンプル

メソッド

メソッドも継承できます。メソッドを継承したときは内容は上書きになります。

リスト9のサンプルでは、mySquareクラスでsize属性値を5ずつ増やすchangesize()メソッドを定義しています。そのmySquareクラスを継承したmySquare2クラスではchangesize()メソッドを再定義し、今度はsize属性値を5ずつ減らす処理に変更しています。

サンプルの四角をクリックすると、上の四角は大きくなり、下の四角は小さくなります。

リスト9
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <class name="myView" height="50" width="100" bgcolor="red" >
    <handler name="onmouseover">
      this.setAttribute('bgcolor',"blue");
    </handler>
    <handler name="onmouseout">
      this.setAttribute('bgcolor',"red");
    </handler>
    <view width="${parent.width-4}" height="${parent.height-4}"
      align="center" valign="middle" bgcolor="yellow" />
  </class>
  <class name="mySquare" width="${this.size}" height="${this.size}" extends="myView">
    <attribute name="size" value="40"/>
    <handler name="onclick">
      this.changesize();
    </handler>
    <method name="changesize">
      // 5ずつ大きくするメソッド
      this.setAttribute('size',this.size+5);
    </method>
  </class>
  <class name="mySquare2" extends="mySquare">
    <method name="changesize">
      // 5ずつ小さくするメソッド
      this.setAttribute('size',this.size-5);
    </method>
  </class>
    
  <mySquare />
  <mySquare2 />
</canvas>
リスト9 サンプル

標準コンポーネントを継承

これまでのサンプルではextendsのデフォルトである<view>を継承したクラスでした。ここでは<text>、<button>、<window>といったOpenLaszloの標準コンポーネントを継承してカスタマイズした例を紹介します。

<text>を継承

<text>を継承したクラスです。文字列の背景色をつけてみた例です。

リスト10
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <class name="myText" bgcolor="aqua" extends="text">
  サンプル
  </class>
  <myText/>
  <myText/>
  <myText/>
</canvas>
リスト10 サンプル

<button>を継承

<button>を継承したクラスです。ボタンをおすたびにラベルが変わります。

リスト11
<canvas proxied="false" bgcolor="0xffffcc"> 
  <simplelayout spacing="5"/>
  <class name="myButton" width="100" extends="button">
    ボタン
    <handler name="onclick">
      this.setAttribute('text',this.text=="ボタン"?"ぼたん":"ボタン");
    </handler>
  </class>
  <myButton/>
  <myButton/>
  <myButton/>
</canvas>
リスト11 サンプル

<window>を継承

<window>を継承したクラスです。デフォルトだとウインドウのタイトルバーにある×ボタンを押すとウインドウがその場で消えますが、このサンプルではclose()メソッドを上書きして、消える代わりに上に移動するように変更してみました。画面からはみ出るので上に消えたように見えます。

リスト12
<canvas proxied="false" bgcolor="0xffffcc"> 
  <class name="myWindow" width="200" height="80" closeable="true" extends="window">
    <method name="close">
      this.animate('y',-100,700,false);
    </method>
  <text>閉じると上に消えていきます。</text>
  </class>
  <myWindow title="ウインドウ1"/>
  <myWindow title="ウインドウ2" y="100"/>
  <myWindow title="ウインドウ3" y="200"/>
</canvas>
リスト12 サンプル

おすすめ記事

記事・ニュース一覧