我正在尝试使用代理模型来添加将对源模型中的项目进行分组的虚拟行。我几乎有一些“工作”的东西,但我无法选择重新定位到虚拟行的项目。
下面是我用来制作此功能原型的简单测试用例的代码。这是基于数周在互联网上搜索线索甚至 AI 建议的结果,但它仍然混淆了这里实际发生的事情。
#!/usr/bin/env python
from Qt import QtCore, QtGui, QtWidgets
class VirtualRowProxyModel(QtCore.QSortFilterProxyModel):
# Some internal id indicating when its a virtual row
IS_VIRTUAL = 5
def __init__(self, parent=None):
super(VirtualRowProxyModel, self).__init__(parent)
def flags(self, index):
return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
def mapToSource(self, proxyIndex):
if self._isVirtualRow(proxyIndex):
return QtCore.QModelIndex()
return super(VirtualRowProxyModel, self).mapToSource(proxyIndex)
def mapFromSource(self, sourceIndex):
row = sourceIndex.row()
column = sourceIndex.column()
parent = sourceIndex.parent()
if row == 0 and not parent.isValid():
return self.index(0, 0).child(row, column)
return super(VirtualRowProxyModel, self).mapFromSource(sourceIndex)
def hasChildren(self, parent=QtCore.QModelIndex()):
if self._isVirtualRow(parent):
return True
return super(VirtualRowProxyModel, self).hasChildren(parent)
def index(self, row, column, parent=QtCore.QModelIndex()):
if not parent.isValid():
return self.createIndex(row, column, self.IS_VIRTUAL)
return super(VirtualRowProxyModel, self).index(row, column, parent)
def parent(self, index):
if not index.isValid():
return QtCore.QModelIndex()
if self._isVirtualRow(index):
return QtCore.QModelIndex()
sourceIndex = self.mapToSource(index)
if not sourceIndex.parent().isValid():
return self.index(0, 0)
return super(VirtualRowProxyModel, self).parent(index)
def data(self, proxyIndex, role=QtCore.Qt.DisplayRole):
# if role == QtCore.Qt.DisplayRole:
# sourceIndex = self.mapToSource(proxyIndex)
# return str([sourceIndex.row(), sourceIndex.data(),
# proxyIndex.isValid(), proxyIndex.parent().isValid(), sourceIndex.parent().isValid()])
if self._isVirtualRow(proxyIndex):
if role == QtCore.Qt.DisplayRole:
sourceIndex = self.mapToSource(proxyIndex)
return "-VIRTUAL ROW-"
if role == QtCore.Qt.UserRole:
return True
return None
return super(VirtualRowProxyModel, self).data(proxyIndex, role)
def rowCount(self, parent=QtCore.QModelIndex()):
if not parent.isValid():
return 3
if self._isVirtualRow(parent):
if parent.row() == 0:
return 1
return 0
return self.sourceModel().rowCount(self.mapToSource(parent))
def _isVirtualRow(self, index):
return index.isValid() and index.internalId() == self.IS_VIRTUAL
def itemRow(name):
return [QtGui.QStandardItem(name)]
class Ctrl(QtCore.QObject):
def __init__(self, parent=None):
super(Ctrl, self).__init__(parent)
self.window = QtWidgets.QFrame()
layout = QtWidgets.QHBoxLayout(self.window)
self.view = QtWidgets.QTreeView()
self.view.setAlternatingRowColors(True)
model = QtGui.QStandardItemModel()
row1 = itemRow("A")
model.appendRow(row1)
row2 = itemRow("B")
row1[0].appendRow(row2)
row3 = itemRow("C")
row2[0].appendRow(row3)
self.proxy = VirtualRowProxyModel()
self.proxy.setSourceModel(model)
self.view.setModel(self.proxy)
self.view.expandAll()
layout.addWidget(self.view)
if __name__ == '__main__':
app = QtWidgets.QApplication([])
app.setStyle("fusion")
ctrl = Ctrl()
window = ctrl.window
window.resize(600, 300)
window.show()
window.raise_()
app.exec_()
如果你运行这个,项目“A”在一个虚拟行下重新定位,但它是不可选择的。但是,B和C是可选的。
我不确定这种一般方法是否正确,所以如果您对此有更好的建议,请告诉我。我发现了一些对项目模型进行分组的代理模型的 C++ 示例,但是它们非常大并且也让我感到困惑。 谢谢!