プラグイン作って覚えたことを淡々と記録するよ(TableView編)
プラグインSDKにTableViewってコンポーネントがあったから使ってみたよ(com.intellij.ui.tableパッケージに入ってる)。曰く,
Provides a useful and easily configurable wrapper around the Swing JTable component.
なんだそうな。
そもそも,JTableの使い方自体よくわかってないので,どんなに便利になったのかは,いまいちわかってないんだけど,まあいいや。これを使う上でのポイントは,ListTableModelちゅう専用のTableModelにあるっぽい。説明が面倒臭いので,コード載っけとく。
SomeBeans:テーブルに表示したいJavaBeans(テキトーなのでいい)。
public class SomeBeans { private String firstname; private String lastname; private int age; private String email; public SomeBeans(int seed) { firstname = "aaaa:" + seed; lastname = "bbbb"; age = 99 * seed; email = "foo@bar.boo"; } : }
TestTableView:TableViewを貼っ付けたFormのコード。
public class TestTableView { private JPanel mainPanel; // TableViewをSomeBeansでパラメタ化しとく private TableView<SomeBeans> table; public TestTableView() { table.setModel(createListTableModel()); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // 何でか知らんが,getTableHeader()しないとヘッダが表示されなかった JTableHeader header = table.getTableHeader(); header.setReorderingAllowed(false); } private ListTableModel<SomeBeans> createListTableModel() { // ListTableModelはTableViewと同じクラス(SomeBeans)でパラメタ化しとく ListTableModel<SomeBeans> model = new ListTableModel<SomeBeans>( // ColumnInfoは,行の型と列の型の2つでパラメタ化する new ColumnInfo<SomeBeans, String>("First Name") { // コンストラクタ引数がヘッダ名になる // 必ず実装するのは,valueOf() public String valueOf(SomeBeans item) { // このカラムの値を返す return item.getFirstname(); } // カラム幅の初期値 // TableColumn.setPreferredWith()に相当してるっぽい public int getAdditionalWidth() { return 100; } }, : new ColumnInfo<SomeBeans, Integer>("Age") { public Integer valueOf(SomeBeans item) { return item.getAge(); } // getAdditionalWidth()と違って,getWidth()だとカラム幅は固定される // TableColumn.setMaxWidth()に相当してるっぽい public int getWidth(JTable table) { return 30; } // Comparatorを返すカラムは自動的にソート可能になる public Comparator<SomeBeans> getComparator() { return new Comparator<SomeBeans>() { public int compare(SomeBeans o1, SomeBeans o2) { return o2.getAge() - o1.getAge(); } }; } }, : ); // これが実データ。当然,同じ型(SomeBeans)でパラメタ化しとく List<SomeBeans> list = new ArrayList<SomeBeans>(); for (int i = 0; i < 10; i++) list.add(new SomeBeans(i)); // 実データをListTableModelにセットする model.setItems(list); return model; } : }
ColumnInfoの組み方次第にもよるが,素のJTable,DefaultTableModelよりは組みやすそうかも。少なくともカラムのソートの実装は簡単そうだ。じゃあ,早速Maven Repo SearchプラグインをTableView化するかと言えば,興が乗らないのでまた今度。:-P
→http://terai.xrea.jp/Swing/TableSorter.html
Java6だとソートも簡単みたいだけど,OSXがJava5なんで,IDEAプラグインはJava5でビルドが主流なのよね...。
→http://terai.xrea.jp/Swing/TableRowSorter.html
おまけ:GUIのテストするだけだったら,いちいちプラグインとして実行させる必要はなく,Formのバインドコードにこんな感じのメインルーチン書いとけばOK。
public static void main(String[] args) throws Exception { JFrame frame = new JFrame(); UIManager.setLookAndFeel(new WindowsLookAndFeel()); SwingUtilities.updateComponentTreeUI(frame); frame.setContentPane(new TestTableView().mainPanel); frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.pack(); frame.setVisible(true); }
ちなみに,先のTestTableViewを実行すると,こんな感じになる。
(追記)Maven Repo SearchをTableView化してみた。気付いた点が2つほどあるので,メモっておく。
カラム幅について:ColumnInfo.getAdditionalWidth()やgetWidth(JTable table)で決まるって言ったのは間違い(TableView.setSize()に答えが書いてあるので,詳しくはそちらを参照)。
ColumnInfo.getPreferredStringValue()もしくは,getMaxStringValue()でカラム幅の元ネタとなる文字列を返すのが本筋のようだ。
なんで,たとえば5文字分のカラム幅が欲しいのであれば,こんなコードを書くと良い。
public class SomeColumnInfo extends ColumnInfo<SomeBeans, String> { : public String getPreferredStringValue() { return "12345"; }
ヘッダクリックによるソート:TableViewにComparetorを返すColumnInfoをセットすることで,該当カラムがソート可能になる。それは,まあ便利なんだけど,なんでかソートしてもヘッダ項目の再描画がされず,ソート項目のハイライトやアローが以前のままになる(データ部分はちゃんとソートされるよ)。で,ウインドウを動かすとかカラム幅を変更するとか再描画を促すと,最新の状態になる。
しょうがないんで,TableView.onHeaderClicked(int)を上書きして,こんなことしてんだけど,ちょっと腑に落ちないよなぁ。:-(
public class SomeTableView extends TableView<SomeBeans> { : protected void onHeaderClicked(int column) { super.onHeaderClicked(column); getTableHeader().repaint(); // ヘッダを再描画 }
とは言え,JTableよりは便利なのは確かなんで,プラグインで表を使う場合はTableViewを積極的に使っていこう。