Wicketで画面項目表示の分岐と反復
はじめに
先日(といってもずいぶん前ですが)に、後輩とこんな会話がありました。
私 :Wicketもっとメジャーにならないかな。
Web上に日本語の情報が増えれば安心感が出るかと思って、たびたびblogのネタにしてるのだけど。
後輩:えっ。id:sekomのblogがWicketの裾野を広げる役に立つと本当に思っているのですか?
Wicketに対するネガティブな話題が多いと思うのですが……。
私 :……たしかに。
しかし、ポジティブかつキャッチーなネタは思いつかなかったので、代わりに「Wicket始めたばかりの時、これが疑問だったなぁ……」というトピックの一部を今回は記録します。
ちょっとは、Wicketの利用者の裾野を広げる役に立つ、はず。
対象読者
- Wicketを使って、Hello Worldを画面に出せる人
環境
- Wicket 1.3.4
何が疑問だったか
WicketはHTMLをテンプレートにして画面を作るわけですが、そうすると以下の2点が気になるのです。
しかし、直接的な説明がなかなか見つからず、理解が進むまで疑問のままでした。
今ならば、「こう書けば、大体同じことが出来る」ということが分かるのでそれをメモします。
JSTLのc:if相当の実現方法
Wicketに存在する以下の2点の機能を使います。
- Component.setVisible()というメソッドを用いたコンポーネントの表示非表示の切替。
- WebMarkupContainerクラスという、画面には表示されないけれど、他のコンポーネントを保持することが可能なコンポーネント
以下は現在時刻の末尾に応じて、画面表示の一部を差し替えるプログラムの例です。
まずはHTML側の実装。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <body> <span wicket:id="message">絶対出るメッセージ</span><br /> <span wicket:id="evenBlock"> <span wicket:id="evenMessage">偶数のときに絶対出るメッセージ</span><br /> </span> <span wicket:id="oddBlock"> <span wicket:id="oddMessage">奇数のときに絶対出るメッセージ</span><br /> </span> </body> </html>
次にJava側の実装。
package sequenceSelectionIteration; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.link.PageLink; public class SelectionPage extends WebPage { public SelectionPage() { super(); add(new Label("message", "絶対出るメッセージ(分岐の例)")); WebMarkupContainer evenBlock = new WebMarkupContainer("evenBlock"); add(evenBlock); evenBlock.add(new Label("evenMessage","偶数のときに絶対出るメッセージ")); evenBlock.add(new PageLink("evenLink",IterationPage.class)); WebMarkupContainer oddBlock = new WebMarkupContainer("oddBlock"); add(oddBlock); oddBlock.add(new Label("oddMessage","奇数のときに絶対出るメッセージ")); oddBlock.add(new PageLink("oddLink",IterationPage.class)); //現在時間が偶数か奇数か判断して表示するブロックを切り替える。 if(System.currentTimeMillis() % 2 == 1){ evenBlock.setVisible(false); oddBlock.setVisible(true); }else{ evenBlock.setVisible(true); oddBlock.setVisible(false); } } }
実行時に出力されるHTMLの例です。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <body> <span wicket:id="message">絶対出るメッセージ(分岐の例)</span><br /> <span wicket:id="evenBlock"> <span wicket:id="evenMessage">偶数のときに絶対出るメッセージ</span><br /> <a href="?wicket:interface=:1:evenBlock:evenLink::ILinkListener::" wicket:id="evenLink">偶数のときに出るリンク</a><br /> </span> </body> </html>
今回のように表示、非表示を切り替えたいコンポーネントが少ないならば、無理にWebMarkupContainerクラスを使わなくても良いのですが、例と言うことでその辺は許しておいてください。
人によっては、あってもなくてもいいspanタグ(wicket:id="evenBlock"のspanタグ)が入ってしまうのが嫌かもしれませんけど、まあ、そこはご愛敬ということで。
タグが入るのが嫌ならば、タグを消したいWebMarkupContainerクラスのインスタンスについて、setRenderBodyOnlyを引数trueで呼び出しておけば、タグを消すことも出来ます。
JSTLのc:forEach
繰り返しは、ListViewクラスを使用します。
ListViewクラスの使用感はforeachと割と似てます。
簡単な説明を書きにくいので、以下に使用例のみ載せます。
なんとなく使えてしまう程度の複雑さでも言いましょうか。
Label要素の表示を繰り返す使用例です。
まずはHTML側の実装。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <body> 繰り返しの例<br /> <span wicket:id="listView"> <span wicket:id="message">繰り返し</span> </span> </body> </html>
次にJava側の実装。
ackage sequenceSelectionIteration; import java.util.ArrayList; import java.util.List; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; public class IterationPage extends WebPage { public IterationPage() { super(); List<String> list = new ArrayList<String>(); list.add("メッセージ1"); list.add("メッセージ2"); add(new ListView("listView",list){ private static final long serialVersionUID = 1L; protected void populateItem(ListItem item) { String message = (String)item.getModelObject(); item.add(new Label("message", message)); } }); } }
実行時に出力されるHTMLの例です。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <body> 繰り返しの例<br /> <span wicket:id="listView"> <span wicket:id="message">メッセージ1</span> </span><span wicket:id="listView"> <span wicket:id="message">メッセージ2</span> </span> </body> </html>
出力されたHTMLのインデントが微妙に気持ち悪いですが、繰り返せています。
おわりに
今回は自分の中で解決したときに、メモしてなかったことのメモでした。
余談ですが、id:sekomは「c:if」と「c:forEach」をなぜ気にしてたのだろう、と思われる方もいるかもしれません。
気にしていた理由は「1つの入り口と1つの出口を持つようなプログラムは、「順次・反復・分岐」の3つの基本的な論理構造によって記述できる」という構造化定理のためです。
「順次・反復・分岐」が実現できるならば、概ねどんな画面レイアウトも作れるだろう、ということで最初の頃に特に関心を持っていたのでした。