2016年7月21日木曜日

JavaFX の ListView でアイコンを表示/Cell のカスタマイズ


JavaFX の ListView で String 以外を構成要素にするの拡張的な内容になりますが、
ListView の表示が toString() では収まらない、文字列以外も表示したい、という際には、ListView のリストを構成する Cell をカスタマイズすることになります。
その Cell をカスタマイズした一例として…

やりたかったことは ListView にファイル名と対応するアイコンの表示。
ポイントは ListView の Cell のカスタマイズと Icon の描画方法。

といっても、ほとんど

JavaFX file listview with icon and file name - Stack Overflow
http://stackoverflow.com/questions/28034432/javafx-file-listview-with-icon-and-file-name

のマネです。

Item というクラスがファイル名などを持っていて、ListView<Item> として ListView の要素のクラスとなっているとします。
ListView#setCellFactory() で Cell をカスタマイズする ListCell を拡張したクラス(この場合 ItemFormatCellを返すようにします。
        listView.setCellFactory(new Callback<ListView<Item>, ListCell<Item>>() {
             @Override
             public ListCell<Item> call(ListView<Item> list) {
                 return new ItemFormatCell();
             }
         });

ItemFormatCell クラスで、実際に1つのセルの表示内容をカスタマイズすることになりますが、ここで updateItem() をオーバーライドして実装するのが定番のようです。
次の例では、

  • 空行には何も表示しない(setText(), setGraphic() で null 指定)
  • 対応する Item がある場合には、アイコン(setGraphic())+ファイル名(setText())を表示する

ということをやっています。
    final class ItemFormatCell extends ListCell<Item> {
        public ItemFormatCell() {    }
   
        @Override protected void updateItem(Item item, boolean empty) {
            final boolean bUseJLabel = false;
     
            super.updateItem(item, empty);
     
            if(empty || item == null){
                 setText(null);
                 setGraphic(null);
                 return;
            }
     
            // getItemName() はファイル名を返すメソッドとして実装
            setText(item.getItemName());
            setContentDisplay(ContentDisplay.LEFT); // Graphic は Text の左に表示
            // getIcon() は対応する Icon を返すメソッドとして実装
            // Windows では FileSystemView.getFileSystemView().getSystemIcon() を利用
            Icon icon = item.getIcon();
            BufferedImage bufferedImage = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
            icon.paintIcon(null, bufferedImage.getGraphics(), 0, 0);
            // 最終的に Icon を ImageView の形で Cell に表示
            setGraphic(new ImageView(SwingFXUtils.toFXImage(bufferedImage, null)));    
        }
    }

ListView の Cell のカスタマイズについては、Cell の javadoc も参照してみて下さい。


※補足
Icon を setGraphic() に渡せるようにする手順ですが、
上記の方法とは別に

  1. Icon を swing の JLabel で表示させる
  2. その JLabel を JavaFX の SwingNode に setContent()
  3. その SwingNode を setGraphic() 
という swing の GUI部品を使った方法も試してみて、こちらの方がコード的にはシンプルだったのですが、
動作が少し遅いのと、どうしても JavaFX の Platform.exit() 時にアプリケーションが終わらない(多分、Swing のスレッドが残ってしまっていて、消し方が分からなかった)という理由で没にしました。

0 件のコメント:

コメントを投稿