I'm started to learning Qt4 Model/View Programming and I have beginner question.
I have simple application which show sqlite table in QTableView
:
class Model(QtSql.QSqlTableModel):def __init__(self, parent=None):super(Model, self).__init__(parent)self.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)self.setTable("test")self.select()class App(QtGui.QMainWindow):def __init__(self, model):QtGui.QMainWindow.__init__(self)self.ui = Ui_MainWindow()self.ui.setupUi(self)self.ui.tableView.setModel(model)if __name__ == "__main__":myDb = QtSql.QSqlDatabase.addDatabase("QSQLITE")myDb.setDatabaseName("test.db")if not myDb.open():print 'FIXME'model = Model()app = QtGui.QApplication(sys.argv)window = App(model)window.show()sys.exit(app.exec_())
Here how database looks like:
sqlite> create table test (a INTEGER, b INTEGER, c STRING);
sqlite> insert into test VALUES(1, 2, "xxx");
sqlite> insert into test VALUES(6, 7, "yyy");
So I'm getting something like:
+---+---+-----+
| a | b | c |
+---+---+-----+
| 1 | 2 | xxx |
+---+---+-----+
| 6 | 7 | yyy |
+---+---+-----+
Is it possible to modify Model
to have in QTableView
something like virtual column? For example something like:
+---+---+-----+-----+
| a | b | sum | c |
+---+---+-----+-----+
| 1 | 2 | 3 | xxx |
+---+---+-----+-----+
| 6 | 7 | 13 | yyy |
+---+---+-----+-----+
Or maybe I should do it in some other way?
Yes, you can do that. Although @BrtH's answer is relevant, models are tricky and it's easy to get lost. So I thought a more case in point example would be better.
Personally, I'd use a proxy model derived from QAbstractProxyModel
. But, in your case reimplementing QSqlTableModel
is also feasible. Below is an implementation for your goal. Note that, it's essential for you to know basics of Model/View methodology so that you understand what each method does.
class Model(QtSql.QSqlTableModel):def __init__(self, parent=None):super(Model, self).__init__(parent)self.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)self.setTable("test")self.select()def columnCount(self, parent=QtCore.QModelIndex()):# this is probably obvious# since we are adding a virtual column, we need one more columnreturn super(Model, self).columnCount()+1def data(self, index, role=QtCore.Qt.DisplayRole):if role == QtCore.Qt.DisplayRole and index.column()==2:# 2nd column is our virtual column.# if we are there, we need to calculate and return the value# we take the first two columns, get the data, turn it to integer and sum them# [0] at the end is necessary because pyqt returns value and a bool# http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qvariant.html#toIntreturn sum(self.data(self.index(index.row(), i)).toInt()[0] for i in range(2))if index.column() > 2:# if we are past 2nd column, we need to shift it to left by one# to get the real valueindex = self.index(index.row(), index.column()-1)# get the value from base implementationreturn super(Model, self).data(index, role)def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):# this is similar to `data`if section==2 and orientation==QtCore.Qt.Horizontal and role==QtCore.Qt.DisplayRole:return 'Sum'if section > 2 and orientation==QtCore.Qt.Horizontal:section -= 1return super(Model, self).headerData(section, orientation, role)def flags(self, index):# since 2nd column is virtual, it doesn't make sense for it to be Editable# other columns can be Editable (default for QSqlTableModel)if index.column()==2:return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabledreturn QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditabledef setData(self, index, data, role):# similar to data.# we need to be careful when setting data (after edit)# if column is after 2, it is actually the column before thatif index.column() > 2:index = self.index(index.row(), index.column()-1)return super(Model, self).setData(index, data, role)