久しぶりにSwingプログラミング

久しぶりにSwingでプログラミングをしていてTableTree的なことをやりたかったので、これまた久しぶりのSwingXにあるJXTreeTableを使ってみました。
JTableなどでもそうですが、JXTreeTableではJXTreeTable本体に加えてデータを表すTreeTableNodeと、それを表示するためのTreeTableModelを用意する必要があります。JFaceでいうとモデルがTreeTableNode、コンテンツプロバイダとラベルプロバイダを組み合わせたものがTreeTableModelに相当します。
試しに作ってみたのはこんな感じ。まずはTreeTableModelです。

public class SampleTreeTableModel extends DefaultTreeTableModel {

  private static final int INDEX_NAME = 0;
  private static final int INDEX_SIZE = 1;

  @Override
  public boolean isLeaf(Object node) {
    File file = (File) ((DefaultMutableTreeTableNode) node).getUserObject();
    return file.isFile();
  }

  @Override
  public int getColumnCount() {
    return 2;
  }

  @Override
  public String getColumnName(int column) {
    switch(column){
      case INDEX_NAME: return "名前";
      case INDEX_SIZE: return "サイズ";
      default: return null;
    }
  }

  @Override
  public Object getValueAt(Object node, int column) {
    File file= (File) ((DefaultMutableTreeTableNode) node).getUserObject();

    switch(column){
      case INDEX_NAME: return file.getName();
      case INDEX_SIZE: return file.isFile() ? file.length() : "";
      default: return null;
    }
  }

}

以下のような感じで使います。

private JXTreeTable buildTreeTable(){
  SampleTreeTableModel model = new SampleTreeTableModel();
  JXTreeTable treeTable = new JXTreeTable(model);

  model.setRoot(wrapToTreeTableNode(new File("...")));

  return treeTable;
}

private DefaultMutableTreeTableNode wrapToTreeTableNode(File file){
  DefaultMutableTreeTableNode node = new DefaultMutableTreeTableNode(file);
  
  for(File child: file.listFiles()){
    if(child.isFile()){
      node.add(new DefaultMutableTreeTableNode(child));
    } else {
      node.add(wrapToTreeTableNode(child));
    }
  }

  return node;
}

んで、表示はこんな感じになります。

ここでは初期化時にすべてのノードを作成していますが、TreeTableNodeもしくはTreeTableModelを作りこめば展開されたタイミングでノードを生成するような動きも実現できます。TreeTableModelを完全に自作すれば任意のオブジェクトをノードとして使うこともできそう…。
ところでSwingXって去年の11月に1.6がリリースされています。まだ生きてたんですね…。