PyQt5模型/视图-一个模型,两个视图

时间:2020-04-27 18:26:25

标签: python model-view-controller pyqt pyqt5

我正在使用PyQt5设计应用程序。我需要在两个表上显示相同的数据,但在每个表上以不同的方式显示。那是: 第一个表是可编辑的。可以编辑几个元素(它们的名称,值等)

enter image description here

但是,第二张表需要在垂直标题上显示第一张表的第一列(元素名称),并且第一张表的一列(在此示例中为第三列)作为唯一行:

(我还没有实现,我为了更好的理解而画了它)

enter image description here

为了使两个表之间的数据保持一致(并且在内部,因为表中的值用于其他操作),我认为使用模型/体系结构是最好的方法。我已经开始为第一个表实现模型(继承QAbstractTableModel),但是对于每个表,此模型类中的方法(数据,rowCount,columnCount,...)应该完全不同。

我应该如何解决这个问题?我应该为第二张表创建自定义View类吗?

2 个答案:

答案 0 :(得分:2)

如果要基于其他模型获得新模型,则可以使用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_())

enter image description here

答案 1 :(得分:1)

设计中缺少的部分是用于完整的modelview-view模型流程的观察者设计模式实现。 您可以实现自己的可观察数据容器,以here的形式绑定到多个视图 或者您可以使用pypi的观察者第3方库。我建议实现自己的可观察数据容器,以更好地管理将来的更改,例如像问题中那样转换表视图。