コントロールの作成
画面の構成を考えるとき、重要となるのが「コントロール」でしょう。他の要素はいくらでも操作できますが、コントロールは自動的に表示が生成されてしまいます。カスタマイズするためには、独自のコントロールを作成することを考えることになります。
コントロールは、org.apache.click.controlにある「AbstractControl」というクラスを継承して作られています。入力関係はこのサブクラスにあるFieldというクラスを継承して作られています。ここでは、AbstractControlを継承して、独自のコントロールを作ってみましょう。一例として、ラベルと入力フィールドをテーブルでレイアウトして表示する「BoxField」を作ってみます。また入力制御の一例として、入力されたアルファベットはすべて大文字に変換されるようにしてみましょう。
では、src内のjp.codezine.clickパッケージ内に「BoxField.java」というソースファイルを作成してください。そして次のように記述をしましょう。
package jp.codezine.click;
import org.apache.click.control.*;
import org.apache.click.util.HtmlStringBuffer;
public class BoxField extends AbstractControl {
private String value = "";
private String label = "";
public BoxField(String name, String label) {
super(name);
setLabel(label);
}
public void setValue(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public void onInit() {
super.onInit();
}
@Override
public String getTag() {
return "input";
}
@Override
public boolean onProcess() {
String requestValue = getContext().getRequestParameter(getName());
if (requestValue != null)
setValue(requestValue.toUpperCase());
registerActionEvent();
return true;
}
@Override
public void render(HtmlStringBuffer buffer) {
buffer.elementStart("table");
buffer.appendAttribute("class", "boxfield");
buffer.appendAttribute("border", "1");
buffer.elementStart("tr");
buffer.elementStart("th");
buffer.append(">" + label);
buffer.elementEnd("th");
buffer.elementEnd("tr");
buffer.elementStart("tr");
buffer.elementStart("td");
renderTagBegin(getTag(), buffer);
renderTagEnd(getTag(), buffer);
buffer.elementEnd("td");
buffer.elementEnd("tr");
buffer.elementEnd("table");
}
@Override
protected void renderTagBegin(String tagName,
HtmlStringBuffer buffer) {
super.renderTagBegin(tagName,buffer);
String val = getValue();
if (val != null) {
buffer.appendAttribute("value", val);
}
appendAttributes(buffer);
}
@Override
protected void renderTagEnd(String tagName,
HtmlStringBuffer buffer) {
super.renderTagEnd(tagName, buffer);
}
}
作成したら、入力フィールドとしてこのBoxFieldを使ってみましょう。利用の一例を以下にあげておきます。
public class HeloPage extends Page {
public String header = "";
public String footer = "";
public String title = "";
public String msg = "";
public Form form;
private BoxField box;
private Submit submit;
public HeloPage(){
this.getContext().setLocale(Locale.JAPAN);
}
@Override
public void onInit(){
header = this.getMessage("layout.header");
footer = this.getMessage("layout.footer");
title = this.getMessage("page.title");
msg = this.getMessage("page.init_msg");
form = new Form("form");
box = new BoxField("box","box");
form.add(box);
submit = new Submit("submit","submit");
form.add(submit);
this.addControl(form);
}
@Override
public void onPost() {
msg = box.getValue();
}
}
<style>
.boxfield tr th { background: #9999FF; }
.boxfield tr td { background: #CCCCFF; }
</style>
<h2 id="title">$title</h2>
<p>$msg</p>
<p>$form</p>
BoxFieldインスタンスを作成してフォームに組み込むことで、一般のコントロールと同様に使うことができるようになります。またboxfieldというクラスにスタイルシートを設定することで、表示スタイルを設定することもできます。
まとめ
今回は、表示についていろいろと考えてみました。Apache Clickで表示を考えるとき、はずせないのが「Velocity」の存在です。今回もメニュー作成でVelocityのマクロを利用したりしています。表示を考えるとき、テンプレートエンジンの存在は重要です。
この他、独自のコントロールとして部品を定義しておき、それらを組み合わせて表示を構成していくのも一つのアイデアです。よく使われる部品類を独自定義しておくことで、全体で統一したデザインを構築することができます。
また、Apache Clickでは、「ダイレクトレンダリング」といって、直接HTMLのソースをクライアントに出力させることもできます。これはPageのgetContext().getResponse()でHttpServletResponse を取得してしまい、そのままサーブレットなどの出力と同じ要領で書き出してしまおう、というものです。この場合、ページの描画終了を示すため、最後に「setPath」でパスをnullに設定するのを忘れないようにします。これで出力をすべてJava側から行わせることもできるようになります。この機能についても、興味があれば調べてみると面白いでしょう。
とりあえず、これでPage側の処理からデザインまで一通り理解できました。ごく基本的な機能を使ったものなら、Webアプリケーション開発に使えるようにはなったはずです。実際に利用してみて、それまでのStrutsなどのフレームワークとどう違うか、実感してください。それがApache Clickを理解する最適な道と言えるでしょう。

