Проверка действительности PyQt на QTreeWidgetItem - PullRequest
0 голосов
/ 30 января 2019

Я создаю 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 - Использование нескольких валидаторов для делегатов элементов связано, но ответа не дано, толькопредложение в комментарии о том, что нужно подкласс QValidator обрабатывать обнаружение конфликта имен в том же регулярном выражении.Не представляете, как это сделать, валидатор создан и назначен перед этими QTreeWidgetItems, не так ли?

Также этот вопрос Сделайте QTreeWidgetItem уникальным среди братьев и сестер .Никто не ответил.

1 Ответ

0 голосов
/ 31 января 2019

Я нашел решение:

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» я не смогу набрать «c» после «ab», хотя я хотел набрать «abcd».

Я нашел этот вопрос относительно ошибки edit: editting failed, и кажется, что Qt.QueuedConnection делает свое дело.Таким образом, tree.itemChanged подключен к функции проверки дублирования, и если проверка не пройдена, он предлагает пользователю повторно ввести имя еще раз.При желании можно вызвать всплывающую подсказку, уведомляющую о конфликте.

Возможно, это не идеальное решение.

...