[Java][Wicket]Wicketでn行m列で折り返すリストを作る
Wicket本が未だに入荷しないので一つ書く。Wicket奮闘記第二弾。困り度的には、最悪1列表示で妥協すれば良かったのでそんなに高くない。
ただのリストじゃなくて、要素が何個か横に続き、n個で折り返す……というサンプル。イメージとしては、mixiのマイミクとかマイコミュニティみたいな感じかなぁ。相変わらずバージョンは1.3なのです。
[f:id:kk_Ataka:20090316004745p:image]
こんな感じ。横に2つで折り返し。
どういう風に実現するかすごい困ったけれど、調べてみるとGridViewというコンポーネントがあったのでこれは使えそうだと。以下Javaソース。
// テーブルのcolspanに設定する数
private int column;
private List<SampleObjectModelBean> selected;
public SampleGridView() {
// 行の設定
column = 2;
// DBから何らかのリスト一覧を持ってきたという体で
final List<SampleObjectModelBean> list = GenerateBeanUtility.GenerateSampleObjectModelBean();
// 自分が取得している項目という体で
selected = new ArrayList<SampleObjectModelBean>();
selected.add(list.get(2));
selected.add(list.get(5));
// DataProvider 規則的に回すもの
IDataProvider dataProvider = new IDataProvider() {
private static final long serialVersionUID = -9120134891423038532L;
public Iterator<SampleObjectModelBean> iterator(int first, int count) {
return list.iterator();
}
public int size() {
return list.size();
}
public IModel model(Object object) {
return new Model((Serializable)object);
}
public void detach() {
}
};
final Form form = new Form("form");
this.add(form);
final CheckGroup checkGroup = new CheckGroup("checkGroup", new PropertyModel(this, "selected"));
form.add(checkGroup);
final WebMarkupContainer colspanWMC = new WebMarkupContainer("colspanWMC");
// テーブルのcolspan属性を動的にしてやる
colspanWMC.add(new SimpleAttributeModifier("colspan", String.valueOf(column)));
checkGroup.add(colspanWMC);
final GridView gridView = new GridView("rows", dataProvider) {
private static final long serialVersionUID = 3658408852637870671L;
// ListViewと同様のpopulateItem
@Override
protected void populateItem(Item item) {
SampleObjectModelBean bean = (SampleObjectModelBean)item.getModelObject();
item.add(new Check("check", item.getModel()));
item.add(new Label("value", bean.getName()));
}
// 空だった場合
@Override
protected void populateEmptyItem(Item item) {
item.add(new Check("check").setVisible(false));
item.add(new Label("value", "Empty"));
}
};
// カラムの数をセット
gridView.setColumns(column);
checkGroup.add(gridView);
final WebMarkupContainer listWMC = new WebMarkupContainer("listWMC");
listWMC.setOutputMarkupId(true);
this.add(listWMC);
// 選択したものを表示
ListView listView = new ListView("resultList", selected) {
private static final long serialVersionUID = 2797947925339607450L;
@Override
protected void populateItem(ListItem listItem) {
SampleObjectModelBean bean = (SampleObjectModelBean)listItem.getModelObject();
listItem.add(new Label("name", bean.getName()));
listItem.add(new Label("outline", bean.getOutline()));
}
};
listWMC.add(listView);
// 選択決定ボタン
AjaxButton button = new AjaxButton("button") {
private static final long serialVersionUID = 7635585733674755967L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form form) {
target.addComponent(listWMC);
}
};
form.add(button);
// 列を増やしてみる
AjaxLink incLink = new AjaxLink("incLink") {
private static final long serialVersionUID = 7734634038402851693L;
@Override
public void onClick(AjaxRequestTarget target) {
if (column < list.size()) {
column++;
}
colspanWMC.add(new SimpleAttributeModifier("colspan", String.valueOf(column)));
gridView.setColumns(column);
target.addComponent(form);
}
};
this.add(incLink);
// 列を減らしてみる
AjaxLink decLink = new AjaxLink("decLink") {
private static final long serialVersionUID = -3611671121498659140L;
@Override
public void onClick(AjaxRequestTarget target) {
if (column > 1) {
column--;
}
colspanWMC.add(new SimpleAttributeModifier("colspan", String.valueOf(column)));
gridView.setColumns(column);
target.addComponent(form);
}
};
this.add(decLink);
}
public List<SampleObjectModelBean> getSelected() {
return selected;
}
public void setSelected(List<SampleObjectModelBean> selected) {
this.selected = selected;
}
で、html。
<h1>GridViewを用いてテーブルをn列で折り返した選択フォーム(例:mixiのコミュニティ一覧みたいな)</h1>
<form wicket:id="form">
<input type="submit" wicket:id="button" />
<table cellspacing="0" cellpadding="2" border="1">
<span wicket:id="checkGroup">
<tr>
<th wicket:id="colspanWMC">なんとか一覧</th>
</tr>
<tr wicket:id="rows">
<td wicket:id="cols">
<input type="checkbox" wicket:id="check" />
<span wicket:id="value" />
</td>
</tr>
</span>
</table>
</form>
<h1>(おまけ)列を動的に変えてみる</h1>
<ul>
<li><a href="#" wicket:id="decLink">列減らす</a></li>
<li><a href="#" wicket:id="incLink">列増やす</a></li>
</ul>
<h1>選択したもの</h1>
<span wicket:id="listWMC">
<dl wicket:id="resultList">
<dt wicket:id="name"></dt>
<dd class="recital" wicket:id="outline"></dd>
</dl>
</span>
列を変えるボタンのソースとかはおいといて……、とりあえず
[f:id:kk_Ataka:20090316004745p:image]
の画面は実現できます。普通のListViewでコレクションを表示していくのと違う点は、
- 1. ListViewがGridView
- -表示するオブジェクトがModel(かList)ではなく、DataProvider
- populateEmptyItemの処理
- カラム数をセット
- wicket:idでちょこっと
このくらいです。
まず、ListViewがGridView。これはそういうコンポーネントがあるのかぁ的な感じでゴリゴリ変えていきます。
次に、GridViewに変えた事で引数にModelとかListが使えなくなりました……。代わりにDataProviderというものを突っ込んでやらないといけないらしい……。DataProviderはこんな感じ。listはDBから取得してきたという体で生成した選択項目全部のリストです。
IDataProvider dataProvider = new IDataProvider() {
private static final long serialVersionUID = -9120134891423038532L;
public Iterator<SampleObjectModelBean> iterator(int first, int count) {
return list.iterator();
}
public int size() {
return list.size();
}
public IModel model(Object object) {
return new Model((Serializable)object);
}
public void detach() {
}
};
とりあえずこんな感じで動きました。iteratorメソッドには引数が二つあったりするんですが、次回は使います。今回は使わなくても動いた……。[1]
これで、回すのに必要なものは揃ったので、populateItemをオーバライドしますが、populateItemとは別にpopulateEmptyItemというメソッドもオーバライドしないといけません。理由は後述。
次にテーブルを何列で折り返したいかをsetColumnsメソッドで指定します。今回は頭の方で2に設定しているので、n行2列のテーブルに出来るはずです。しかし、列を指定した事でテーブルに空白が出来る可能性が起こってしまいます。2列のテーブルなら、リストが奇数の場合最後の行が1列しか埋まりません;
ここでpopulateEmptyItemの出番です。テーブルがまだ全部埋まっていないのに要素が終わってしまった場合、これが呼ばれます。
[f:id:kk_Ataka:20090316004745p:image]
Emptyと表示しているところがpopulateEmptyItemが呼ばれている箇所です。めでたしめでたし。
最後にwicket:id。
final GridView gridView = new GridView("rows", dataProvider) {
private static final long serialVersionUID = 3658408852637870671L;
// ListViewと同様のpopulateItem
@Override
protected void populateItem(Item item) {
SampleObjectModelBean bean = (SampleObjectModelBean)item.getModelObject();
item.add(new Check("check", item.getModel()));
item.add(new Label("value", bean.getName()));
以下略
JavaでWicket:idを生成しているのは、
- - GridViewのrows - -populateItem内のCheckのcheck - populateItem内のLabelのvalue
の三つなんですが、この三つをListView的な感じでバインドしていっても、
WicketMessage: Unable to find component with id 'check' in [MarkupContainer [Component id = 1, page = sampleWicket.view.gridView.SampleGridView, path = 2:form:checkGroup:rows:1.Item, isVisible = true, isVersioned = false]]. This means that you declared wicket:id=check in your markup, but that you either did not add the component to your page at all, or that the hierarchy does not match.
checkがない! と怒られてしまいます。
なんで>< と調べてみると、どうも、
<tr wicket:id="rows">
<td wicket:id="cols">
<input type="checkbox" wicket:id="check" />
<span wicket:id="value" />
</td>
</tr>
rows(=GridView)の下にcolsというidを振らないといけないらしい。GridViewクラスの中にも
Item rowItem = newRowItem(newChildId(), row);
RepeatingView rowView = new RepeatingView("cols");
rowItem.add(rowView);
add(rowItem);
こんな記述があって、どうもcolsを振っているらしい! 振れば動く!
最後はらしいらしいが続いてますが、一応これでmixiのマイピクみたいなテーブルも作れそうです。
この記事を書くに当たって、[http://hamachan.info/excel/gyoretu.html:title]で行と列のわかりやすい覚え方を知りました。
行と列わからないんです>< でもこれで忘れない!
cheat
某研究室のcheatです
なんかエラーググってたらみつけますた
1247234728
ikura
スタイルシートつかって要素のサイズを決めて、float:leftで設置していくのでは駄目なんでしょうか??
1320027787
kk_Ataka
2年前の事なので定かではないですが、この時はWicketでなんとかできないかと考えた末の方法だったのだと思います!
1321447309
[1] 不都合が起こるパターンもあるのだろうか?