Batch的な処理をするツールを作る時、処理したいファイルの指定や、ディレクトリの指定っというのがあると思います。そういう時、QListViewなどにファイルをD&Dして指定できたらいいなーっと思う時があります!
PySide(Qt)でのD&Dはちょーっと厄介というか、面倒くさいので、メモも兼ねてご紹介したいと思います!
クラスの骨格
まずは、QListViewを継承したクラスを用意します。
from PySide import QtCore from PySide import QtGui class ListView(QtGui.QListView): def __init__(self, *args, **kwargs): super(ListView, self).__init__(*args, **kwargs)
D&Dできるためのフラグ
デフォルトではD&Dできないので、フラグの設定を済ませます。
from PySide import QtCore from PySide import QtGui class ListView(QtGui.QListView): def __init__(self, *args, **kwargs): super(ListView, self).__init__(*args, **kwargs) self.setDragEnabled(False) self.setAcceptDrops(True) self.setDropIndicatorShown(True)
「self.setDragEnabled(False)」は、QListView内でのドラッグのON/OFFです。ファイルのリストをD&Dで並び替える機能はつけないので、ここではOFFにしました。
「self.setAcceptDrops(True)」は、QListViewにドロップを受け付けるON/OFFです。ONにすることで、ドロップを受け付けるようになります。
「self.setDropIndicatorShown(True)」は、ドロップインジケータの表示ON/OFFです。ONにすることで、ドロップした際の状態がわかりやすくなります!
dragEnterEventの実装
この関数は、D&D操作がウィジェットに来た時に実行さ、その操作を受け付けるかどうかを決めます。今回は、ファイルのD&Dですので、URLの有無で、受け付けるかどうか決めます。
from PySide import QtCore from PySide import QtGui class ListView(QtGui.QListView): def __init__(self, *args, **kwargs): super(ListView, self).__init__(*args, **kwargs) self.setDragEnabled(False) self.setAcceptDrops(True) self.setDropIndicatorShown(True) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: super(ListView, self).dragEnterEvent(event)
dragMoveEventの実装
この関数は、D&D操作を受け入れた後に継続的に実行され、その操作を受け付けるかどうかを決めます。今回は、ファイルのD&Dですので、URLの有無で、受け付けるかどうか決めます。
from PySide import QtCore from PySide import QtGui class ListView(QtGui.QListView): def __init__(self, *args, **kwargs): super(ListView, self).__init__(*args, **kwargs) self.setDragEnabled(False) self.setAcceptDrops(True) self.setDropIndicatorShown(True) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: super(ListView, self).dragEnterEvent(event) def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: super(ListView, self).dragMoveEvent(event)
dropEventの実装
この関数は、ウィジェット上でドロップイベントが発生した時に実行されます。そう!今回のメインの部分です。この関数でも、URLがあるかキチンと調べてから、アイテムの追加を行っています。
from PySide import QtCore from PySide import QtGui class ListView(QtGui.QListView): def __init__(self, *args, **kwargs): super(ListView, self).__init__(*args, **kwargs) self.setDragEnabled(False) self.setAcceptDrops(True) self.setDropIndicatorShown(True) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: super(ListView, self).dragEnterEvent(event) def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: super(ListView, self).dragMoveEvent(event) def dropEvent(self, event): if event.mimeData().hasUrls(): model = self.model() urls = event.mimeData().urls() for url in urls: filename = url.toLocalFile() print type(url) item = QtGui.QStandardItem(filename) model.appendRow(item) event.accept() else: super(ListView, self).dropEvent(event)
URLが存在する場合は、1つづつ処理をしていきます。URLの情報は、「QUrl」のインスタンスです。ここではファイルのフルパスを表示したかったので「toLocalFile()」を使って取得しています。他にもファイルの情報を取り出すメソッドがあるので、お好みで変更してください。
取り出したURLは、Viewに設定されたModelにQStandardItemのインスタンスを追加していきます。
処理が終わったら、イベントを受け入れたことを通知するために「accept()」を実行しましょう。
実行テスト
上記のListVIewを使い、QStandardItemModelなどを設定してください。その後UIにファイルをD&Dすると、冒頭のような動作になります。
ざっくり試したい場合は、以下のようなコードになるかと思います。
model = QtGui.QStandardItemModel() window = ListView() window.setWindowFlags(QtCore.Qt.Window) window.setModel(model) window.show()