控制QTreeWidget项的拖放禁用/启用 - python

时间:2015-12-07 12:40:11

标签: python qt drag-and-drop pyside

在我的示例中,我希望用户能够在所有类型的系列之间拖放子项。但是,我想限制用户无法将某个人拖放到另一个人身上,或者将某个人作为根对象放弃,这反过来会使其成为一个家庭。

我已经非常接近了。但是有一个bug。如果用户将某个人拖动到一个家庭,将鼠标悬停在家庭上方的光标上,如果您小心地将光标移动到该系列的最顶端,您将看到该指示器,允许您放下该项目以便#&# 39;高于家庭,不属于家庭。代码测试为true并允许用户成功删除此人。结果将该人置于家庭之外。下图显示了我的意思。

代码主要集中在第75-125行之间。

enter image description here

# Imports
# ------------------------------------------------------------------------------
import sys
from PySide import QtCore, QtGui

# Class Object
# ------------------------------------------------------------------------------
class Person():
    def __init__(self, name="", age=0):
        self.name = name
        self.age = age

class Family():
    def __init__(self, name=""):
        self.name = name


DROP_VALIDATION_DICT = { 
    Person : ( Family, None ),
    Family : ( None, ),
}

# Custom QTreeWidgetItem
# ------------------------------------------------------------------------------
class CustomTreeNode( QtGui.QTreeWidgetItem ): 
    def __init__( self, parent, data ):
        super( CustomTreeNode, self ).__init__( parent )
        self.data = data

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, value):
        self._data = value
        self.setText( 0, self.data.name )

    def update(self):
        if self.data:
            self.setText(0, self.data.name)


# Custom QTreeWidgetItem
# ------------------------------------------------------------------------------
class CustomTreeWidget( QtGui.QTreeWidget ):
    def __init__(self, parent=None):
        QtGui.QTreeWidget.__init__(self, parent)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.setItemsExpandable(True)
        self.setAnimated(True)
        self.setDragEnabled(True)
        self.setDropIndicatorShown(True)
        self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.setAlternatingRowColors(True)
        # self._dragroot = self.itemRootIndex() # added

        # signals
        self.itemExpanded.connect(self.on_item_expanded)
        self.itemCollapsed.connect(self.on_item_collapsed)

    def set_headers(self, headers=[]):
        self.setColumnCount( len(headers) )
        self.setHeaderLabels( headers )

    def keyPressEvent(self, event):
        if (event.key() == QtCore.Qt.Key_Escape and
            event.modifiers() == QtCore.Qt.NoModifier):
            self.clearSelection()
        else:
            QtGui.QTreeWidget.keyPressEvent(self, event)

    def mousePressEvent(self, event):
        item = self.itemAt(event.pos())
        if item is None:
            self.clearSelection()

        QtGui.QTreeWidget.mousePressEvent(self, event)

    def on_item_expanded(self):
        key_mod = QtGui.QApplication.keyboardModifiers()

        if key_mod == QtCore.Qt.ControlModifier:
            self.expandAll()

    def on_item_collapsed(self):
        key_mod = QtGui.QApplication.keyboardModifiers()

        if key_mod == QtCore.Qt.ControlModifier:
            self.collapseAll()

    # drag-n-drop with constraints
    def dragEnterEvent(self, event):
        item = self.itemAt(event.pos())
        if item is not None and ( isinstance(item.data, Family) ):
        # if event.mimeData().hasUrls():
            event.acceptProposedAction()
        else:
            super(CustomTreeWidget, self).dragEnterEvent(event)

    def dragMoveEvent(self, event):
        print "testing"
        print "moving..."
        item = self.itemAt(event.pos())
        rect = self.visualItemRect(item)
        # QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ForbiddenCursor))

        print rect, event.pos()
        print "Cursor: ", event.pos().y(), event.pos().y()+2
        if event.pos().y() < rect.y()+2:
            print "not inside"
        else:
            print "inside"
        super(CustomTreeWidget, self).dragMoveEvent(event)

    def dropEvent(self, event):
        item = self.itemAt(event.pos())
        if item is not None and ( isinstance(item.data, Family) ):
            super(CustomTreeWidget,self).dropEvent(event)

        else:
            print "ignored"
            event.setDropAction(QtCore.Qt.IgnoreAction)


# UI
# ------------------------------------------------------------------------------
class ExampleWidget(QtGui.QWidget):

    def __init__( self, parent=None ):
        super(ExampleWidget, self).__init__()
        self.initUI()


    def initUI(self):

        # widgets
        self.treewidget = CustomTreeWidget()
        self.treewidget.set_headers( ["items"] )
        self.btn_add_family_tree_node = QtGui.QPushButton("Add Family")
        self.btn_add_person_tree_node = QtGui.QPushButton("Add Person")

        # layout
        self.mainLayout = QtGui.QGridLayout(self)
        self.mainLayout.addWidget(self.btn_add_family_tree_node, 0,0)
        self.mainLayout.addWidget(self.btn_add_person_tree_node, 0,1)
        self.mainLayout.addWidget(self.treewidget, 1,0,1,3)

        # signals
        self.btn_add_family_tree_node.clicked.connect(self.add_family_tree_node_clicked)
        self.btn_add_person_tree_node.clicked.connect(self.add_person_tree_node_clicked)

        # display
        self.resize(300, 400)
        self.show()
        self.center_window(self, True)

        # test data
        self.add_test_families("Roberstons", ["Kevin", "Mindy", "Riley"])
        self.add_test_families("Rodriguez", ["Matt", "Kim", "Stephanie"])

    def add_test_families(self, name, children):
        family = Family( name )
        node = CustomTreeNode( self.treewidget, family )
        node.setExpanded(True)

        # # disable drag and drop flags
        # # QtCore.Qt.ItemIsDragEnabled
        # flags =  QtCore.Qt.ItemIsSelectable | \
        #     QtCore.Qt.ItemIsUserCheckable | \
        #     QtCore.Qt.ItemIsEnabled | \
        #     QtCore.Qt.ItemIsDropEnabled 
        # node.setFlags(flags)

        for i in xrange(len(children)):
            person = Person( children[i] )
            CustomTreeNode( node, person )


    # Functions
    # --------------------------------------------------------------------------
    def add_family_tree_node_clicked(self):
        print "Created new family!"
        roots = [self.treewidget]

        text, ok = QtGui.QInputDialog.getText(self, 'Input Dialog', 'Enter family name:')
        if ok:
            for root in roots:
                family = Family( text )
                node = CustomTreeNode( root, family )
                node.setExpanded(True)
                self.treewidget.itemSelectionChanged.emit()


    def add_person_tree_node_clicked(self):
        print "Created new person!"
        roots = self.treewidget.selectedItems()

        text, ok = QtGui.QInputDialog.getText(self, 'Input Dialog', 'Enter your name:')
        if ok:
            for root in roots:
                person = Person( text )
                node = CustomTreeNode( root, person )
                node.setExpanded(True)
                self.treewidget.itemSelectionChanged.emit()


    def center_window(self, window , cursor=False):
        qr = window.frameGeometry()
        cp = QtGui.QCursor.pos() if cursor else QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        window.move(qr.topLeft())


# __name__
# ------------------------------------------------------------------------------
if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = ExampleWidget()
    sys.exit(app.exec_())

0 个答案:

没有答案