目次
この章はXULコンポーネントセットを説明しています。他の実装とは異なり、ZKのXULコンポーネントはインターネット上で効率的に使われるため、最適化されています。一部のコンポーネントはXUL標準とは少し異なるかもしれません。便宜上、それらをZULコンポーネントと呼びます。
ラベルはテキストを表します。
<window border="normal">Hello World </window>
ラベルに属性を指定する場合、以下のようにはっきりと<label> を指定しなければいけません。
<window border="normal"><label style="color: red" value="Hello World"/> </window>
【ヒント】:ZUMLはXMLであって、HTMLではありませので、 
;を受け取りません。しかしながら、代わりに 
;を使うことができます。
p
re、hyphen、maxlengthプロパティを使い、ラベルの外見を変えることができます。例えば、preにtrue
を指定する場合、空白、タブなどのすべてのホワイトスペースは省略されません。
|
|
|
|
|
|---|---|---|---|
|
|
|
|
指定した |
|
|
|
|
単語の長さが |
|
|
|
|
|
|
|
|
|
|
<window border="normal" width="200px"> <vbox> <label value="Hello, World!" maxlength="5"/> <label value="Hello, WorldChampion!" hyphen="true" maxlength="10"/> <label pre="true"><attribute name="value">aa bb c dd ef</attribute> </label> </vbox> </window>
multilineプロパティはpreプロパティに似ています。違う点はmultiline は各々の行初めにある新しい線と空白のみを保存します。
2種類のボタンがあります。button とtoolbarbuttonです。外見は違いますが、働きは同じです。button コンポーネントはHTML BUTTONタグを使用します。一方、toolbarbuttonコンポーネントはHTML Aのタグを使います。
labelとimageプロパティでラベルとイメージをボタンに指定することができます。二つとも指定された場合、dir
プロパティでどれを一番前に表示するかを指定できます。orientプロパティはlayoutを横方向、縦方向、どちらかに指定できます。
<button label="Left" image="/img/folder.gif" width="125px"/><button label="Right" image="/img/folder.gif" dir="reverse" width="125px"/> <button label="Above" image="/img/folder.gif" orient="vertical" width="125px"/> <button label="Below" image="/img/folder.gif" orient="vertical" dir="reverse" width="125px"/>
URLによってイメージを指定することに加えて、setImageContentメソッドを使うことで、動的に生成させたイメージをボタンに指定することができます。詳しくは以下のセクションをご覧ください。
【ヒント】: setImageContentメソッドはimageプロパティを持つすべてのコンポーネントで提供されています。つまり、setImageContentはイメージを動的に生成するときに使われます。一方、ImageはURLが認識できるイメージに使われます。
buttonとtoolbarbuttonに動作を加える方法は二つあります。初めはonClickイベントにリスナを指定します。二つ目はURLをhrefプロパティに指定します。両方共に指定された場合、hrefプロパティのほうが、優先順位が高いです。つまり、onClickイベントは送信されません。
<button onClick="do_something_in_Java()"/> <button href="/another_page.zul"/>
イベントを処理している時、現デスクトップの処理を停止するかどうかを操作します。そして、sendRedirectメソッドを使って他のページに変えます。つまり、以下二つのボタンの働きは(ユーザーからみれば) 同じです。
<button onClick="Executions.sendRedirect("another.zul")"/> <button href="another.zul"/>
onClickイベントはサーバーへ送信され処理されるので、sendRedirectを呼ぶ前にロジックを加えることができます。たとえば、sendRedirectはある条件が満たされた場合のみ、他のページに変えるといったことが可能です。
一方で、hrefプロパティは完全にクライアント側で処理されます。ユーザーがボタンをクリックするなどクライアント側の操作はアプリケーションには通知されせん。
ラジオボタンはオン・オフできるコンポーネントです。ラジオボタンはradiogroupと呼ばれるグループ中でグループ化されます。同じグループの中では一つだけのラジオボタンが選択できます。
<radiogroup onCheck="alert(self.selectedItem.label)"> <radio label="Apple"/> <radio label="Orange"/> <radio label="Banana"/> </radiogroup>
以下に示したように、radiogroupとradioは組み合わせることができ、レイアウトは自分のしたいようにできます。
<radiogroup onCheck="alert(self.selectedItem.label)"> <radio label="Apple"/> <radio label="Orange"/> <radio label="Banana"/> </radiogroup>
ラジオボタンは一番関係の近いancestorradiogroupに属しています。以下のように一つのラジオグループを他のものを入れ子することができます。視覚的には重ねているように見えるかもしれませんが、どのグループも独立に操作できます。
<radiogroup> <grid> <rows> <row><radio label="Apple" selected="true"/> Fruit, music or computer</row> <row><radio label="Orange"/><textbox/></row> <row><radio label="Banana"/><datebox/></row> </rows></grid> </radiogroup>
image コンポーネントはブラウザ上でイメージを表示します。imageコンポーネントにイメージを指定する方法は二つあります。一つ目はsrcプロパティを使って、イメージが位置されているURIを指定します。この方法はHTMLがサポートしているものに似ています。静的なイメージを表示する場合、URLによって認識できるイメージを表示する場合、このアプローチは便利です。
<image src="/some/my.jpg"/>
URIを受け取っている他のプロパティを使用しているように、地域依存イメージを“*”で表示します。例えば、異なった地域に異なったイメージを指定するなら、以下のように使用できます。
<image src="/my*.png"
そのため、ユーザーの一人がデフォルト地域がde_DEに設定されたブラウザで訪れることを想定します。ZKは/my_de_DE.pngと呼ばれるイメージファイルを位置しようと試みます。見つからない場合、/my_de.pngを探し、最後は/my.pngを試します。
より詳しくは、国際化の章のブラウザとロケール依存URIを参照してください。
二つ目は、setContentメソッドを使用して、イメージコンテンツをimageコンポーネントに直接指定できます。指定したと同時に、ブラウザで表示されているイメージが自動的に更新されます。このアプローチはイメージが動的に生成されるときに使うと便利です。
例えば、以下のようにユーザーに指定された位置にマップを生成させます。
Location: <textbox onChange="updateMap(self.value)"/>
Map: <image id="image"/>
<zscript>
void updateMap(String location) {
if (location.length() > 0)
image.setContent(new MapImage(location));
}
</zscript>
上の例の中のMapImageは指定された位置を計算し、マップで表示するビジネスロジックと仮定します。
イメージコンポーネントはorg.zkoss.image.Imageインターフェースの中のコンテンツのみを受け取ります。ツールによって生成させたイメージがこのフォーマットでない場合、org.zkoss.image.AImageクラスを使用して、バイナリデータ配列、又はファイル、又は入力列を包みImageインターフェースに入れましょう。
従来のウェブアプリケーション中で動的に発生したイメージを一時キャッシュすることは難しいです。imageコンポーネントを使えば心配する必要はありません。一度イメージコンテンツが指定されると、それはimageコンポーネントに属し、imageコンポーネントを使わなくなった後、メモリは自動的に開放されます。
【ヒント】:イメージや、オーディオ以外のPDFといったコンテンツを表示する場合、iframeコンポーネントを使用できます。
imagemapコンポーネントは特別なイメージです。i
mageコンポーネントが受け取るすべてのプロパティを受け取ります。しかし、imageとは異なっていて、ユーザーがイメージ上でクリックをしたら、onClickイベントとマウス位置の座標は両方サーバーに送り返されます。対照的に、imageの場合はonClickイベントは座標を含まないで送信されます。
マウス位置座標は左上の隅を(0,0)として、画面のピクセルを数えます。org.zkoss.zk.ui.event.MouseEventのインスタンスとして保存されます。一度、アプリケーションがonClickイベントを受け取ると、getX
と
getYメソッドでマウスの位置座標を調べます。
例えば、もしユーザーが左上から208ピクセル右、205ピクセル下という点をクリックしたら、以下の文からイメージが表示されます。
<imagemap src="/img/sun.jpg" onClick="alert(event.x + ", " +event.y)"/>

