在QTreeWidgetItem上的PyQt有效性检查 [英] PyQt validity check on QTreeWidgetItem

查看:153
本文介绍了在QTreeWidgetItem上的PyQt有效性检查的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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:

  1. 名称只能包含有效字符列表.这已经通过将QRegExpValidator添加到子类QItemDelegate并将新的委托分配给QTreeWidget来实现.
  2. 这个名字不能和它的兄弟姐妹冲突.这是我现在不知道要实现的.
  1. the name can only contain a list of valid characters. This is achieved already by adding a QRegExpValidator to a subclassed QItemDelegate, and assigning the new delegate to the QTreeWidget.
  2. the name can't conflict with its siblings. This I don't know now to achieve.

这是我目前的尝试:

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)会引发错误

In particular, I'm connecting tree.itemChanged.connect(self.checkString), and checkString() checks name conflicts. However, when conflict detected I don't know how to revert to the old name and re-enter into the edit mode and let user rename again. The tree.editItem(item) would throw an error

edit: editing failed

.我想那会再次触发信号并最终陷入无尽的循环?

. I guess that would trigger the signal again and end up in an endless loop?

我找到了 PyQt-使用多个验证器进行项目委托相关,但没有给出答案,只是在注释中提出了一个建议,即应该子类QValidator来处理同一正则表达式中的名称冲突检测.不知道该怎么做,验证器是在那些QTreeWidgetItems之前创建和分配的,不是吗?

I've found PyQt - Using Multiple Validators for Item Delegates related, but no answer is given, only a suggestion in the comment that one should subclass QValidator to handle name conflict detection in the same regex. No idea how to do this, the validator is created and assigned before those QTreeWidgetItems, isn't it?

这个问题也是使QTreeWidgetItem在同级中唯一.没有人回答.

Also this question Make QTreeWidgetItem unique among siblings. No body answered.

推荐答案

我找到了一个解决方案:

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


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'冲突,即使我打算键入'abcd',我也无法在'ab'之后键入'c'.

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'.

我发现了关于edit: editting failed错误的这个问题,并且Qt.QueuedConnection似乎可以解决问题.因此,tree.itemChanged连接到重复检查功能,如果检查失败,它将提示用户再次输入名称.可以选择弹出提示冲突的工具提示.

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.

这篇关于在QTreeWidgetItem上的PyQt有效性检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