QTreeWidgetItem的PyQt有效性检查

2024-10-01 07:28:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在构建一个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)将抛出一个错误

^{pr2}$

一。我想这会再次触发信号,最终形成一个无休止的循环?在

我发现了PyQt - Using Multiple Validators for Item Delegates相关,但没有给出答案,只是在注释中建议应该将QValidator子类化,以便在同一个regex中处理名称冲突检测。不知道怎么做,验证器是在那些QTreeWidgetItems之前创建和分配的,不是吗?在

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


Tags: importself名称treeinitdefitemparent
1条回答
网友
1楼 · 发布于 2024-10-01 07:28:15

我找到了一个解决方案:

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错误,似乎{}起了作用。因此,tree.itemChanged连接到一个重复检查函数,如果检查失败,它会提示用户重新输入名称。可以选择弹出一个工具提示来通知冲突。在

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

相关问题 更多 >