アプリケーションは大抵座標を使用して、ユーザーがクリックした場所を決めます。そして、それにしたがってレスポンスをします。
アプリケーション自体が座標を処理する代わりに、開発者がimagemapコンポーネントの子要素としてareaコンポーネントを加えることができます。
<imagemap src="/img/sun.jpg" onClick="alert(event.area)"> <area id="First" coords="0, 0, 100, 100"/> <area id="Second" shape="circle" coords="200, 200, 100"/> </imagemap>
次に、imagemapコンポーネントはロジック名へマウスの位置座標を翻訳します。:ユーザーがクリックしたエリアの識別子。例えば、ユーザーは(150,150)でクリックしたら、以下のように結果を得ます。

エリアコンポーネントは3タイプの形をサポートしています:circle・ polygon ・ rectangle。マウスの座標は左上を(0,0)として、スクリーンのピクセルを数えたものです。
|
形 |
コーディネイト / 説明 |
|---|---|
|
|
ピクセルの中で中心を |
|
|
|
|
|
初めの座標のペアは四角形の角の一つで、他のペアは対角にある反対の角です。四角形は四つの辺の多角形を指定する方法を単純にしたものです。 |
一つのareaコンポーネント中の座標が他をオーバーラップする場合、初めに設定されたものが優先されます。
audioコンポーネントはブラウザでオーディオを流します。imageのように、srcプロパティを使用し、オーディオリソースのURLを指定します。又は、setContentメソッド使用し、動的に生成したオーディオを指定します。
ブラウザとオーディオのプラグインがそれらの機能により、開発者はplay、stop、pauseメソッドで、オーディオの動作を操作します。現在はメディアプレーヤーが付いているインターネットエクスプローラーがそのような操作を可能にしています。

