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:
- 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.
Here is my current attempt:
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_())
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?
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?
Also this question Make QTreeWidgetItem unique among siblings. No body answered.