代码之家  ›  专栏  ›  技术社区  ›  Jason

QTreeWidgetItem上的PyQt有效性检查

  •  1
  • Jason  · 技术社区  · 7 年前

    我正在构建一个QTreeWidget,在其中实现添加新项目和重命名功能。我想检查用户提供的新名称的有效性,包括:

    1. 名称只能包含有效字符的列表。通过添加一个 QRegExpValidator 到一个子类 QItemDelegate ,并将新代理分配给 QTreeWidget .
    2. 这个名字不能和它的兄弟姐妹冲突。我现在不知道该怎么做。

    以下是我目前的尝试:

    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
    
    
    class TreeWidgetDelegate(QItemDelegate):
        def __init__(self, parent=None):
            QItemDelegate.__init__(self, parent=parent)
    
        def createEditor(self, parent, option, index):
            editor = QLineEdit(parent)
            reg=QRegExp('[A-z0-9\[\]_-]+')
            vd=QRegExpValidator(reg)
    
            editor.setValidator(vd)
            return editor
    
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super(self.__class__, self).__init__()
            frame=QWidget()
            self.setCentralWidget(frame)
            hl=QVBoxLayout()
            frame.setLayout(hl)
    
            self.tree=QTreeWidget(self)
            mydele=TreeWidgetDelegate()
            self.tree.setItemDelegate(mydele)
            hl.addWidget(self.tree)
    
            # add treewidgetitems
            for ii in range(5):
                item=QTreeWidgetItem([str(ii),])
                self.tree.addTopLevelItem(item)
    
            self.tree.itemDoubleClicked.connect(self.rename)
            self.tree.itemChanged.connect(self.checkString)
    
            dele=self.tree.itemDelegate()
            print('dele',dele)
    
            self.show()
    
        def rename(self):
            item=self.tree.selectedItems()
            if item:
                item=item[0]
                item.setFlags(item.flags() | Qt.ItemIsEditable)
                self.tree.scrollToItem(item)
                self.tree.editItem(item)
    
        def checkString(self,item,column):
            text=item.data(0,column)
            print('newname:',text)
    
            siblings=[self.tree.topLevelItem(ii).data(0,0) for ii in \
                    range(self.tree.topLevelItemCount())]
            print('siblings:',siblings)
    
            if text in siblings:
                print('invalid name')
    
                # this gives "edit: editing failed"
                self.tree.editItem(item)
    
    
    if __name__ == "__main__":
         app = QApplication(sys.argv)
         form = MainWindow()
         form.show()
         sys.exit(app.exec_())
    

    特别是,我正在连接 tree.itemChanged.connect(self.checkString) checkString() 检查名称冲突。然而,当检测到冲突时,我不知道如何恢复到旧名称并重新进入编辑模式,让用户再次重命名。这个 tree.editItem(item) 会犯错误吗

    edit: editing failed
    

    .我想这会再次触发信号,并以无休止的循环结束?

    我找到了 PyQt - Using Multiple Validators for Item Delegates 相关的,但没有给出答案,只是在评论中建议一个人应该子类化 QValidator 在同一个正则表达式中处理名称冲突检测。不知道怎么做,验证器是在这些之前创建和分配的 QTreeWidgetItems 是吗?

    还有这个问题 Make QTreeWidgetItem unique among siblings .没有人回答。

    1 回复  |  直到 7 年前
        1
  •  0
  •   Jason    7 年前

    我找到了一个解决方案:

    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
    
    
    class TreeWidgetDelegate(QItemDelegate):
        def __init__(self, parent=None):
            QItemDelegate.__init__(self, parent=parent)
    
        def createEditor(self, parent, option, index):
            editor = QLineEdit(parent)
            # allow only these chars
            reg=QRegExp('[A-z0-9\[\]_-]+')
            regvd=QRegExpValidator(reg)
            editor.setValidator(regvd)
            return editor
    
    
    class MainWindow(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 treewidgetitems
            for ii in range(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()
    
        def getSiblings(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
    
        def rename(self):
            item=self.tree.selectedItems()
            if item:
                item=item[0]
                item.setFlags(item.flags() | Qt.ItemIsEditable)
                self.tree.scrollToItem(item)
                self.tree.editItem(item)
    
        def checkName(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_())
    

    它仍在使用自定义委托检查无效字符。我试图通过子类化在代理编辑器中添加兄弟冲突检查 QValidator 并向其提供当前的兄弟姐妹名单。但是,这将执行即时验证,而不是提交后验证。例如,在检查“abc”与“abc”冲突时,我将无法在“ab”之后键入“c”,即使我想键入“abcd”。

    我发现 this question 关于 edit: editting failed 错误,看起来 Qt.QueuedConnection 成功了。所以 tree.itemChanged 连接到复制检查功能,如果检查失败,则会提示用户再次输入名称。可以选择弹出工具提示,通知冲突。

    但这可能不是理想的解决方案。