PyQt5 模型/视图 - 一个模型,两个视图
Posted
技术标签:
【中文标题】PyQt5 模型/视图 - 一个模型,两个视图【英文标题】:PyQt5 Model/View - One model, two views 【发布时间】:2020-04-27 18:26:25 【问题描述】:我正在使用 PyQt5 设计一个应用程序。我需要在两个表上显示相同的数据,但在每个表上以不同的方式显示。那是: 第一个表是可编辑的。可以编辑几个元素(它们的名称、值等)
然而,第二个表格需要在垂直标题上显示第一个表格的第一列(元素名称),并将第一个表格的其中一列(在本例中为第三个)作为唯一的行:
(我还没有做到这一点,我画了它以便更好地理解)
为了使两个表之间的数据保持一致(并且在内部,因为表中的值用于其他操作),我认为使用模型/架构是最好的方法。我已经开始为第一个表实现模型(继承 QAbstractTableModel),但是这个模型类中的方法(数据、行计数、列计数...)对于每个表来说应该是非常不同的。
我应该如何解决这个问题?我应该为第二个表创建一个自定义 View 类吗?
【问题讨论】:
【参考方案1】:如果您想获得基于另一个模型的新模型,那么您可以使用 QXProxyModel。在您的特定情况下,您可以使用以下过程转换模型:
使用 QTransposeProxyModel 旋转表格。 使用 hideRow() 隐藏行。 通过实现基于 QIdentityProxyModel 的代理来映射标头。from PyQt5 import QtCore, QtGui, QtWidgets
class CustomProxyModel(QtCore.QIdentityProxyModel):
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return self.sourceModel().index(0, section).data(role)
else:
return 1
return super().headerData(section, orientation, role)
def setSourceModel(self, model):
super().setSourceModel(model)
model.dataChanged.connect(self._on_headerDataChanged)
def _on_headerDataChanged(self, topLeft, bottomRight, roles):
if topLeft.row() <= 0 <= bottomRight.row():
self.headerDataChanged.emit(
QtCore.Qt.Horizontal, topLeft.row(), bottomRight.row()
)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
model = QtGui.QStandardItemModel(3, 4)
datas = (
("Element 1", "2", "3", "4"),
("Another element", "6", "7", "8"),
("Element nr. 3", "10", "11", "12"),
)
for i, r in enumerate(datas):
for j, d in enumerate(r):
it = QtGui.QStandardItem(d)
model.setItem(i, j, it)
proxy = QtCore.QTransposeProxyModel()
proxy.setSourceModel(model)
proxy2 = CustomProxyModel()
proxy2.setSourceModel(proxy)
view1 = QtWidgets.QTableView()
view1.setModel(model)
view2 = QtWidgets.QTableView()
view2.setModel(proxy2)
for r in range(proxy.rowCount()):
if r != 2:
view2.hideRow(r)
w = QtWidgets.QWidget()
lay = QtWidgets.QHBoxLayout(w)
lay.addWidget(view1)
lay.addWidget(view2)
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
【讨论】:
感谢您的回答。尽管最终的实现会比我预期的更复杂,但您的回答将非常有帮助。我有一个问题:在 CustomProxyModel > _on_headerDataChanged 中,发射信号的参数不应该是 topLeft.column(), bottomRight.column() 吗? (而不是 row(),因为这是来自转置模型...@eyllanesc @kru96 它给您带来了麻烦吗? dataChanged信号是模型的典型,即不考虑是否代理。 首先,很抱歉这么长时间才回复...不,我还没有尝试过。我只是在查看您的代码并试图理解它之后问它。一旦我尝试了这一切我会写一个回复,但目前我能够在这个项目上投入很少的时间。【参考方案2】:您的设计中缺少的部分是完整的模型视图-视图模型流的观察者设计模式实现。 您可以实现自己的可观察数据容器以绑定到多个视图here 或者您可以使用 pypi 的观察者 3rd 方库。我建议实现您自己的可观察数据容器,以更好地管理未来的更改,例如像您的问题中那样转置表格视图。
【讨论】:
以上是关于PyQt5 模型/视图 - 一个模型,两个视图的主要内容,如果未能解决你的问题,请参考以下文章