pyside qtreewidget约束拖放 [英] pyside qtreewidget constrain drag and drop

查看:401
本文介绍了pyside qtreewidget约束拖放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试向QTreeWidget拖放功能添加一个约束,以防止分支进入另一个根目录中的另一个分支。



事情更清楚:

我有4个对象。让他们称苹果,香蕉,胡萝卜,榴莲。



树如下所示:

  isDelicious(Root)
| - BackgroundObjects(Branch)
| - Durian
| - ForgroundObjects(Branch)
| - Apple
| - 香蕉
| - 胡萝卜
isSmelly(根)
| - BackgroundObjects(Branch)
| - Apple
| - Carrot
| - ForgroundObjects(Branch)
| - 香蕉
| - 榴莲

所以,这些对象被允许从BackgroundObjects拖放到ForgroundObjects,而在同一个根目录下可以拖放对象,但不允许这些对象被拖放到另一个根上的一个分支上。



我已经尝试重新实现和子类化dragMoveEvent,dragEnterEvent和dropEvent,如果我在dragEnterEvent中的事件中调用accept,那么它将调用dragMoveEvent(我期望)。但是,dropEvent仅在我离开QTreeWidget之后才被调用。



我想做的是检查所选对象的祖父母移动之前,并提出新祖父,看看他们是否一样。如果是的话,接受移动。否则忽略移动。



我已经搜索了解是否有任何答案,到目前为止,我还没有看到任何我想要做的事情。可能最接近的是Stack Overflow中的两个问题:

https://stackoverflow.com/questions/17134289/managing-drag-and-drop-within-qtreewidgets-in-pyside

qt:QTreeView - 限制拖放只发生在一个特殊的祖父母(祖先)

解决方案

Qt似乎并没有使这种事情变得非常简单。 b
$ b

我可以想出的最好的办法是在拖放和拖动事件期间临时重置项目标志。下面的示例动态地计算当前的顶级项,以阻止拖放。但是也可以使用 setData()在每个项目中添加标识符。

来自PyQt4的QtCore,QtGui 

class TreeWidget(QtGui.QTreeWidget):
def __init __(self,parent = None):
QtGui.QTreeWidget。 __init __(self,parent)
self.setDragDropMode(self.InternalMove)
self.setDragEnabled(True)
self.setDropIndicatorShown(True)
self._dragroot = self.itemRootIndex )

def itemRootIndex(self,item = None):
root = self.invisibleRootItem()
而项不是无:
item = item.parent( )
如果项目不是无:
root =项目
返回QtCore.QPersistentModelIndex(
self.indexFromItem(root))

def startDrag(self ,action):
items = self.selectedItems()
self._dragroot = self.itemRootIndex(items and items [0])
QtGui.QTree Widget.startDrag(self,actions)

def dragEnterEvent(self,event):
self._drag_event(event,True)

def dragMoveEvent(self,event )
self._drag_event(event,False)

def _drag_event(self,event,enter = True):
items = []
disable = False
item = self.itemAt(event.pos())
如果项不是无:
disable = self._dragroot!= self.itemRootIndex(item)
如果不禁用:
rect = self.visualItemRect(item)
如果event.pos()。x() rect.x():
disable = True
如果禁用:
项目中的项目,item.parent():
如果项目不是无:
标志= item.flags()
item.setFlags(flags&〜QtCore.Qt.ItemIsDropEnabled)
items.append((item,flags))
如果输入:
QtGui .QTreeWidget.dragEnterEvent(self,event)
else:
QtGui.QTreeWidget.dragMoveEvent(self,event)
项目中的标志:
item.setFlags(flags)

class Window(QtGui.QWidget):
def __init __(self):
QtGui.QWidget .__ init __(self)
self.tree = TreeWidget(self)
self.tree.header()。hide()
def add(root,* labels):
item = QtGui.QTreeWidgetItem(self.tree,[root])
item.setFlags(item.flags()&
〜(QtCore.Qt.ItemIsDragEnabled |
QtCore.Qt.ItemIsDropEnabled))
为索引,枚举中的标题(
('BackgroundObjects','ForegroundObjects')):
subitem = QtGui.QTreeWidgetItem(item,[title] )
subitem.setFlags(
subitem.flags()& 〜QtCore.Qt.ItemIsDragEnabled)
标签中的文本[index] .split():
child = QtGui.QTreeWidgetItem(subitem,[text])
child.setFlags(
child.flags()&〜QtCore.Qt.ItemIsDropEnabled)
add('isDelicious','Durian','Apple Banana Carrot')
add('isSmelly','Apple Carrot' 'Banana Durian')
root = self.tree.invisibleRootItem()
root.setFlags(root.flags()&〜QtCore.Qt.ItemIsDropEnabled)
self.tree.expandAll( )
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.tree)

如果__name__ =='__main__':

