qooxdooで作成されたWebページをカスタマイズする

Webアプリケーションフレームワーク「qooxdoo」を利用すれば、JavaScriptのコードのみでインタラクティブなWebアプリケーションを作成することができる。前回はqooxdooを用いてWebアプリケーションの雛型を作るまでの手順を紹介した。今回は、qooxdooで提供されるGUIツールキットを利用してWebページをカスタマイズしてみたい。

qooxdooに用意されたAPIはAPIドキュメントで見ることができる。非常に多くのパッケージが並んでいるが、GUI部品に関連するものはこのうちのqx.uiパッケージに含まれる。個々のGUI部品の使い方はデモブラウザで紹介されている。本稿では入力フィールドとボタン、テーブルを用いた非常にシンプルな例を使って、GUIツールキットでWebページをコーディングする一連の流れを紹介する。

qooxdooのGUI部品はJavaにおけるSwingなどとよく似たアーキテクチャになっている。すなわち、基本はコンテナを用意してその上にコンポーネントを配置していくという形であり、個々のコンポーネントはそれぞれクラスとして定義されている。コンテナを複数積み重ねて使用できる点や、レイアウトを補助するレイアウトマネージャが用意されている点などもよく似ている。

たとえば、次のコードはqx.ui.container.Compositeというコンテナにレイアウトマネージャを設定し、ボタンをひとつ配置したコード例である。使用しているレイアウトマネージャはqx.ui.layout.Basicで、これは左端からの距離leftと、上端からの距離topを指定することで、コンポーネントの配置を決めるというもの。ボタンを表すクラスはqx.ui.form.Buttonで、{left:50, top:20}の位置に配置している。

リスト1

var container = new qx.ui.container.Composite();
container.setLayout(new qx.ui.layout.Basic());

var button = new qx.ui.form.Button("押す!");
container.add(button, {left:50, top:20});

ボタンがクリックされた場合には、qx.ui.core.MExecutable#executeイベントが発生する。これを受け取るリスナは次のようにして登録する。

リスト2

button.addListener("execute", function(e) {
    alert("ボタンが押されました。");    // リスナの処理
});

ごく簡単な例だが、GUI部品の配置については基本的にはこの繰り返しとなる。

では以上を踏まえた上で、Application.jsを修正して図1に示すようなページをレイアウトしてみようと思う。プロジェクト名は「myapp2」を利用する。

図1 今回作成するWebページ

Application.js全体の構造はリスト3のようにした。新しく追加したcreateTableメソッドはテーブルを作成するためのもの(中身は後述)。

リスト3

qx.Class.define("myapp2.Application",
{
  extend : qx.application.Standalone,

  members :
  {

    /**
     * テーブルオブジェクトを作成して返す
     */
    createTable : function()
    {
        // リスト6を参照
    },

    /**
     * メインメソッド
     */
    main : function()
    {
      // Call super class
      this.base(arguments);

      // ログ出力を有効にする
      if (qx.core.Variant.isSet("qx.debug", "on"))
      {
        qx.log.appender.Native;
        qx.log.appender.Console;
      }

      /*
      -------------------------------------------------------------------------
        以下を修正してアプリケーションを作成する
      -------------------------------------------------------------------------
      */
      // リスト4を参照

      // リスト5を参照

      // テーブルを作成
      var messageTable = this.createTable();

      // リスト7を参照

      // リスト8を参照

      // アプリケーションのルートオブジェクトを取得
      var doc = this.getRoot();
      // コンテナをルートに追加
      doc.add(container, {left: 50, top: 30});
    }
  }
});

入力フィールドを構成するリスト4は次のように書ける。ここではボタンの他にラベルを表すqx.ui.basic.Labelとテキストフィールドを表すqx.ui.form.TextFieldを使っている。

リスト4

      // 入力フィールドを作成
      var label1 = new qx.ui.basic.Label("名前:");
          var namefield = new qx.ui.form.TextField("").set({
          width: 80
      });
      var label2 = new qx.ui.basic.Label("メッセージ:");
      var messagefield = new qx.ui.form.TextField("").set({
          width: 250
      });

      // ボタンを作成
      var setButton = new qx.ui.form.Button("セット");

