[英]PyQt: How to get QListWidget's listItem .data() on dropEvent
There are two QListWidgets. 有两个QListWidgets。 Every list item was assigned MyClass()'s instance using
setData(QtCore.Qt.UserRole, myClassInstA)
. 使用
setData(QtCore.Qt.UserRole, myClassInstA)
为每个列表项分配MyClass()的实例。
Clicking a lower QListWidget's listItem prints out a clicked listItem's data retrieved using: 单击较低的QListWidget的listItem将打印出使用以下方法检索的单击的listItem数据:
.data(QtCore.Qt.UserRole).toPyObject()
Any itemA dragged and dropped from top QListWidget onto a lower shows None for data. 从顶部QListWidget拖放到底部的任何itemA均显示None。 Interesting that clicking the same item prints there is a data.
有趣的是,单击同一项目会打印出一个数据。 I wonder if it is possible to retrieve a data stored in listItem within droppedOnB() function (so droppedOnB() is able to print out the data stored in a item).
我想知道是否有可能在dropOnB()函数中检索存储在listItem中的数据(因此dropOnB()能够打印出存储在项目中的数据)。
from PyQt4 import QtGui, QtCore
import sys, os
class MyClass(object):
def __init__(self):
super(MyClass, self).__init__()
class ThumbListWidget(QtGui.QListWidget):
_drag_info = []
def __init__(self, type, name, parent=None):
super(ThumbListWidget, self).__init__(parent)
self.setObjectName(name)
self.setIconSize(QtCore.QSize(124, 124))
self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.setAcceptDrops(True)
self._dropping = False
def startDrag(self, actions):
self._drag_info[:] = [str(self.objectName())]
for item in self.selectedItems():
self._drag_info.append(self.row(item))
super(ThumbListWidget, self).startDrag(actions)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
super(ThumbListWidget, self).dragEnterEvent(event)
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
else:
super(ThumbListWidget, self).dragMoveEvent(event)
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
links = []
for url in event.mimeData().urls():
links.append(str(url.toLocalFile()))
self.emit(QtCore.SIGNAL("dropped"), links)
else:
# event.setDropAction(QtCore.Qt.MoveAction)
self._dropping = True
super(ThumbListWidget, self).dropEvent(event)
self._dropping = False
def rowsInserted(self, parent, start, end):
if self._dropping:
self._drag_info.append((start, end))
self.emit(QtCore.SIGNAL("dropped"), self._drag_info)
super(ThumbListWidget, self).rowsInserted(parent, start, end)
class Dialog_01(QtGui.QMainWindow):
def __init__(self):
super(QtGui.QMainWindow,self).__init__()
self.listItems={}
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.listWidgetA = ThumbListWidget(self, 'MainTree')
self.listWidgetB = ThumbListWidget(self, 'SecondaryTree')
self.listWidgetB.setDragDropMode(QtGui.QAbstractItemView.DropOnly)
for i in range(7):
listItemA=QtGui.QListWidgetItem()
listItemA.setText('A'+'%04d'%i)
self.listWidgetA.addItem(listItemA)
myClassInstA=MyClass()
listItemA.setData(QtCore.Qt.UserRole, myClassInstA)
listItemB=QtGui.QListWidgetItem()
listItemB.setText('B'+'%04d'%i)
self.listWidgetB.addItem(listItemB)
myClassInstB=MyClass()
listItemB.setData(QtCore.Qt.UserRole, myClassInstB)
myBoxLayout.addWidget(self.listWidgetA)
myBoxLayout.addWidget(self.listWidgetB)
self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.droppedOnB)
self.listWidgetB.clicked.connect(self.itemClicked)
def droppedOnB(self, dropped_list):
print '\n\t droppedOnB()', dropped_list, dropped_list[-1]
destIndexes=dropped_list[-1]
for index in range(destIndexes[0],destIndexes[-1]+1):
dropedItem=self.listWidgetB.item(index)
modelIndex=self.listWidgetB.indexFromItem(dropedItem)
dataObject = modelIndex.data(QtCore.Qt.UserRole).toPyObject()
print '\n\t\t droppedOnB()', type(modelIndex), type(dataObject)
def itemClicked(self, modelIndex):
dataObject = modelIndex.data(QtCore.Qt.UserRole).toPyObject()
print 'itemClicked(): ' ,type(modelIndex), type(dataObject)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog_1 = Dialog_01()
dialog_1.show()
dialog_1.resize(720,480)
sys.exit(app.exec_())
The ultimate goal was to replace MyClassA 's instance data -object (attached to itemA) with MyClassB after itemA is dropped onto listWidgetB. 最终目标是意达滴到listWidgetB后MyClassB更换MyClassA的实例数据 -object(连接到意达)。
When itemA is dropped onto the destination listWidgetB the itemA arrives with no data stored. 将itemA放到目标listWidgetB上时,iteA到达时未存储任何数据。 It returns None if you try to retrieve it with itemA.data(QtCore.Qt.UserRole).toPyObject() (if done inside of droppedOnB() - a method triggered first onDrop event).
如果尝试使用itemA.data(QtCore.Qt.UserRole).toPyObject()检索它,则返回None(如果在dropOnB()内完成-一个方法触发第一个onDrop事件)。
Trying to assign, reassign a data to just dropped listItem... or even removing it causes all kind of surprises later. 尝试分配,重新分配数据到刚刚删除的listItem ...甚至删除它,都会在以后引起各种意外。 I am using .setHidden(True).
我正在使用.setHidden(True)。
Those are the steps: 这些是步骤:
Here is a functional code. 这是一个功能代码。 Once again, itemA is assign an instance of ClassA on creation.
在创建时,再次为itemA分配ClassA的实例。 After itemA is dropped onto listWidgetB a dropped item is hidden and 'substituted' with another item to which classB instance is assigned.
在将itemA放置到listWidgetB上之后,隐藏的项目被隐藏,并被分配了classB实例的另一个项目“替代”。
from PyQt4 import QtGui, QtCore
import sys, os, copy
class MyClassA(object):
def __init__(self):
super(MyClassA, self).__init__()
class MyClassB(object):
def __init__(self):
super(MyClassB, self).__init__()
self.DataObjectCopy=None
class ThumbListWidget(QtGui.QListWidget):
_drag_info = []
def __init__(self, type, name, parent=None):
super(ThumbListWidget, self).__init__(parent)
self.setObjectName(name)
self.setIconSize(QtCore.QSize(124, 124))
self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.setAcceptDrops(True)
self._dropping = False
def startDrag(self, actions):
self._drag_info[:] = [str(self.objectName())]
for item in self.selectedItems():
self._drag_info.append(self.row(item))
super(ThumbListWidget, self).startDrag(actions)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls():
event.accept()
else:
super(ThumbListWidget, self).dragEnterEvent(event)
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
else:
super(ThumbListWidget, self).dragMoveEvent(event)
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
links = []
for url in event.mimeData().urls():
links.append(str(url.toLocalFile()))
self.emit(QtCore.SIGNAL("dropped"), links)
else:
# event.setDropAction(QtCore.Qt.MoveAction)
self._dropping = True
super(ThumbListWidget, self).dropEvent(event)
self._dropping = False
def rowsInserted(self, parent, start, end):
if self._dropping:
self._drag_info.append((start, end))
self.emit(QtCore.SIGNAL("dropped"), self._drag_info)
super(ThumbListWidget, self).rowsInserted(parent, start, end)
class Dialog_01(QtGui.QMainWindow):
def __init__(self):
super(QtGui.QMainWindow,self).__init__()
self.listItems={}
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.listWidgetA = ThumbListWidget(self, 'MainTree')
self.listWidgetB = ThumbListWidget(self, 'SecondaryTree')
self.listWidgetB.setDragDropMode(QtGui.QAbstractItemView.DropOnly)
for i in range(3):
listItemA=QtGui.QListWidgetItem()
listItemA.setText('A'+'%04d'%i)
self.listWidgetA.addItem(listItemA)
myClassInstA=MyClassA()
listItemA.setData(QtCore.Qt.UserRole, myClassInstA)
listItemB=QtGui.QListWidgetItem()
listItemB.setText('B'+'%04d'%i)
self.listWidgetB.addItem(listItemB)
myClassInstB=MyClassB()
listItemB.setData(QtCore.Qt.UserRole, myClassInstB)
myBoxLayout.addWidget(self.listWidgetA)
myBoxLayout.addWidget(self.listWidgetB)
self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.droppedOnB)
self.listWidgetB.clicked.connect(self.itemClicked)
def droppedOnB(self, dropped_list):
if not dropped_list or len(dropped_list)<3: return
srcIndexes=dropped_list[1:-1]
destIndexes=dropped_list[-1]
# build a list of corresponding src-to-dest indexes sets
itemsIndxes=[]
i=0
for num in range(destIndexes[0], destIndexes[-1]+1):
itemsIndxes.append((srcIndexes[i], num))
i+=1
print '\n\t droppedOnB(): dropped_list =',dropped_list,'; srcIndexes =',srcIndexes,'; destIndexes =',destIndexes, '; itemsIndxes =',itemsIndxes
for indexSet in itemsIndxes:
srcNum = indexSet[0]
destIndxNum = indexSet[-1]
# Get source listItem's data object
srcItem=self.listWidgetA.item(srcNum)
if not srcItem: continue
srcItemData = srcItem.data(QtCore.Qt.UserRole)
if not srcItemData: continue
srcItemDataObject=srcItemData.toPyObject()
if not srcItemDataObject: continue
# make a deepcopy of src data object
itemDataObject_copy=copy.deepcopy(srcItemDataObject)
# get dropped item
droppedItem=self.listWidgetB.item(destIndxNum)
# hide dropped item since removing it results to mess
droppedItem.setHidden(True)
# declare new ClassB instance
myClassInstB=MyClassB()
myClassInstB.DataObjectCopy=itemDataObject_copy
# create a new listItem
newListItem=QtGui.QListWidgetItem()
newListItem.setData(QtCore.Qt.UserRole, myClassInstB)
newListItem.setText(srcItem.text())
self.listWidgetB.blockSignals(True)
self.listWidgetB.addItem(newListItem)
self.listWidgetB.blockSignals(False)
def itemClicked(self, modelIndex):
dataObject = modelIndex.data(QtCore.Qt.UserRole).toPyObject()
print 'itemClicked(): instance type:', type(dataObject)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog_1 = Dialog_01()
dialog_1.show()
dialog_1.resize(720,480)
sys.exit(app.exec_())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.