I am using PySide6 to build a UI with a QTreeView that allows users to select a single item from a hierarchy. I have implemented the QStandardItemModel with user-checkable items, and I am updating the check state of the items in response to user input.
However, after the first time an item is checked, the program crashes with the error "RuntimeError: Internal C++ object (PySide6.QtGui.QStandardItem) already deleted."
I have reduced the code to a minimal example, which follows:
from PySide6.QtWidgets import QDialog, QPushButton, QWidget, QLineEdit
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QSizePolicy, QTreeView
from PySide6.QtGui import QIcon, QStandardItemModel, QStandardItem
from PySide6.QtCore import Qt
class MinimalModel(QStandardItemModel):
def __init__(self, parent=None):
super(MinimalModel, self).__init__(parent)
self.root_item = self.invisibleRootItem()
for i in range(2):
item = QStandardItem("parent " + str(i))
item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
item.setCheckState(Qt.Unchecked)
self.root_item.appendRow(item)
parentItem = item
for j in range(4):
item = QStandardItem("item "+ str(j))
item.setFlags(item.flags() | Qt.ItemIsUserCheckable | Qt.ItemNeverHasChildren)
item.setCheckState(Qt.Unchecked)
parentItem.appendRow(item)
class TreeWidgetSingleSelector(QTreeView):
executing = False
def __init__(self, model):
super().__init__()
self.setModel(model)
self.setHeaderHidden(True)
self.model().dataChanged.connect(self.on_check_state_changed)
def on_check_state_changed(self, index, column):
if self.executing:
return
self.executing = True
# rest of the method code
item = self.model().itemFromIndex(index)
root = self.model().root_item # invisibleRootItem()
for i in range(root.rowCount()):
root.child(i).setCheckState(Qt.Unchecked)
if root.child(i).hasChildren():
for j in range(root.child(i).rowCount()):
root.child(i).child(j).setCheckState(Qt.Unchecked)
item.setCheckState(Qt.Checked)
self.executing = False
class TreeWidgetSingleSelectorWindow(QDialog):
def __init__(self, model, line_widget):
super().__init__()
self.model = model
self.tree = TreeWidgetSingleSelector(self.model)
self.line_widget = line_widget
self.setWindowTitle("Select Single Item")
layout = QVBoxLayout()
layout.addWidget(self.tree)
save_button = QPushButton("Select Item")
save_button.clicked.connect(self.save_item)
h_lout = QHBoxLayout()
h_lout.addStretch(1)
h_lout.addWidget(save_button)
layout.addLayout(h_lout)
self.setLayout(layout)
self.finished.connect(self.deleteLater)
def save_item(self):
if self.tree.model().rowCount() > 0:
items = [self.tree.model().root_item.child(i) for i in range(self.tree.model().root_item.rowCount())]
for item in items:
for i in range(item.rowCount()):
if item.child(i).checkState() == Qt.Checked:
self.line_widget.clear()
self.line_widget.setText(item.text() + "." + item.child(i).text())
self.accept()
def closeEvent(self, event):
# Clean up the tree views when the main window is closed
self.tree.deleteLater()
event.accept()
class LineEditTreeSelector(QWidget):
def __init__(self, model):
super().__init__()
self.model = model
self.line_edit = QLineEdit()
button = QPushButton()
button.setFixedWidth(20)
button.setFixedHeight(20)
button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
button.setIcon(QIcon("art/add_24.png"))
layout = QHBoxLayout(self)
layout.addWidget(button)
layout.addWidget(self.line_edit)
layout.setSpacing(0)
button.clicked.connect(self.on_button_clicked)
def on_button_clicked(self):
tree_selector = TreeWidgetSingleSelectorWindow(self.model, self.line_edit)
tree_selector.exec()
def get_text(self):
return self.line_edit.text()
class scatterplot_widget(QWidget):
def __init__(self, model):
QWidget.__init__(self)
vertical_box = QVBoxLayout(self)
self.tree_selector_x = LineEditTreeSelector(model)
self.tree_selector_y = LineEditTreeSelector(model)
vertical_box.addWidget(self.tree_selector_x)
vertical_box.addWidget(self.tree_selector_y)
if __name__ == '__main__':
from PySide6.QtWidgets import QApplication
import sys
# creating application
app = QApplication(sys.argv)
model = MinimalModel()
main = scatterplot_widget(model)
# showing the window
main.show()
# loop
sys.exit(app.exec_())
Any ideas? Thanks in advance.
source https://stackoverflow.com/questions/76076681/standard-item-already-deleted-from-model-when-opening-qtreeview-for-the-second-t
Comments
Post a Comment