これは、オンデマンドでロードを実行するディレクトリエクスプローラーのラインに沿った、より完全なzkmvvmツリーの例です。
https://github.com/simbo1905/zktreemvvm
「gitclone」でチェックアウトしてから、次のコマンドで実行してください。
mvn -Djetty.port=8080 package jetty:run
コードは、指定されたポートで独自のJettyサーバーを起動します。
これは、モックや単体テストが難しい生のjava.io.Fileを使用するのではなく、ファイルシステムの抽象化としてApacheCommonsVFSを使用します。デフォルトでは、コードは、通常のファイルやフォルダーであるかのようにcommons-vfs2-2.0.jarの内部を参照するためのZK画面を表示します。ViewModelクラスのFILE_SYSTEM_URIuriを「file:/// some / path /」のようなファイルの場所に変更するだけで、通常のファイルシステムを表示できます。
zulページにはツリーが含まれており、そのモデルをvm.treeModelにバインドし、selectedItemイベントをvm.pickedItemメソッドにバインドします。
<?xml version="1.0" encoding="UTF-8"?>
<zk>
<window apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('org.github.simbo1905.zktreemvvm.CommonsVfs220ViewModel')">
<tree model="@load(vm.treeModel)" selectedItem="@bind(vm.pickedItem)">
<treecols>
<treecol label="name" />
<treecol label="index" />
</treecols>
<template name="model" var="node" status="s">
<treeitem>
<treerow>
<treecell label="@bind(node) @converter('org.github.simbo1905.zktreemvvm.NodeConverter')" />
<treecell label="@bind(s.index)" />
</treerow>
</treeitem>
</template>
</tree>
</window>
</zk>
@Converterは、ツリーモデルに保持されているFileObjectデータのわかりやすいレンダリングを行います。
実際のViewModelはあまり機能しませんが、selectedItemイベントハンドラー(ログのみを実行します)を保持し、TreeModelへのアクセスを提供します。
public TreeModel<FileObject> getTreeModel() {
if (treeModel == null) {
try {
FileSystemManager fsManager = VFS.getManager();
FileObject fo = fsManager.resolveFile( FILE_SYSTEM_URI );
treeModel = new CachingVfsTreeModel(fo);
} catch (FileSystemException e) {
throw new IllegalArgumentException(String.format("Could not open VFS uri: %s",FILE_SYSTEM_URI),e);
}
}
return treeModel;
}
主な作業は、AbstractTreeModelを拡張し、必須メソッドを定義するVfsTreeModelクラスです。
public class VfsTreeModel extends AbstractTreeModel<FileObject> {
// __ snip __
@Override
public FileObject getChild(FileObject parent, int index) {
log.info(String.format("%s getChild on %s with index %s", level(parent), innerName(parent), index));
FileObject child = null;
try {
FileObject[] children = parent.getChildren();
child = children[index];
} catch (FileSystemException e) {
throw new IllegalArgumentException(e);
}
return child;
}
@Override
public int getChildCount(FileObject node) {
int childCount = 0;
try {
FileType type = node.getType();
if( type == FileType.FOLDER ){
childCount = node.getChildren().length;
}
} catch (FileSystemException e) {
throw new IllegalArgumentException(e);
}
log.info(String.format("%s getChildCount on %s returning %s",level(node),innerName(node), childCount));
return childCount;
}
@Override
public boolean isLeaf(FileObject node) {
boolean isLeaf = false;
try {
FileType type = node.getType();
isLeaf = (type == FileType.FILE );
} catch (FileSystemException e) {
throw new IllegalArgumentException(e);
}
log.info(String.format("%s isLeaf on %s returning %s", level(node),innerName(node), isLeaf));
return isLeaf;
}
このバグトラッカーには、フレームワークがその情報を把握するために他の多くの呼び出しを行わないようにgetPathをオーバーライドすることが推奨されていました。
http://tracker.zkoss.org/browse/ZK-1278
そのメソッドは、ルートへのウォークとして実装されます。
@Override
public int[] getPath(FileObject node) {
List<Integer> paths = new ArrayList<Integer>();
try {
FileObject parent = node.getParent();
while (parent != null && parent.getType().equals(FileType.FOLDER)) {
FileObject[] children = parent.getChildren();
for( int index = 0; index < children.length; index++){
FileObject c = children[index];
if( node.equals(c)){
paths.add(index);
break;
}
}
node = parent;
parent = node.getParent();
}
} catch (FileSystemException e) {
throw new IllegalArgumentException(e);
}
int[] p = new int[paths.size()];
for( int index = 0; index < paths.size(); index++){
p[index] = paths.get(p.length - 1 - index); // reverse
}
log.info(String.format("%s getPath on %s",level(node),innerName(node)));
return p;
}
次のツリーモデルのドキュメントと「巨大なデータ」のドキュメントでは、キャッシュを推奨しています。
http://books.zkoss.org/wiki/ZK_Developer%27s_Reference/MVC/Model/Tree_Model
http://books.zkoss.org/wiki/ZK%20Developer%27s%20Reference/Performance%20Tips/Listbox,%20Grid%20and%20Tree%20for%20Huge%20Data/Implement%20ListModel%20and%20TreeModel
したがって、サンプルコードでは、ViewModelはVfsViewModelのキャッシングサブクラスを作成します。ページを更新すると、新しいオブジェクトが作成され、キャッシュがガベージコレクションされます。これは、この例ではおそらく十分です。