导入sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500,300,300,300)
window.show()
sys.exit(app.exec_())


I'm trying to add a constraint to the QTreeWidget drag and drop function to prevent the branches from entering another branch in another root.

Here's an example to make things more clear:
I have 4 objects. Lets call them apple, banana, carrot, durian.

The tree looks like this:

isDelicious (Root)
|-- BackgroundObjects (Branch)
   |-- Durian
|-- ForgroundObjects (Branch)
   |-- Apple
   |-- Banana
   |-- Carrot
isSmelly (Root)
|-- BackgroundObjects (Branch)
   |-- Apple
   |-- Carrot
|-- ForgroundObjects (Branch)
   |-- Banana
   |-- Durian

So, the objects are allowed to be dragged and dropped from BackgroundObjects to ForgroundObjects, and visa versa on the same root, but they are not allowed to be dragged and dropped onto a branch on a different root.

I have tried reimplementing and subclassing dragMoveEvent, dragEnterEvent, and dropEvent, and if I call accept on the event in dragEnterEvent, it'll call dragMoveEvent after (which I expect). However, dropEvent is only called when I drop outside of the QTreeWidget.

What I want to do is check the grandparent of the selected objects before they are moved, and the proposed new grandparent to see if they are the same. If so, then accept the move. Otherwise ignore the move.

I have searched to see if there is any answers, and so far I haven't seen any for what I'm trying to do. Probably the closest would be these two questions from Stack Overflow:
https://stackoverflow.com/questions/17134289/managing-drag-and-drop-within-qtreewidgets-in-pyside
qt: QTreeView - limit drag and drop to only happen within a particlar grandparent (ancestor)

解决方案

Qt does not seem to make this sort of thing very easy.

The best I could come up with was to temporarily reset the item flags during the drag-enter and drag-move events. The example below calculates the current top-level item dynamically in order to contrain drag and drop. But it could also be done by using setData() to add an identifier to each item.

from PyQt4 import QtCore, QtGui

class TreeWidget(QtGui.QTreeWidget):
    def __init__(self, parent=None):
        QtGui.QTreeWidget.__init__(self, parent)
        self.setDragDropMode(self.InternalMove)
        self.setDragEnabled(True)
        self.setDropIndicatorShown(True)
        self._dragroot = self.itemRootIndex()

    def itemRootIndex(self, item=None):
        root = self.invisibleRootItem()
        while item is not None:
            item = item.parent()
            if item is not None:
                root = item
        return QtCore.QPersistentModelIndex(
            self.indexFromItem(root))

    def startDrag(self, actions):
        items = self.selectedItems()
        self._dragroot = self.itemRootIndex(items and items[0])
        QtGui.QTreeWidget.startDrag(self, actions)

    def dragEnterEvent(self, event):
        self._drag_event(event, True)

    def dragMoveEvent(self, event):
        self._drag_event(event, False)

    def _drag_event(self, event, enter=True):
        items = []
        disable = False
        item = self.itemAt(event.pos())
        if item is not None:
            disable = self._dragroot != self.itemRootIndex(item)
            if not disable:
                rect = self.visualItemRect(item)
                if event.pos().x() < rect.x():
                    disable = True
        if disable:
            for item in item, item.parent():
                if item is not None:
                    flags = item.flags()
                    item.setFlags(flags & ~QtCore.Qt.ItemIsDropEnabled)
                    items.append((item, flags))
        if enter:
            QtGui.QTreeWidget.dragEnterEvent(self, event)
        else:
            QtGui.QTreeWidget.dragMoveEvent(self, event)
        for item, flags in items:
            item.setFlags(flags)

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.tree = TreeWidget(self)
        self.tree.header().hide()
        def add(root, *labels):
            item = QtGui.QTreeWidgetItem(self.tree, [root])
            item.setFlags(item.flags() &
                          ~(QtCore.Qt.ItemIsDragEnabled |
                            QtCore.Qt.ItemIsDropEnabled))
            for index, title in enumerate(
                ('BackgroundObjects', 'ForegroundObjects')):
                subitem = QtGui.QTreeWidgetItem(item, [title])
                subitem.setFlags(
                    subitem.flags() & ~QtCore.Qt.ItemIsDragEnabled)
                for text in labels[index].split():
                    child = QtGui.QTreeWidgetItem(subitem, [text])
                    child.setFlags(
                        child.flags() & ~QtCore.Qt.ItemIsDropEnabled)
        add('isDelicious', 'Durian', 'Apple Banana Carrot')
        add('isSmelly', 'Apple Carrot', 'Banana Durian')
        root = self.tree.invisibleRootItem()
        root.setFlags(root.flags() & ~QtCore.Qt.ItemIsDropEnabled)
        self.tree.expandAll()
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.tree)

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 300, 300)
    window.show()
    sys.exit(app.exec_())

这篇关于pyside qtreewidget约束拖放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