入力制御のセットはXULコンポーネントセット中でサポートされています。:textbox、 intbox、 decimalbox、 doublebox、 datebox、combobox、bandbox。それらによって、ユーザーは異なったタイプのデータを入力できます。
<zk> <textbox/> <datebox/> </zk>
【ヒント】:comboboxとbandboxは特別な入力ボックスです。その二つはここに書いたプロパティを共有しています。後に出てくるc
omboboxesとb
andboxesセクション中でそれら独特な特徴が議論されます。
textboxコンポーネントのtypeプロパティをpasswordに指定することで、ユーザーが何を入力したかは表示されません。
Username: <textbox/> Password: <textbox type="password"/>
フォーマットフィールドによって、入力制御のフォーマットを選択できます。デフォルトはn
ullです。databoxでは、デフォルトはyyyy/mm/ddです。intboxとdecimalでは、デフォルトは何も指定しないです。
<datebox format="MM/dd/yyyy"/> <decimalbox format="#,##0.##"/>
他のプロパティのように、以下に書いてあるように、動的にフォーマットを変えることができます。
<datebox id="db"/><button label="set MM-dd-yyyy" onClick="db.setFormat("MM-dd-yyyy")"/>
マウスを使わずに入力:datebox
Alt+DOWNはカレンダーをポップアップさせます。
LEFT, RIGHT, UP, DOWNでカレンダーから選択された日を変えます。
ENTERで選択された日を有効にします。(dateboxにコピーすることによって)
Alt+UP またはESCは選択をあきらめ、カレンダーを閉じます。
constraintプロパティの使用によって、入力制御が受け取る値を規制します。Positive、negative、no zero、no empty、no future、no past、no today、regular expressionを組み合わせて使用することができます。初めの三つの規制はintboxとdecimalboxだけに適用できます。no future、no past、no todayの規制はdateboxにのみ適用できます。no emptyの規制はどのタイプのコンポーネントにも適用できます。regular expressionsの規制はtextbox、combobox、bandboxのようなストリングを入力するコンポーネントにのみ適用できます。
二つ以上の規制を指定するために、コンマ(,)を使って以下のように分けます。
<intbox constraint="no negative,no zero"/>
regular expressionを指定する時に、/を使って以下のようにregular expressionを閉じます。
<textbox constraint="/.+@.+\.[a-z]+/"/>
メモ:
上のステートメントはXMLなので、\\でバックスラッシュを表現しないでください。一方で、Javaで書いているなら、バックスラッシュを\\で表現しなければなりません。
new Textbox().setContraint("/.+@.+\\.[a-z]+/");
カンマで分けることで、別の規制を持つregular expressionと混在に使うことができます。
デフォルトの代わりに、アプリケーション依存のメッセージを表示する場合、規制の後ろにコロンを使って、失敗したときに表示したいメッセージを加えます。
<textbox constraint="/.+@.+\.[a-z]+/: e-mail address only"/> <datebox constraint="no empty, no future: now or never"/>
メモ:
エラーメッセージを指定する場合は最後の要素で指定しコロンで始めます。
多言語をサポートするのに、国際化の章で説明されている l functionを使用します。
<textbox constraint="/.+@.+\.[a-z]+/: ${c:l('err.email.required')}"/>
より複雑な規制をするなら、org.zkoss.zul.Constraintインターフェースを実装するオブジェクトを指定します。
<window title="Custom Constraint">
<zscript><![CDATA[
Constraint ctt = new Constraint() {
public void validate(Component comp, Object value) throws WrongValueException {
if (value =e= null || ((Integer)value).intValue() < 100)
throw new WrongValueException(comp, "At least 100 must be specified");
}
}
]]></zscript>
<intbox constraint="${ctt}"/>
</window>
Javaクラスに規制を実装することができます。例えば、my.EmailValidatorの場合は:
<?taglib uri="/WEB-INF/tld/web/core.dsp.tld" prefix="c"?>
<textbox constraint="${c:new('my.EmailValidator')}"/>
上の例ではorg.zkoss.ui.WrongValueExceptionを使用して、エラーを表します。説明したように、エラーを発生させるコンポーネントを初めの引数に指定しなければなりません。そして、二つ目の引数にエラーメッセージを指定します。
どんなときでも、例えばonChangeイベントが以下のように受け取られたときに、この例外を使用することができます。
<textbox><attribute name="onChange"> if (!self.value.equals("good")) { self.value = "try again"; throw new WrongValueException(self, "Not a good answer!"); } </attribute> </textbox>
前の例中で示されたデフォルトのエラーボックスの代わりに、規制を伴ったorg.zkoss.zul.CustomConstraintインターフェースを実装することでカスタムの外見を提供することができます。CustomConstraintインターフェースはshowCustomErrorと呼ばれるメソッドをもち、例外が発生したとき、又はバリデーションが失敗したときに呼び出されます。以下は例です。
<window title="Custom Constraint" border="normal">
<zscript><![CDATA[
class MyConst implements Constraint, CustomConstraint {
//Constraint//
public void validate(Component comp, Object value) {
if (value == null || ((Integer)value).intValue() < 100)
throw new WrongValueException(comp, "At least 100 must be specified");
}
//CustomConstraint//
public void showCustomError(Component comp, WrongValueException ex) {
errmsg.setValue(ex != null ? ex.getMessage(): "");
}
}
Constraint ctt = new MyConst();
]]></zscript>
<hbox>
Enter a number at least 100:
<intbox constraint="${ctt}"/>
<label id="errmsg"/>
</hbox>
</window>

