方法に対応し内部のドラッグドロップ操作を使用QListWidget?
質問
私のQt4用のPyQtのバインディング)が含まれて QListWidget
, 初期化され、このように:
class MyList(QtGui.QListWidget):
def __init__(self):
QtGui.QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
て追加する事ができますので、またドラッグ&ドロップ並べ替えます。がどのように通知リストを返し注文により、ユーザーまたの追加 dropMimeData(self, index, data, action)
法のクラスがることはありませんが呼び出されます。
解決
これに対処しなければならなかったので、それはお尻の痛みですが、ここで何をすべきかです:
ListWidget
サブクラスに eventFilter
をインストールしてから、 ChildRemoved
イベントを監視する必要があります。このイベントは移動だけでなく削除もカバーするため、リスト内でドラッグアンドドロップを使用してアイテムを再配置する場合に機能するはずです。
QtをC ++で記述していますが、ここにPython化バージョンがあります:
class MyList(QtGui.QListWidget):
def __init__(self):
QtGui.QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
self.installEventFilter(self)
def eventFilter(self, sender, event):
if (event.type() == QEvent.ChildRemoved):
self.on_order_changed()
return False # don't actually interrupt anything
def on_order_changed(self):
# do magic things with our new-found knowledge
このリストを含む他のクラスがある場合、イベントフィルターメソッドをそこに移動することができます。これがお役に立てば幸いです、これを理解する前にこれと1日戦わなければならなかったことを知っています。
他のヒント
しています。:)
で実際にアクセスのlistwidgetの内部モデル myList->model()
-から多くの信号が可能です。
場合だけドラッグ&ドロップ接続し、 layoutChanged
.だって移動ボタンが実装されて除去+追加)に接続 rowsInserted
ます。
したい場合はどの移動 rowsMoved
の方が良いかもしれないよ layoutChanged
.
Trey Stoutの回答は機能しましたが、リストの順序が実際に変更されていないときに明らかにイベントを取得していました。 Chaniの回答に目を向けましたが、これは必要に応じて機能しますが、コードがなければPythonで実装するのに少し手間がかかりました。
将来の訪問者を支援するためにコードスニペットを共有すると思った:
class MyList(QListWidget):
def __init__(self):
QListWidget.__init__(self)
self.setDragDropMode(self.InternalMove)
list_model = self.model()
list_model.layoutChanged.connect(self.on_layout_changed)
def on_layout_changed(self):
print "Layout Changed"
これはPySideでテストされていますが、PyQtで動作しない理由はありません。
解決策ではなく、いくつかのアイデア:
supportedDropActionsメソッドによって返される内容を確認する必要があります。 Qt :: MoveActionまたはQt :: CopyActionを含めるために、そのメソッドを上書きする必要があるかもしれません。
QListView :: indexesMovedシグナルはありますが、QListWidgetを使用している場合にシグナルが発行されるかどうかはわかりません。確認する価値があります。
これは古いことは知っていますが、Treyの答えを使用してコードを機能させることができたので、Pythonソリューションを共有したいと考えました。これは、サブクラス化されたものではなく、 QDialog
内の QListWidget
用です。
class NotesDialog(QtGui.QDialog):
def __init__(self, notes_list, notes_dir):
QtGui.QDialog.__init__(self)
self.ui=Ui_NotesDialog()
# the notesList QListWidget is created here (from Qt Designer)
self.ui.setupUi(self)
# install an event filter to catch internal QListWidget drop events
self.ui.notesList.installEventFilter(self)
def eventFilter(self, sender, event):
# this is the function that processes internal drop in notesList
if event.type() == QtCore.QEvent.ChildRemoved:
self.update_views() # do something
return False # don't actually interrupt anything
QListWidget.model()
アプローチは、提案されたソリューションの中で最もエレガントに見えましたが、PyQt5では機能しませんでした。理由はわかりませんが、Qt5への移行で何かが変わった可能性があります。 eventFilter
アプローチは機能しましたが、検討する価値がある別の代替手段があります。QDropEventをオーバーライドし、event.sourceがselfであるかどうかを確認することです。 PyQt5でチェックインするために提案されたすべてのソリューションがコーディングされたMVCEである以下のコードを参照してください。
import sys
from PyQt5 import QtGui, QtWidgets, QtCore
class MyList(QtWidgets.QListWidget):
itemMoved = QtCore.pyqtSignal()
def __init__(self):
super(MyList, self).__init__()
self.setDragDropMode(self.InternalMove)
list_model = self.model()
# list_model.layoutChanged.connect(self.onLayoutChanged) # doesn't work
# self.installEventFilter(self) # works
self.itemMoved.connect(self.onLayoutChanged) # works
def onLayoutChanged(self):
print("Layout Changed")
def eventFilter(self, sender, event):
"""
Parameters
----------
sender : object
event : QtCore.QEvent
"""
if event.type() == QtCore.QEvent.ChildRemoved:
self.onLayoutChanged()
return False
def dropEvent(self, QDropEvent):
"""
Parameters
----------
QDropEvent : QtGui.QDropEvent
"""
mime = QDropEvent.mimeData() # type: QtCore.QMimeData
source = QDropEvent.source()
if source is self:
super(MyList, self).dropEvent(QDropEvent)
self.itemMoved.emit()
app = QtWidgets.QApplication([])
form = MyList()
for text in ("one", "two", "three"):
item = QtWidgets.QListWidgetItem(text)
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
item.setCheckState(QtCore.Qt.Checked)
form.addItem(item)
form.show()
sys.exit(app.exec_())