PyQt4:在 QTreeView 中拖放
我用 PyQt4 制作了一个 UI。它有一个树视图,我想处理它。 树视图由模型库组成。我在 .py 文件中创建数据并导入它。 所以,我可以在我的树视图中看到数据树。 但我无法拖放它,因此无法更改顺序。 我引用了一些文章,因此将其添加到我的脚本中,但它们无法工作。 我种植了一些“打印”,所以我追查了我的问题。 我发现当拖动一个项目时,它会传输到 MIME 数据。 但是当它被删除时,我找不到任何输出。 该脚本似乎没有调用“dropMimeData”方法。 我该如何修复我的脚本?
from PyQt4 import QtCore, QtGui
from setting import *
from copy import deepcopy
from cPickle import dumps, load, loads
from cStringIO import StringIO
class PyMimeData(QtCore.QMimeData):
MIME_TYPE = QtCore.QString('text/plain')
def __init__(self, data=None):
QtCore.QMimeData.__init__(self)
self._local_instance = data
if data is not None:
try:
pdata = dumps(data)
except:
return
self.setData(self.MIME_TYPE, dumps(data.__class__) + pdata)
@classmethod
def coerce(cls, md):
if isinstance(md, cls):
return md
if not md.hasFormat(cls.MIME_TYPE):
return None
nmd = cls()
nmd.setData(cls.MIME_TYPE, md.data())
return nmd
def instance(self):
if self._local_instance is not None:
return self._local_instance
io = StringIO(str(self.data(self.MIME_TYPE)))
try:
load(io)
return load(io)
except:
pass
return None
def instanceType(self):
if self._local_instance is not None:
return self._local_instance.__class__
try:
return loads(str(self.data(self.MIME_TYPE)))
except:
pass
return None
class treeItem(QtGui.QStandardItem):
def __init__(self, data, parent=None):
super(treeItem, self).__init__(data)
self.parentItem = parent
self.itemData = data
self.childItems = []
def appendChild(self, item):
self.childItems.append(item)
def parent(self):
return self.parentItem
def childAtRow(self, row):
return self.childItems[row]
def rowOfChild(self, child):
for i, item in enumerate(self.childItems):
if item == child:
return i
return -1
class treeModel(QtGui.QStandardItemModel):
def __init__(self, name, parent=None):
super(treeModel, self).__init__(parent)
self.headerName = name
self.childItems = []
def appendChild(self, item):
self.childItems.append(item)
def removeRowAll(self):
pass
def addItemList(self, parent, elements):
for text, children in elements:
item = treeItem(text, parent)
self.addItems(parent, item)
if children:
self.addItemList(item, children)
def addItems(self, parent, inputItem):
parent.appendRow(inputItem)
parent.appendChild(inputItem)
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self.headerName
def supportedDropActions(self):
return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction
def flags(self, index):
defaultFlags = QtCore.QAbstractItemModel.flags(self, index)
if index.isValid():
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled | defaultFlags
else:
return QtCore.Qt.ItemIsDropEnabled | defaultFlags
def mimeTypes(self):
types = QtCore.QStringList()
types.append('text/plain')
return types
def mimeData(self, index):
node = self.nodeFromIndex(index[0])
mimeData = PyMimeData(node)
return mimeData
def dropMimeData(self, mimedata, action, row, column, parentIndex):
print mimedata, action, row, column, parentIndex
if action == QtCore.Qt.IgnoreAction:
return True
dragNode = mimedata.instance()
print dragNode
parentNode = self.nodeFromIndex(parentIndex)
# copy of node being moved
newNode = deepcopy(dragNode)
print newNode
newNode.setParent(parentNode)
self.insertRow(len(parentNode)-1, parentIndex)
self.emit(QtCore.SIGNAL("dataChanged(QtCore.QModelIndex,QtCore.QModelIndex)"), parentIndex, parentIndex)
return True
def nodeFromIndex(self, index):
##return index.internalPointer() if index.isValid() else self.root
return index.model() if index.isValid() else self.parent()
def insertRow(self, row, parent):
return self.insertRows(row, 1, parent)
def insertRows(self, row, count, parent):
self.beginInsertRows(parent, row, (row + (count - 1)))
self.endInsertRows()
return True
def removeRow(self, row, parentIndex):
return self.removeRows(row, 1, parentIndex)
def removeRows(self, row, count, parentIndex):
self.beginRemoveRows(parentIndex, row, row)
node = self.nodeFromIndex(parentIndex)
node.removeChild(row)
self.endRemoveRows()
return True
添加脚本 这里是ui创建(上面的脚本是在这个脚本中导入的)
class RigControlWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent = getMayaWindow()):
super(RigControlWindow, self).__init__(parent)
self.setupUi(self)
self.bodyrig_treelist.setDragEnabled(1)
self.bodyrig_treelist.setAcceptDrops(1)
self.bodyrig_treelist.setDropIndicatorShown(1)
self.bodyrig_treelist.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
QtCore.QObject.connect(self.finalize_button, QtCore.SIGNAL("clicked()"), self.AddData_treeList)
def AddData_treeList(self):
self.localtreeModel = treeModel("objects")
self.bodyrig_treelist.setModel(self.localtreeModel)
self.localtreeModel.addItemList(self.localtreeModel, data)
并且数据是
data = [("root",[("upper",[("hand",[]),
("head",[])
]),
("lower",[("leg",[]),
("foot",[])
])
])
]
I make a UI with PyQt4. It has a treeView and I want to deal with it.
The treeView is made up with model-base. I create a data in .py file and import it.
So, I can see the data tree in my treeView.
But I can't drag and drop it, so can't change the order.
I referred some articles so add it in my script, but they couldn't work.
I plant some "print", so I chased my problem.
I found that when drag a item, it transferred to MIME data.
But when it is dropped, I can't find any outputs.
It seems that the script doesn't call "dropMimeData" method.
How can I fix my script?
from PyQt4 import QtCore, QtGui
from setting import *
from copy import deepcopy
from cPickle import dumps, load, loads
from cStringIO import StringIO
class PyMimeData(QtCore.QMimeData):
MIME_TYPE = QtCore.QString('text/plain')
def __init__(self, data=None):
QtCore.QMimeData.__init__(self)
self._local_instance = data
if data is not None:
try:
pdata = dumps(data)
except:
return
self.setData(self.MIME_TYPE, dumps(data.__class__) + pdata)
@classmethod
def coerce(cls, md):
if isinstance(md, cls):
return md
if not md.hasFormat(cls.MIME_TYPE):
return None
nmd = cls()
nmd.setData(cls.MIME_TYPE, md.data())
return nmd
def instance(self):
if self._local_instance is not None:
return self._local_instance
io = StringIO(str(self.data(self.MIME_TYPE)))
try:
load(io)
return load(io)
except:
pass
return None
def instanceType(self):
if self._local_instance is not None:
return self._local_instance.__class__
try:
return loads(str(self.data(self.MIME_TYPE)))
except:
pass
return None
class treeItem(QtGui.QStandardItem):
def __init__(self, data, parent=None):
super(treeItem, self).__init__(data)
self.parentItem = parent
self.itemData = data
self.childItems = []
def appendChild(self, item):
self.childItems.append(item)
def parent(self):
return self.parentItem
def childAtRow(self, row):
return self.childItems[row]
def rowOfChild(self, child):
for i, item in enumerate(self.childItems):
if item == child:
return i
return -1
class treeModel(QtGui.QStandardItemModel):
def __init__(self, name, parent=None):
super(treeModel, self).__init__(parent)
self.headerName = name
self.childItems = []
def appendChild(self, item):
self.childItems.append(item)
def removeRowAll(self):
pass
def addItemList(self, parent, elements):
for text, children in elements:
item = treeItem(text, parent)
self.addItems(parent, item)
if children:
self.addItemList(item, children)
def addItems(self, parent, inputItem):
parent.appendRow(inputItem)
parent.appendChild(inputItem)
def headerData(self, section, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return self.headerName
def supportedDropActions(self):
return QtCore.Qt.MoveAction | QtCore.Qt.CopyAction
def flags(self, index):
defaultFlags = QtCore.QAbstractItemModel.flags(self, index)
if index.isValid():
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled | defaultFlags
else:
return QtCore.Qt.ItemIsDropEnabled | defaultFlags
def mimeTypes(self):
types = QtCore.QStringList()
types.append('text/plain')
return types
def mimeData(self, index):
node = self.nodeFromIndex(index[0])
mimeData = PyMimeData(node)
return mimeData
def dropMimeData(self, mimedata, action, row, column, parentIndex):
print mimedata, action, row, column, parentIndex
if action == QtCore.Qt.IgnoreAction:
return True
dragNode = mimedata.instance()
print dragNode
parentNode = self.nodeFromIndex(parentIndex)
# copy of node being moved
newNode = deepcopy(dragNode)
print newNode
newNode.setParent(parentNode)
self.insertRow(len(parentNode)-1, parentIndex)
self.emit(QtCore.SIGNAL("dataChanged(QtCore.QModelIndex,QtCore.QModelIndex)"), parentIndex, parentIndex)
return True
def nodeFromIndex(self, index):
##return index.internalPointer() if index.isValid() else self.root
return index.model() if index.isValid() else self.parent()
def insertRow(self, row, parent):
return self.insertRows(row, 1, parent)
def insertRows(self, row, count, parent):
self.beginInsertRows(parent, row, (row + (count - 1)))
self.endInsertRows()
return True
def removeRow(self, row, parentIndex):
return self.removeRows(row, 1, parentIndex)
def removeRows(self, row, count, parentIndex):
self.beginRemoveRows(parentIndex, row, row)
node = self.nodeFromIndex(parentIndex)
node.removeChild(row)
self.endRemoveRows()
return True
added script
here is ui creation (the script above is imported in this script)
class RigControlWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent = getMayaWindow()):
super(RigControlWindow, self).__init__(parent)
self.setupUi(self)
self.bodyrig_treelist.setDragEnabled(1)
self.bodyrig_treelist.setAcceptDrops(1)
self.bodyrig_treelist.setDropIndicatorShown(1)
self.bodyrig_treelist.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
QtCore.QObject.connect(self.finalize_button, QtCore.SIGNAL("clicked()"), self.AddData_treeList)
def AddData_treeList(self):
self.localtreeModel = treeModel("objects")
self.bodyrig_treelist.setModel(self.localtreeModel)
self.localtreeModel.addItemList(self.localtreeModel, data)
and data is
data = [("root",[("upper",[("hand",[]),
("head",[])
]),
("lower",[("leg",[]),
("foot",[])
])
])
]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
QTreeView.dragMoveEvent
和QTreeView.dragEnterEvent
方法都检查event.mimeData()
返回的对象,看看它是否可以返回任何数据模型支持的格式(即由model.mimeTypes()
返回的格式)。但是您的
PyMimeData
子类不支持任何格式,因为它从未成功设置传递给其构造函数的数据。问题位于
PyMimeData.__init__
:data
是从treeModel.mimeData
方法传入的:但是如果你检查<的类型code>data/node 你会看到它是一个
treeModel
实例,因此dumps(data)
将失败,因为data
> 不能腌制。因此,PyMimeData
对象未正确初始化,因此它会被拖动事件忽略。The
QTreeView.dragMoveEvent
andQTreeView.dragEnterEvent
methods both check the object returned byevent.mimeData()
to see if it can return data for any of the formats supported by the model (i.e. those returned bymodel.mimeTypes()
).But your
PyMimeData
subclass doesn't support any formats, because it never successfully sets the data passed to its constructor.The problem is located in
PyMimeData.__init__
:The
data
is passed in from thetreeModel.mimeData
method:But if you check the type of
data/node
you'll see that it is atreeModel
instance, and sodumps(data)
will fail becausedata
can't be pickled. As a result of this, thePyMimeData
object is not initialized properly, and so it is ignored by drag events.