応答はクライアントでより多く規制を承認(validate)することで改善できます。このためには、Constraint でorg.zkoss.zul.ClientConstraint インターフェースを実装しなければなりません。クライアントですべてのバリデーションが行われると、isClientCompleteメソッドにtrueを返します。サーバー側へ送信し、バリデーションを行う必要がなくなります。
Validate_erroboxと呼ばれる要素を使用すれば、クライアントでJavaScriptコードだけで外見をカスタマイズすることができます。例えば、
<script type="text/javascript"><![CDATA[
//Running at the browser
window.Validate_errorbox = function (id, boxid, msg) {
var html = '<div style="display:none;position:absolute" id="'
+boxid+'">'+zk.encodeXML(msg, true)+'</div>';
document.body.insertAdjacentHTML("afterbegin", html);
return $e(boxid); }
]]></script>
【メモ】:
zscriptはサーバーで実行されているコードを示します。一方、scriptはブラウザで実行されているスクリプトコードを表します。
【メモ】:CustomConstraintが実装されているなら、すべての承認がサーバーで行われるためClientConstraintは無視されます。つまり、ClientConstraintを使用して、応答を改善する場合、Validate_erroboxを上書きすることがエラーメッセージの表示を変更する唯一の方法です。
コンテンツがユーザによって変更された場合、入力制御はonChangeイベントでアプリケーションに通知します。
onChangeのイベントリスナが呼び出された時、変数は設定されます。その時に不合理的な値を拒否するのは遅すぎます。さもなければ、適切な値を再設定しなければなりません。より良い方法として、Custom Constraintsセクションで説明しているように、規制を使用することをお勧めします。
ユーザーがコンテンツを変更している最中にしても、入力制御はonChangingイベントでアプリケーションを通知します。
onChangingリスナが呼び出されたとき、値はまだ設定されていません。つまり、valueプロパティは古いままです。ユーザーが入力したものを取得するために、以下のようにイベントのvalueプロパティを参照しなければなりません。
<grid> <rows> <row>The onChanging textbox: <textbox onChanging="copy.value = event.value"/></row> <row>Instant copy: <textbox id="copy" readonly="true"/></row> </rows> </grid>
ユーザーがまだ変更を終えていないので、onChangingイベントリスナの中で不合理的な変数を拒否したくても早すぎてできません。より良い方法として、Custom Constraintsセクション中に書かれているように規制を使用することをお勧めします。

