在QTreeWidgetItem上的PyQt有效性检查 [英] PyQt validity check on QTreeWidgetItem
问题描述
我正在构建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:
- 名称只能包含有效字符列表.这已经通过将
QRegExpValidator
添加到子类QItemDelegate
并将新的委托分配给QTreeWidget
来实现. - 这个名字不能和它的兄弟姐妹冲突.这是我现在不知道要实现的.
- the name can only contain a list of valid characters. This is achieved already by adding a
QRegExpValidator
to a subclassedQItemDelegate
, and assigning the new delegate to theQTreeWidget
. - 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屋!