【问题标题】:PyQt validity check on QTreeWidgetItemQTreeWidgetItem 上的 PyQt 有效性检查
【发布时间】:2019-01-30 14:41:57
【问题描述】:

我正在构建一个 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。没有人回答。

【问题讨论】:

    标签: python pyqt pyqt5 qtreewidget qtreewidgetitem


    【解决方案1】:

    我找到了解决办法:

    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”v.s. 时。 'abc' 冲突,我将无法在 'ab' 之后输入 'c',即使我打算输入 'abcd'。

    我发现this questionedit: editting failed 错误有关,看来Qt.QueuedConnection 可以解决问题。所以tree.itemChanged连接了一个重复检查功能,如果检查失败,它会提示用户重新输入名称。可以选择弹出一个提示冲突的工具提示。

    虽然可能不是理想的解决方案。

    【讨论】:

      猜你喜欢
      • 2012-08-21
      • 1970-01-01
      • 2014-02-21
      • 2011-06-06
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      相关资源
      最近更新 更多