如何将自定义 QStandardItem 放入 QListView
How to drop a custom QStandardItem into a QListView
我正在尝试使用自定义 QStandardItem 在两个 QListView 之间进行拖放操作。
我无法在网上找到我需要的信息,但 this document 有点帮助,但现在我被困住了。
拖放一个 QListView to another works fine when I use a QStandardItem to hold my data, but when I use a custom item I run into trouble, because the receiving model/view creates a QStandardItem 自定义项目时。
理想情况下,我可以告诉接收模型使用我的自定义项目作为默认项目,否则就照做,但我想这不会那么容易?!
似乎一切都是开箱即用的,除了 QStandardItem 在放下时的创建,而不是我的自定义项目,所以我希望我不必为了得到它而重新发明(拖放)轮一部分对吗?!
如果我确实需要重新发明轮子并实现视图的 dropEvent 以手动附加传入的项目,那么我 运行 变成了另一个怪人。这是我的测试代码(包括一些我在网上找到的用于解码丢失数据的代码):
from PySide import QtCore, QtGui
class MyItem(QtGui.QStandardItem):
'''This is the item I'd like to drop into the view'''
def __init__(self, parent=None):
super(MyItem, self).__init__(parent)
self.testAttr = 'test attribute value'
class ReceivingView(QtGui.QListView):
'''Custom view to show the problem - i.e. the dropEvent produces a QStandardItem rather than MyItem'''
def __init__(self, parent=None):
super(ReceivingView, self).__init__(parent)
def decode_data(self, bytearray):
'''Decode byte array to receive item back'''
data = []
item = {}
ds = QtCore.QDataStream(bytearray)
while not ds.atEnd():
row = ds.readInt32()
column = ds.readInt32()
map_items = ds.readInt32()
for i in range(map_items):
key = ds.readInt32()
value = MyItem()
ds >> value
#item[QtCore.Qt.ItemDataRole(key)] = value
item = value
data.append(item)
return data
def dropEvent(self, event):
byteArray = event.mimeData().data('application/x-qabstractitemmodeldatalist')
for item in self.decode_data(byteArray):
copiedItem = MyItem(item)
newItem = MyItem('hello')
print copiedItem
print newItem
self.model().appendRow(copiedItem) # the copied item does not show up, even though it is appended to the model
#self.model().appendRow(newItem) # this works as expected
event.accept()
item = self.model().item(self.model().rowCount() - 1)
print item
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
mw = QtGui.QMainWindow()
w = QtGui.QSplitter()
mw.setCentralWidget(w)
# models
model1 = QtGui.QStandardItemModel()
model2 = QtGui.QStandardItemModel()
for i in xrange(5):
#item = QtGui.QStandardItem()
item = MyItem()
item.setData(str(i), QtCore.Qt.DisplayRole)
model1.appendRow(item)
# views
view1 = QtGui.QListView()
view2 = ReceivingView()
for v in (view1, view2):
v.setViewMode(QtGui.QListView.IconMode)
view1.setModel(model1)
view2.setModel(model2)
w.addWidget(view1)
w.addWidget(view2)
mw.show()
mw.raise_()
sys.exit(app.exec_())
想法是对丢弃的数据进行解码以接收原始项目,然后制作一个副本并将该副本附加到接收模型。
自定义项附加到模型,但在放置事件后不会显示在视图中。如果我在 drop even 中创建一个新的自定义项目并附加它,一切都会按预期进行。
关于上面的问题我有两个问题:
- 这种方法是允许自定义物品掉落的正确方法还是有更简单的方法?
- 为什么上面代码中的自定义项的副本在拖放后没有显示在视图中?
提前致谢,
坦率
看来你想要setItemPrototype。这为模型提供了一个项目工厂,因此它会在必要时隐式使用您的自定义 class。
您需要做的就是在您的项目中重新实现 clone()
class:
class MyItem(QtGui.QStandardItem):
'''This is the item I'd like to drop into the view'''
def __init__(self, parent=None):
super(MyItem, self).__init__(parent)
self.testAttr = 'test attribute value'
def clone(self):
return MyItem()
然后将 class 的实例设置为接收模型上的原型:
# models
model1 = QtGui.QStandardItemModel()
model2 = QtGui.QStandardItemModel()
model2.setItemPrototype(MyItem())
你可以忘掉所有数据流的东西。
PS:
我想我应该指出 Qt 显然对项目生命周期中可能设置的任何 python 数据属性一无所知,因此当项目在拖放操作。如果你想保留这样的数据,请使用 setData()
和自定义角色:
class MyItem(QtGui.QStandardItem):
_TestAttrRole = QtCore.Qt.UserRole + 2
def clone(self):
item = MyItem()
item.testArr = 'test attribute value'
return item
@property
def testAttr(self):
return self.data(self._TestAttrRole)
@testAttr.setter
def testAttr(self, value):
self.setData(value, self._TestAttrRole)
我正在尝试使用自定义 QStandardItem 在两个 QListView 之间进行拖放操作。 我无法在网上找到我需要的信息,但 this document 有点帮助,但现在我被困住了。
拖放一个 QListView to another works fine when I use a QStandardItem to hold my data, but when I use a custom item I run into trouble, because the receiving model/view creates a QStandardItem 自定义项目时。
理想情况下,我可以告诉接收模型使用我的自定义项目作为默认项目,否则就照做,但我想这不会那么容易?! 似乎一切都是开箱即用的,除了 QStandardItem 在放下时的创建,而不是我的自定义项目,所以我希望我不必为了得到它而重新发明(拖放)轮一部分对吗?!
如果我确实需要重新发明轮子并实现视图的 dropEvent 以手动附加传入的项目,那么我 运行 变成了另一个怪人。这是我的测试代码(包括一些我在网上找到的用于解码丢失数据的代码):
from PySide import QtCore, QtGui
class MyItem(QtGui.QStandardItem):
'''This is the item I'd like to drop into the view'''
def __init__(self, parent=None):
super(MyItem, self).__init__(parent)
self.testAttr = 'test attribute value'
class ReceivingView(QtGui.QListView):
'''Custom view to show the problem - i.e. the dropEvent produces a QStandardItem rather than MyItem'''
def __init__(self, parent=None):
super(ReceivingView, self).__init__(parent)
def decode_data(self, bytearray):
'''Decode byte array to receive item back'''
data = []
item = {}
ds = QtCore.QDataStream(bytearray)
while not ds.atEnd():
row = ds.readInt32()
column = ds.readInt32()
map_items = ds.readInt32()
for i in range(map_items):
key = ds.readInt32()
value = MyItem()
ds >> value
#item[QtCore.Qt.ItemDataRole(key)] = value
item = value
data.append(item)
return data
def dropEvent(self, event):
byteArray = event.mimeData().data('application/x-qabstractitemmodeldatalist')
for item in self.decode_data(byteArray):
copiedItem = MyItem(item)
newItem = MyItem('hello')
print copiedItem
print newItem
self.model().appendRow(copiedItem) # the copied item does not show up, even though it is appended to the model
#self.model().appendRow(newItem) # this works as expected
event.accept()
item = self.model().item(self.model().rowCount() - 1)
print item
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
mw = QtGui.QMainWindow()
w = QtGui.QSplitter()
mw.setCentralWidget(w)
# models
model1 = QtGui.QStandardItemModel()
model2 = QtGui.QStandardItemModel()
for i in xrange(5):
#item = QtGui.QStandardItem()
item = MyItem()
item.setData(str(i), QtCore.Qt.DisplayRole)
model1.appendRow(item)
# views
view1 = QtGui.QListView()
view2 = ReceivingView()
for v in (view1, view2):
v.setViewMode(QtGui.QListView.IconMode)
view1.setModel(model1)
view2.setModel(model2)
w.addWidget(view1)
w.addWidget(view2)
mw.show()
mw.raise_()
sys.exit(app.exec_())
想法是对丢弃的数据进行解码以接收原始项目,然后制作一个副本并将该副本附加到接收模型。 自定义项附加到模型,但在放置事件后不会显示在视图中。如果我在 drop even 中创建一个新的自定义项目并附加它,一切都会按预期进行。
关于上面的问题我有两个问题:
- 这种方法是允许自定义物品掉落的正确方法还是有更简单的方法?
- 为什么上面代码中的自定义项的副本在拖放后没有显示在视图中?
提前致谢, 坦率
看来你想要setItemPrototype。这为模型提供了一个项目工厂,因此它会在必要时隐式使用您的自定义 class。
您需要做的就是在您的项目中重新实现 clone()
class:
class MyItem(QtGui.QStandardItem):
'''This is the item I'd like to drop into the view'''
def __init__(self, parent=None):
super(MyItem, self).__init__(parent)
self.testAttr = 'test attribute value'
def clone(self):
return MyItem()
然后将 class 的实例设置为接收模型上的原型:
# models
model1 = QtGui.QStandardItemModel()
model2 = QtGui.QStandardItemModel()
model2.setItemPrototype(MyItem())
你可以忘掉所有数据流的东西。
PS:
我想我应该指出 Qt 显然对项目生命周期中可能设置的任何 python 数据属性一无所知,因此当项目在拖放操作。如果你想保留这样的数据,请使用 setData()
和自定义角色:
class MyItem(QtGui.QStandardItem):
_TestAttrRole = QtCore.Qt.UserRole + 2
def clone(self):
item = MyItem()
item.testArr = 'test attribute value'
return item
@property
def testAttr(self):
return self.data(self._TestAttrRole)
@testAttr.setter
def testAttr(self, value):
self.setData(value, self._TestAttrRole)