#python #qt #pyqt #pyside
#python #qt #pyqt #pyside
Вопрос:
Я сталкиваюсь с некоторыми проблемами, пытаясь реализовать перетаскивание для пользовательского QListWidgetItem. Вот несколько примеров кода:
from PyQt4 import QtGui, QtCore
import sys, os
class MyListWidgetItem(QtGui.QListWidgetItem):
def __init__(self, label, data, parent=None):
super(QtGui.QListWidgetItem, self).__init__(label, parent=parent)
self.data = data
def GetData(self):
return self.data
class MyListWidget(QtGui.QListWidget):
def __init__(self, type, parent=None):
super(MyListWidget, self).__init__(parent)
self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.setAcceptDrops(True)
self.viewport().setAcceptDrops(True)
self.setDropIndicatorShown(True)
def startDrag(self, supportedActions):
drag = QtGui.QDrag(self)
t = [i.GetData() for i in self.selectedItems()]
mimeData = self.model().mimeData(self.selectedIndexes())
mimeData.setText(str(t))
drag.setMimeData(mimeData)
if drag.start(QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction:
for item in self.selectedItems():
self.takeItem(self.row(item))
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.ignore()
else:
event.accept()
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.ignore()
else:
event.accept()
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.ignore()
if isinstance(event.source(), MyListWidget):
event.setDropAction(QtCore.Qt.MoveAction)
super(MyListWidget, self).dropEvent(event)
else:
event.ignore()
def dropMimeData(self, index, mimedata, action):
super(MyListWidget, self).dropMimeData(index, mimedata, action)
return True
class Test(QtGui.QMainWindow):
def __init__(self):
super(QtGui.QMainWindow,self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.listWidgetA = MyListWidget(self)
self.listWidgetB = MyListWidget(self)
for i in range(5):
listItemAInstance = MyListWidgetItem(str(i), i, parent=self.listWidgetA)
myBoxLayout.addWidget(self.listWidgetA)
myBoxLayout.addWidget(self.listWidgetB)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog_1 = Test()
dialog_1.show()
dialog_1.resize(480,320)
sys.exit(app.exec_())
Мой пользовательский класс MyListWidgetItem имеет поле «данные», которое в моей реальной программе содержит некоторую информацию, относящуюся к элементу. Если вы запустите код и попытаетесь перетащить элементы из верхнего списка в нижний, все работает, но если вы затем попытаетесь вернуть их в верхний список, вы получите эту ошибку:
Traceback (most recent call last):
File "C:UsersMassiDesktopt.py", line 23, in startDrag
t = [i.GetData() for i in self.selectedItems()]
AttributeError: 'QListWidgetItem' object has no attribute 'GetData'
Кажется довольно очевидным, что поведение перетаскивания по умолчанию игнорирует то, что элементы списка были подклассами, поэтому мне интересно, как лучше всего справиться с этой ситуацией. Любая помощь действительно ценится.
Заранее спасибо!
Комментарии:
1. разве это не должно быть
getData
, нетGetData
?
Ответ №1:
Я бы использовал a QListView
с a QStandardItemModel
и использовал QStandardItemModel.setItemPrototype(MyStandardItem())
и определил MyStandardItem
что-то вроде:
class MyStandardItem(QtGui.QStandardItem):
def __init__(self, *__args):
super().__init__(*__args)
def clone(self):
return MyStandardItem()
Ответ №2:
Если вы добавите некоторую отладочную информацию, подобную следующей, вы можете обнаружить, что «i» уже является MyListWidgetItem , так что это не должно быть проблемой.
def startDrag(self, supportedActions):
drag = QtGui.QDrag(self)
# add the following 2 line debug information
for item in self.selectedItems():
print item.__class__.__name__
t = [i.GetData() for i in self.selectedItems() if hasattr(i, "GetData")]
mimeData = self.model().mimeData(self.selectedIndexes())
mimeData.setText(str(t))
drag.setMimeData(mimeData)
if drag.start(QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction:
for item in self.selectedItems():
self.takeItem(self.row(item))
вывод
MyListWidgetItem
Проблема в том, что вы НЕ можете привести тип элемента к MyListWidgetItem, поскольку python не поддерживает приведение типов, поэтому вам нужно использовать механизм отражения для вызова метода getData(), я только что попробовал код, он отлично работает!