Skip to content Skip to sidebar Skip to footer

Pyqt Validity Check On Qtreewidgetitem

I'm building a QTreeWidget where I'm implementing adding new item and renaming functionality. I'd like to check the validity of the new name given by user, including: the name can

Solution 1:

I've found a solution:

import sys
from PyQt5.QtWidgets import QItemDelegate, QTreeWidget, QVBoxLayout, QLineEdit,\
        QMainWindow, QWidget, QTreeWidgetItem, QApplication
from PyQt5.QtCore import QRegExp, Qt
from PyQt5.QtGui import QRegExpValidator


classTreeWidgetDelegate(QItemDelegate):
    def__init__(self, parent=None):
        QItemDelegate.__init__(self, parent=parent)

    defcreateEditor(self, parent, option, index):
        editor = QLineEdit(parent)
        # allow only these chars
        reg=QRegExp('[A-z0-9\[\]_-]+')
        regvd=QRegExpValidator(reg)
        editor.setValidator(regvd)
        return editor


classMainWindow(QMainWindow):

    def__init__(self):
        super(QMainWindow, self).__init__()
        frame=QWidget()
        self.setCentralWidget(frame)
        hl=QVBoxLayout()
        frame.setLayout(hl)

        self.tree=QTreeWidget(self)
        hl.addWidget(self.tree)

        # assign custom delegate to treewidget
        dele=TreeWidgetDelegate()
        self.tree.setItemDelegate(dele)

        # add treewidgetitemsfor ii inrange(5):
            item=QTreeWidgetItem([str(ii)*3,])
            self.tree.addTopLevelItem(item)

        self.tree.itemDoubleClicked.connect(self.rename)

        # QueuedConnection cures the editting failed issue
        self.tree.itemChanged.connect(self.checkName, Qt.QueuedConnection)

        self.show()

    defgetSiblings(self,item):
        siblings=[self.tree.topLevelItem(ii).data(0,0) for ii in \
                range(self.tree.topLevelItemCount())]
        item_text=item.data(0,0)
        if item_text in siblings:
            siblings.remove(item_text)
        return siblings

    defrename(self):
        item=self.tree.selectedItems()
        if item:
            item=item[0]
            item.setFlags(item.flags() | Qt.ItemIsEditable)
            self.tree.scrollToItem(item)
            self.tree.editItem(item)

    defcheckName(self,item,column):
        text=item.data(0,0)
        siblings=self.getSiblings(item)
        print('checkName: slibings:', siblings)

        if text in siblings:
            print('checkName: ivalid')
            item.setData(0,0,'New_name_needed')
            self.tree.editItem(item)


if __name__ == "__main__":
     app = QApplication(sys.argv)
     form = MainWindow()
     form.show()
     sys.exit(app.exec_())

It's still using a custom delegate to check for invalid characters. I tried adding the sibling conflict check in the delegate's editor, by subclassing QValidator and providing it the current list of siblings. However this would perform on-the-fly validation rather than post-commit validation. For instance when checking for the 'abc' v.s. 'abc' conflict, I won't be able to type 'c' after 'ab', even though I meant to type 'abcd'.

I found this question regarding the edit: editting failed error, and it seems that the Qt.QueuedConnection does the trick. So the tree.itemChanged is connected to a duplication check function, and if it fails the check, it prompts the user to re-enter name again. One can optionally popup a tooltip notifying the conflict.

May not be the ideal solution though.

Post a Comment for "Pyqt Validity Check On Qtreewidgetitem"