当我尝试删除 QTreeView 中项目的最后一个子项时,我的 UI 崩溃而不返回任何错误消息。我看到 this post 给出了一个解决方案,但它对我不起作用,即使我在
index
方法中添加这些行:
if not self.hasIndex(row, column, parent):
return QModelIndex()
所以我尝试使用
QAbstractItemModelTester(self.model, QAbstractItemModelTester.FailureReportingMode.Fatal)
来看看我的模型是否有问题。它返回此错误消息:FAIL! flags == Qt::ItemIsDropEnabled || flags == 0 () returned FALSE (C:\Users\qt\work\qt\qtbase\src\testlib\qabstractitemmodeltester.cpp:373)
首先,我不知道如何修复这个错误,所以如果您有任何想法,欢迎您。其次,我不知道这是否是删除项目的最后一个子项时 UI 崩溃的原因。
我尝试制作一个 MRE,但错误并未显示在其中。 Ui 根本不会崩溃,所以我将其保留在下面,以便您检查是否看到任何我没有看到的错误,并解释了模型中的此错误。
import sys
from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtWidgets import *
from PySide6.QtTest import QAbstractItemModelTester
class MainWindow(QMainWindow):
def __init__(self, parent: QWidget = None):
super().__init__(parent)
self.resize(573, 468)
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.contextMenuEvent)
self.menu : QMenu = QMenu(self)
self.delete_action = self.menu.addAction("Delete")
self.delete_action.triggered.connect(self.delitem)
self.frame = QFrame()
self.setCentralWidget(self.frame)
self.hlayout = QHBoxLayout()
self.frame.setLayout(self.hlayout)
self.view = QTreeView()
self.view.setAlternatingRowColors(True)
self.view.setSelectionBehavior(QAbstractItemView.SelectItems)
self.view.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
self.view.setAnimated(False)
self.view.setAllColumnsShowFocus(True)
self.hlayout.addWidget(self.view)
headers = ["value",'Type','Progress Bar','Test','Test','Test','Test']
self.model = TreeModel(headers, self)
self.view.setModel(self.model)
# QAbstractItemModelTester(self.model, QAbstractItemModelTester.FailureReportingMode.Fatal)
self.view.expandAll()
for column in range(self.model.columnCount()):
self.view.resizeColumnToContents(column)
def delitem(self) :
index: QModelIndex = self.view.currentIndex()
model: QAbstractItemModel = self.model
model.removeRow(index.row(), index.parent())
print('deleted')
def contextMenuEvent(self, event: QContextMenuEvent, point : QPoint = QPoint()) -> None:
selection_model = self.view.selectionModel()
has_selection: bool = not selection_model.selection().isEmpty()
if has_selection :
self.menu.exec(QCursor.pos())
class TreeItem:
def __init__(self, data: list, parent: 'TreeItem' = None):
self.item_data = data
self.parent_item = parent
self.child_items = []
def child(self, number: int) -> 'TreeItem':
if number < 0 or number >= len(self.child_items):
return None
return self.child_items[number]
def last_child(self) -> 'TreeItem':
return self.child_items[-1] if self.child_items else None
def child_count(self) -> int:
return len(self.child_items)
def child_number(self) -> int:
if self.parent_item:
return self.parent_item.child_items.index(self)
return 0
def column_count(self) -> int:
return len(self.item_data)
def data(self, column: int):
if column < 0 or column >= len(self.item_data):
return None
return self.item_data[column]
def insert_children(self, position: int, count: int, columns: int) -> bool:
if position < 0 or position > len(self.child_items):
return False
for row in range(count):
data = [None] * columns
item = TreeItem(data.copy(), self)
self.child_items.insert(position, item)
return True
def insert_columns(self, position: int, columns: int) -> bool:
if position < 0 or position > len(self.item_data):
return False
for column in range(columns):
self.item_data.insert(position, None)
for child in self.child_items:
child.insert_columns(position, columns)
return True
def parent(self):
return self.parent_item
def has_parent(self) -> bool:
if self.parent_item :
return(True)
else :
return(False)
def remove_children(self, position: int, count: int) -> bool:
if position < 0 or position + count > len(self.child_items):
return False
for row in range(count):
self.child_items.pop(position)
return True
def remove_columns(self, position: int, columns: int) -> bool:
if position < 0 or position + columns > len(self.item_data):
return False
for column in range(columns):
self.item_data.pop(position)
for child in self.child_items:
child.remove_columns(position, columns)
return True
def set_data(self, column: int, value):
if column < 0 or column >= len(self.item_data):
return False
self.item_data[column] = value
return True
def __repr__(self) -> str:
result = f"<treeitem.TreeItem at 0x{id(self):x}"
for d in self.item_data:
result += f' "{d}"' if d else " <None>"
result += f", {len(self.child_items)} children>"
return result
def __str__(self) -> str:
result : str = str(self.parent())
for data in self.item_data :
result += ',' + str(data)
return(result)
class TreeModel(QAbstractItemModel):
def __init__(self, headers: list, parent=None):
super().__init__(parent)
self.root_data = headers
self.root_item = TreeItem(self.root_data.copy())
self.setup_model_data(self.root_item)
def columnCount(self, parent: QModelIndex = None) -> int:
return self.root_item.column_count()
def data(self, index: QModelIndex, role: int = None):
if not index.isValid():
return None
if role not in (0,1,2) :
return None
item: TreeItem = self.get_item(index)
return item.data(index.column())
def flags(self, index: QModelIndex) -> Qt.ItemFlags:
if not index.isValid():
return Qt.ItemIsEditable
return Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled | QAbstractItemModel.flags(self, index)
def get_item(self, index: QModelIndex = QModelIndex()) -> TreeItem:
if index.isValid():
item: TreeItem = index.internalPointer()
if item:
return item
return self.root_item
def headerData(self, section: int, orientation: Qt.Orientation,
role: int = Qt.DisplayRole):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.root_item.data(section)
return None
def index(self, row: int, column: int, parent: QModelIndex = QModelIndex()) -> QModelIndex:
# if not self.hasIndex(row, column, parent) :
# return QModelIndex()
if parent.isValid() and parent.column() != 0:
return QModelIndex()
parent_item: TreeItem = self.get_item(parent)
if not parent_item:
return QModelIndex()
child_item: TreeItem = parent_item.child(row)
if child_item:
return self.createIndex(row, column, child_item)
return QModelIndex()
def insertColumns(self, position: int, columns: int,
parent: QModelIndex = QModelIndex()) -> bool:
self.beginInsertColumns(parent, position, position + columns - 1)
success: bool = self.root_item.insert_columns(position, columns)
self.endInsertColumns()
return success
def insertRows(self, position: int, rows: int,
parent: QModelIndex = QModelIndex()) -> bool:
parent_item: TreeItem = self.get_item(parent)
if not parent_item:
return False
self.beginInsertRows(parent, position, position + rows - 1)
column_count = self.root_item.column_count()
success: bool = parent_item.insert_children(position, rows, column_count)
self.endInsertRows()
return success
def parent(self, index: QModelIndex = QModelIndex()) -> QModelIndex:
if not index.isValid():
return QModelIndex()
child_item: TreeItem = self.get_item(index)
if child_item:
parent_item: TreeItem = child_item.parent()
else:
parent_item = None
if parent_item == self.root_item or not parent_item:
return QModelIndex()
return self.createIndex(parent_item.child_number(), 0, parent_item)
def removeColumns(self, position: int, columns: int,
parent: QModelIndex = QModelIndex()) -> bool:
self.beginRemoveColumns(parent, position, position + columns - 1)
success: bool = self.root_item.remove_columns(position, columns)
self.endRemoveColumns()
if self.root_item.column_count() == 0:
self.removeRows(0, self.rowCount())
return success
def removeRows(self, position: int, rows: int,
parent: QModelIndex = QModelIndex()) -> bool:
parent_item: TreeItem = self.get_item(parent)
if not parent_item:
return False
self.beginRemoveRows(parent, position, position + rows - 1)
success: bool = parent_item.remove_children(position, rows)
self.endRemoveRows()
return success
def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
if parent.isValid() and parent.column() > 0:
return 0
parent_item: TreeItem = self.get_item(parent)
if not parent_item:
return 0
return parent_item.child_count()
def setData(self, index: QModelIndex, value, role: int) -> bool:
if role != Qt.EditRole:
return False
item: TreeItem = self.get_item(index)
result: bool = item.set_data(index.column(), value)
if result:
self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole])
return result
def setData2(self, index: QModelIndex, value, role: int) -> bool:
if role != Qt.EditRole:
return False
item: TreeItem = self.get_item(index)
result: bool = item.set_data(index.column(), value)
return result
def setHeaderData(self, section: int, orientation: Qt.Orientation, value,
role: int = None) -> bool:
if role != Qt.EditRole or orientation != Qt.Horizontal:
return False
result: bool = self.root_item.set_data(section, value)
if result:
self.headerDataChanged.emit(orientation, section, section)
return result
def setup_model_data(self, parent: TreeItem):
parents = [parent]
parent : TreeItem = parents[0]
col_count = self.root_item.column_count()
parent.insert_children(parent.child_count(), 1, col_count)
column_data = ['test 1','test 2','test 3','test 4','test 5']
for column in range(len(column_data)):
child = parent.last_child()
child.set_data(column, column_data[column])
for i in range(4) :
child : TreeItem = parent.last_child()
child.insert_children(child.child_count(), 1, col_count)
column_data = ['test 4','test 9','test 4','test 0','test 6']
for column in range(len(column_data)):
child2 = child.last_child()
child2.set_data(column, column_data[column])
def _repr_recursion(self, item: TreeItem, indent: int = 0) -> str:
result = " " * indent + repr(item) + "\n"
for child in item.child_items:
result += self._repr_recursion(child, indent + 2)
return result
def __repr__(self) -> str:
return self._repr_recursion(self.root_item)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
现在下面的代码显示了我所拥有的
setup_model_data method
:
def setup_model_data(self, parent: TreeItem, id_projet):
parents = [parent]
con : Connexion = Connexion()
with con.pool.acquire() as connexion :
with connexion.cursor() as cursor :
for ensemble in cursor.execute("SELECT nom,id_sous_ensemble,id FROM Sous_Ensemble WHERE id_sous_ensemble = 0 AND id_projet = :1 ORDER BY id_sous_ensemble,nom",[id_projet]) :
parent : TreeItem = parents[0]
col_count = self.root_item.column_count()
parent.insert_children(parent.child_count(), 1, col_count)
column_data = [ensemble[0],None,None,-2,ensemble[2]]
for column in range(len(column_data)):
child = parent.last_child()
child.set_data(column, column_data[column])
self.recursiviter(ensemble[2],child)
with connexion.cursor() as cursor1 :
for piece in cursor1.execute("SELECT designation, id_sous_ensemble, id FROM piece WHERE id_sous_ensemble = 0") :
with connexion.cursor() as cursor2 :
for rev_info in cursor2.execute("SELECT id_rev,id_mat FROM link_piece_rev WHERE id_piece = :1 ORDER BY id_rev DESC FETCH NEXT 1 ROWS ONLY",[piece[2]]) :
id_rev = rev_info[0]
id_mat = rev_info[1]
parent.insert_children(parent.child_count(), 1, col_count)
column_data =[piece[0],id_rev,id_mat,-1,piece[2]]
for column in range(len(column_data)):
child = parent.last_child()
child.set_data(column, column_data[column])
def recursiviter(self,id, parent : TreeItem, id_projet = 1) :
con1 : Connexion = Connexion()
with con1.pool.acquire() as connexion1 :
with connexion1.cursor() as cursor2 :
for ensemble in (cursor2.execute("SELECT nom,id_sous_ensemble,id FROM SOUS_ENSEMBLE WHERE id_sous_ensemble = :1 AND id_projet = :2",[id,id_projet])) :
if ensemble :
col_count = self.root_item.column_count()
parent.insert_children(parent.child_count(),1,col_count)
column_data = [ensemble[0],None,None,-2,ensemble[2]]
for column in range(len(column_data)):
child = parent.last_child()
child.set_data(column, column_data[column])
self.recursiviter(ensemble[2],parent.last_child())
else :
return
with connexion1.cursor() as cursor3 :
for piece in cursor3.execute("SELECT designation, id_sous_ensemble, id FROM piece WHERE id_sous_ensemble = :1",[id]) :
if piece :
with connexion1.cursor() as cursor4 :
for rev_info in cursor4.execute("SELECT id_rev,id_mat FROM link_piece_rev WHERE id_piece = :1 ORDER BY id_rev DESC FETCH NEXT 1 ROWS ONLY",[piece[2]]) :
id_rev = rev_info[0]
id_mat = rev_info[1]
col_count = self.root_item.column_count()
parent.insert_children(parent.child_count(), 1, col_count)
column_data =[piece[0],id_rev,id_mat,-1,piece[2]]
for column in range(len(column_data)):
child = parent.last_child()
child.set_data(column, column_data[column])
else :
return
我不知道这是否会对您有帮助,特别是当我从数据库创建模型时使用
setup_model_data
和 recusititer
方法。我按照Qt官方网站给出的exemple来创建我的QTreeView
。我不知道可以给你什么来解决我的问题。请随时在评论中询问任何信息,我会很乐意快速答复。
这方面有什么更新吗? 我有完全相同的问题,并且没有返回码。 很奇怪