入力フィールドの下には「最後のメッセージ」を表示するスペースを設けてある。ここには、最後に登録されたメッセージが表示されるようにする。この部分のソースは次のようにした。qx.ui.basic.Labelだが、qx.bom.Fontを使ってフォントを指定している点がほかとは異なる。

リスト5

      // メッセージラベルを作成
      var label3 = new qx.ui.basic.Label("最後のメッセージ:");
      var lastMessageLabel = new qx.ui.basic.Label("").set({
          decorator: "main",
          width: 400,
          font : new qx.bom.Font(20, ["Verdana", "sans-serif"])
      });

テーブルの作成はcreateTableメソッドで行っている。createTableメソッドの中身を以下に示す。

リスト6

    createTable : function()
    {
      //テーブルモデルを作成
      var tableModel = new qx.ui.table.model.Simple();
      tableModel.setColumns([ "名前", "メッセージ" ]);
      tableModel.setColumnEditable(0, true);
      tableModel.setColumnEditable(1, true);

      // テーブルを作成
      var table = new qx.ui.table.Table(tableModel);
      table.set({
          width: 400,
          height: 300,
          decorator : null
      });

      // カラムモデルを取得して列幅を設定
      var columnModel = table.getTableColumnModel();
      columnModel.setColumnWidth(0,100);
      columnModel.setColumnWidth(1,300);

      return table;
    },

テーブルに関するクラスはqx.ui.tableパッケージにまとめられている。テーブル本体はqx.ui.table.Tableクラスとして定義されており、モデルオブジェクトはqx.ui.table.model以下に用意されたクラスによって定義される。ここではもっとも一般的なqx.ui.table.model.Simpleを利用している。また、カラムモデルオブジェクトを操作することで列のプロパティを変更できる。ここでは列幅を変更している。

作成したコンポーネントを配置するには、コンテナオブジェクトを作成してadd()メソッドを使用すればよい。これは次のようになる。

リスト7

      // コンテナに各コンポーネントを配置
      var container = new qx.ui.container.Composite(new qx.ui.layout.Basic);
      container.add(label1, {left:10, top:4});
      container.add(namefield, {left:10, top:20});
      container.add(label2, {left:100, top:4});
      container.add(messagefield, {left:100, top:20});
      container.add(setButton, {left:360, top:20});
      container.add(label3, {left:10, top:64});
      container.add(lastMessageLabel, {left:10, top:80});
      container.add(messageTable, {left: 10, top: 130});

この例では、ボタンをクリックしたら入力した名前とメッセージがテーブルに追加されるようにしたい。また、最後に入力されたメッセージのみ「最後のメッセージ」の部分に表示したい。したがって、ボタンに対するイベントリスナは次のようになる。

リスト8

      // ボタンにイベントリスナを登録
      setButton.addListener("execute", function(e) {
          var name = namefield.getValue();
      var message = messagefield.getValue();
      if (name != "" && message != "") {
          lastMessageLabel.setValue(name + ": " + message);
          var tableModel = messageTable.getTableModel();
          tableModel.addRows([[name, message]]);
          messagefield.setValue("");
          namefield.setValue("");
      }
      });

最後に、コンテナをアプリケーションのルートオブジェクトに追加する。ルートオブジェクトはthis.getRoot();で取得できるので、それに対してadd()メソッドでcontainerを追加すればよい。

作成したアプリケーションにWebブラウザでアクセスし、メッセージを登録した様子を図2に示す。

図2 メッセージを登録した様子

qx.ui.table.model.Simpleを使ったテーブルは、デフォルトで各フィールドの編集やカラムの並べ替えなどにも対応している。図3は「名前」のカラム名をクリックして名前順に並べ替えた様子。

図3 テーブルのデータを名前順に並べ替えた様子

qooxdooはHTMLレスとは言ってもWYSIWIG的なものではく、あくまでもコーディング主体である。したがってJavaScriptの知識がなければ使いこなすのは難しいが、プログラマからすれば、その点がかえってわかりやすいと言えるかもしれない。