カレンダーは「フラット」カレンダーを表示し、ユーザーは日にちを選択することができます。
<hbox> <calendar id="cal" onChange="in.value = cal.value"/> <datebox id="in" onChange="cal.value = in.value"/> </hbox>
入力制御のように、カレンダーはvalueプロパティを提供しています。開発者は選択した日にちを設定したり、取得したりすることができます。さらに、必要ならば、開発者はonChangeイベントントを監視し、直ちに処理することができます。
ユーザーはスライダーをスクロールすることで値を指定できます。
<slider id="slider" onScroll="Audio.setVolume(slider.curpos)"/>![]()
スライダーは0から100までの値を受け取ります。Maxposプロパティを変更すれば制限された最大値を変更することができます。
タイマーは特定の期間、時間にonTimerイベントをサーバーに送信する参照不可(invisible)のコンポーネントです。 start、stopメソッドによりタイマーを制御できます。
<window title="Timer demo" border="normal"><label id="now"/> <timer id="timer" delay="1000" repeats="true" onTimer="now.setValue(new Date().toString())"/> <separator bar="true"/> <button label="Stops timer" onClick="timer.stop()"/> <button label="Starts timer" onClick="timer.start()"/> </window>
ページングコンポーネントは長いコンテンツを多数のページに分けます。例えば、100の項目があるとして、一度に20項目表示するとしたら、以下のようにページングコンポーネントを使用します。
<paging totalSize="100" pageSize="20"/>![]()
ユーザーがhyperlinksをクリックした時、onPagingイベントとorg.zkoss.zul.event.PagingEvent のインスタンスはページングコンポーネントに送信されます。100項目のうちのどの項目を見せるかを決めるために、リスナをページングコンポーネントに付加します。
<paging id="paging"/>
<zscript>
List result = new SearchEngine().find("ZK");
//assume SearchEngine.find() will return a list of items.
paging.setTotalSize(result.size());
paging.addEventListener("onPaging", new EventListener() {
public void onEvent(Event event) {
int pgno = event.getPaginal().getActivePage();
int ofs = pgno * event.getPaginal().getPageSize();
new Viewer().redraw(result, ofs, ofs + event.getPaginal().getPageSize() - 1);
//assume redraw(List result, int b, int e) will display
//from the b-th item to the e-th item
}
});
</zscript>
