JRuby+swingでファイルのドラッグ・アンド・ドロップを試す

Windowsとかからファイルをドラッグ&ドロップできるようにします。
swingの"TransferHandler"を使うと簡単に実現できるようです。
メモします。



  ↓ドラッグ&ドロップ


ソースコード

# coding: cp932
require 'java'

JFrame = javax.swing.JFrame
JLabel = javax.swing.JLabel
TransferHandler = javax.swing.TransferHandler
DataFlavor = java.awt.datatransfer.DataFlavor

class FileDropHandler < TransferHandler

  def initialize(model)
    super()
    @model = model
  end

  #ファイル(リスト)のドロップ許可を与える
  def canImport(support)
    unless support.is_drop
      return false
    end
    support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
  end

  #ドロップされたアイテムに対して処理を与える
  def importData(support)
    begin
      if support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
        filelist = support.transferable.get_transfer_data(DataFlavor.javaFileListFlavor)
        # puts filelist.to_a.each {|file| puts file}
        @model.text = filelist.to_s #参照先(ラベル)にファイル一覧を渡す
      end
    rescue => e
      puts e.message
      false
    end
    true
  end
end

frame = JFrame.new "File Drag & Drop"
frame.default_close_operation = JFrame::EXIT_ON_CLOSE

label = JLabel.new
label.text = "ここにファイルをドラッグ&ドロップ"
frame.content_pane.add(label)

label.transfer_handler = FileDropHandler.new(label)

frame.pack
frame.set_bounds(10,10,400,60)
frame.visible = true

canImportでDnDの許可を与えます。ここをtrueを返すようにするとドラッグしたときマウスのアイコンが禁止マークではなくなります。
importDataはドロップしたデータを受け取ります。受け取ったデータ(ファイル一覧)をlabel.textに表示させています。
immportData内でドラッグしたことを判断する条件式が足りていないかもしれませんが、今回は細かいことは省略します。

get_transfer_data(DataFlavor.javaFileListFlavor)で取得したfilelistは、"java.util.ArrayList"です。ちょっとどう扱えばよいか考えてしまいます。でも難しく考えずにRubyの配列のようにeachブロックを使って処理すればよいです。
あと、filelist.to_aを使うとjava.util.ArrayListからRubyのArrayクラスに変換できます。


クラスの継承で、initialize内"super()"のカッコ"()"は必要です。
jruby-1.7.0.preview1でこのスクリプトを実行すると
warning: instance vars on non-persistent Java type FileTransferHandler (http://wiki.jruby.org/Persistence)
とワーニングが表示されますが、とりあえず無視します。おそらくpreview2とかで解決されているはずなので。

感想

ドラッグ&ドロップを調査はじめのころAWTのdndを見つけてテストしてました。ですが、僕には理解できませんでした。それでもう少し調べたらswingにもDnDをサポートしているという記述を発見しもっと簡単に実装できることを知りました。
確かにTransferHandlerならcanImportとimportDataだけわかれば実装できるので簡単だと思いました。

swingアプリを作るとき苦労するのはレイアウトだと思います。レイアウトマネージャもよくわからないのがたくさんあるのでどれを使ったらよいかわかりません。ちょっとしたアプリなら今回みたいなドラッグ&ドロップできるシンプルなUIをめざすべきかなと思っていますw
もう少し、UIを手設計で簡単になると良いのですが。。。