Custom dropEvent in TreeWidget: how to find target item (tree item under mouse?)



  • PyQt4 / Python 3

    I'm dragging text from a listwidget to a treewidget, but I need to override the default drag-and-drop behavior because I'm using a custom TreeWidgetItem class. I cannot figure out how to find the tree item currently under the mouse during a dropEvent. Any help would be much appreciaed!

    A simple sample code is below:

    @
    import sys
    from PyQt4.QtGui import *
    from PyQt4.QtGui import *

    class EditScreen(QWidget):
    def init(self):
    super(EditScreen, self).init()
    self.initUI()

    def initUI(self):
        global tree
        global listbox
        self.vbox = QVBoxLayout()
        self.hbox = QHBoxLayout()
        
        
        listbox = QListWidget()
        listbox.setDragEnabled(True)
        listbox.setSelectionMode(QAbstractItemView.ExtendedSelection) 
        for x in range(1,10):
            item = 'Thing' + str(x)
            listbox.addItem(item)
            
        tree = MyTreeWidget()
        tree.setAcceptDrops(True)
        tree.setSelectionMode(QAbstractItemView.ExtendedSelection) 
        for x in range(1,5):
            addnewtreeitem = MyTreeItemClass('Category ' + str(x), toplevel=True)
            addnewtreeitem.setExpanded(True)
        
        question = 'Double-clicking a category in the treewidget (right) calls my "addHere" function,'
        question += '\nwhich adds the selected items (from the left) to the treeview after messing with them a bit.'
        question += '\n\nI would like to drag items over from the listwidget, with exactly the same functionality as the double-click.'
        question += '\nbut I do not understand how to find the target item (underneath the mouse) during a dropEvent.'
        question += '\nI need this target item in order to call my "addHere" function.'
        question += '\n\nI cannot use the standard drag-and-drop behavior because I must use a custom TreeWidgetItem class.'
        
        
        questionlabel = QLabel(question)
        self.hbox.addWidget(listbox)
        self.hbox.addWidget(tree)
        
        
        self.vbox.addWidget(questionlabel)
        
        self.vbox.addLayout(self.hbox)
        
        self.setLayout(self.vbox)
        self.setWindowTitle('How can I make drag-and-drop perform my "addHere" function?')
        self.show()
        
    def keyPressEvent(self, e):        
        if e.key() == Qt.Key_Delete:
            #print('pressed delete key')
            tree.delButtonPressed()
    

    class MyTreeWidget(QTreeWidget):
    def init(self):
    QTreeWidget.init(self)
    self.itemDoubleClicked.connect(self.addHere)

    def delButtonPressed(self):
        for item in self.selectedItems():
            if item.deletable:
                item.parent.removeChild(item)
                MyTreeItemClass.child_list.remove(item)
        
    def addHere(self, clickeditem, column):
        global listbox
        
        for x in listbox.selectedItems():
            if clickeditem.can_add_here == True:
                print('Adding item(s) here', clickeditem.treetext)
                itemtext = x.text()
                newtreeitem = MyTreeItemClass(itemtext, parent=clickeditem)
                clickeditem.setExpanded(False)  # need to use false to counter-act the double-clicking action?
            else:
               print('cannot add to this item')
    

    class MyTreeItemClass(QTreeWidgetItem):
    global tree
    toplevel_list = []
    child_list = []
    def init(self, treetext, toplevel=False, parent=None):
    self.treetext = treetext
    QTreeWidgetItem.init(self, [self.treetext])

        if parent:
            self.parentitem=parent
        
        if toplevel == True:
            self.deletable = False
            self.can_add_here = True
            MyTreeItemClass.toplevel_list.append(self)
            tree.addTopLevelItem(self)
            
        else:
            self.deletable = True
            self.can_add_here = False
            itemnum = int(self.treetext[-1])
            
            if itemnum % 2 == 0:
                self.setForeground(0,QBrush(Qt.blue))
            else:
                self.setForeground(0,QBrush(Qt.red))
    
            if itemnum % 3 == 0:
                self.setBackground(0,QBrush(Qt.lightGray))
    
            if itemnum % 4 == 0:
                self.setBackground(0,QBrush(Qt.black))
                self.setForeground(0,QBrush(Qt.white))
    
            MyTreeItemClass.child_list.append(self)
            self.parentitem.addChild(self)
    

    def main():
    app = QApplication(sys.argv)
    editscreen = EditScreen()
    sys.exit(app.exec_())

    main()
    @



  • "QTreeWidget.itemAt":http://doc.qt.digia.com/qt/qtreewidget.html#itemAt is what your looking for. Try adding the following to your MyTreeWidget class:

    @
    def dropEvent(self, e):
    item=self.itemAt(e.pos())
    if item: self.addHere(item)
    e.accept()
    @

    You might also want to do the following in the constructor to stop the default expand behavior:

    @
    self.setExpandsOnDoubleClick(False)
    @

    Hope this helps ;o)



  • This worked great! Thanks so much.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.