Reputation: 391
I'm designing an application using PyQt5. I need to display the same data on two tables, but in a different way on each table. That is: First table is editable. Several elements can be edited (Their names, values etc.)
Second table, however, needs to display the first column of the first table (element name) on the vertical headers and one of the columns of the first table (third one, in this example) as the only row:
(I haven't achieved this, i drew it for better understanding)
For the Data to be consistent between the two tables (and internally, since the values in the tables are used for other operations) I think using a Model/Architecture is the best way to go. I have started implementing the Model (inheriting QAbstractTableModel) for the first table, but the methods in this Model Class (data, rowCount, columnCount, ...) should be very different for each table.
How should I approach this problem? Should I create a custom View class for the second table?
Upvotes: 2
Views: 1099
Reputation: 243973
If you want to get a new model based on another model then you can use the QXProxyModel. In your particular case you can transform the model using the following procedure:
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_())
Upvotes: 2
Reputation: 1052
missing part in your design is observer design pattern implementation for a full-fledged modelview-view model flow. you may implement your own observable data container to be binded to multiple views as here or you may use a observer 3rd party library from pypi. I suggest to implement your own observable data container to better manage future changes such as transposing the table view like in your question.
Upvotes: 1