Change color of a row of a QSqlQueryModel (QTableView)?
-
I 'm trying to change the color of rows in a QTableView which has a QSqlQueryModel as it's model, but it doesn't work.
This is the python compilable code:import sys from PyQt4 import QtGui, QtCore, QtSql def main(): app = QtGui.QApplication(sys.argv) w = MyWindow() w.show() sys.exit(app.exec_()) class MyWindow(QtGui.QTableView): def __init__(self, *args): QtGui.QTableView.__init__(self, *args) # connect to db (if doesn't exist, it's auto-created) self.db = QtSql.QSqlDatabase.addDatabase('QSQLITE') self.db.setDatabaseName('test.db') self.db.open() #create a table in db and add some data query = QtSql.QSqlQuery() query.exec_("DROP TABLE IF EXISTS games") query.exec_("CREATE TABLE games(id INTEGER PRIMARY KEY, hometeam TEXT, visitorteam TEXT) ") query.exec("INSERT INTO games (hometeam, visitorteam) VALUES ('Star', 'Eagles')") query.exec("INSERT INTO games (hometeam, visitorteam) VALUES ('Best team', 'Reds');") # set the model model = QtSql.QSqlQueryModel(self) self.setModel(model) model.setQuery("SELECT * FROM games") # paint first two rows for i in range(0, 2): model.setData(model.index(i, 0), QtGui.QBrush(QtCore.Qt.red), QtCore.Qt.BackgroundRole) model.setData(model.index(i, 1), QtGui.QBrush(QtCore.Qt.red), QtCore.Qt.BackgroundRole) if __name__ == "__main__": main()
What might be the problem?
-
I subclassed it:
class ColorfullSqlQueryModel(QtSql.QSqlQueryModel): def __init__(self, dbcursor=None): super(ColorfullSqlQueryModel, self).__init__() def data(self, QModelIndex, role=None): v = QtSql.QSqlQueryModel.data(self, QModelIndex, role); if role == QtCore.Qt.BackgroundRole: return QtGui.QColor(QtCore.Qt.yellow) return (v);
It works!! Turns all rows to yellow!
But how can I make it paint ;only the rows I want?
How can I pass the color to function data? -
@Panoss You are on the right track. That's exactly how the interface should be used. To your second question, your model has to decide, which of the background has to what color. To achieve this, you have to pass the information to the model. There is no unified way to do this. But here are two possibilities:
Either use setData, which comes with your model:
bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
http://doc.qt.io/qt-5/qabstractitemmodel.html#setData
Or you add and call some function designed by yourself. Anyway, if you change the underlying data after it is displayed, you have to signal the view that it has to update its content.
You may read up on that here (dataChanged or modelReset):
http://doc.qt.io/qt-5/qabstractitemmodel.html -
I changed function data to setData which has a parameter called 'p_object' and I use it for color:
def setData(self, QModelIndex, p_object, role=None): v = QtSql.QSqlQueryModel.data(self, QModelIndex, role); if role == QtCore.Qt.BackgroundRole: self.dataChanged.emit(QModelIndex, QModelIndex) return QtGui.QColor(p_object) return (v);
I call it this way:
model.setData(index, QtCore.Qt.red, QtCore.Qt.BackgroundRole)
But it's not working, maybe the emit Signal is not correct.
-
@Panoss That was exactly how it works in my application. Maybe they just support the dataChanged signal, which you used earlier. But I just saw, that you do not specify the correct arguments. You have to send the signal like:
dataChanged( ModelIndex to first item changed, ModelIndex to last item changed )
Model indices can be created with:
QModelIndex QAbstractItemModel::index(int row, int column, const QModelIndex &parent = QModelIndex()) const -
@c64zottel said in Change color of a row of a QSqlQueryModel (QTableView)?:
@Panoss That was exactly how it works in my application.
Maybe you could post the code from your setData function?
And I will 'translate' it in python. -
@Panoss I don't have a setData function. The code I use for reset is:
void BattlefieldModel::refresh( const QSet< LinearCoordinate > & indices ) { for( int lc : indices ) { QModelIndex a = index( lc ); emit dataChanged( a, a ); } }
But this is only ok because, ... well lets not get into it.
The arguments of index ( row, column) is just the position you want to update. Since I have just rows, I update just rows.
-
First of all, let me start by saying that using a
QStandardItemModel
filled manually from aQSqlQuery
is probably the fastest way to go.having said that you can use this proxy model to make it work:
Sorry for C++
#include <QIdentityProxyModel> class ExtraRolesProxyModel : public QIdentityProxyModel { Q_OBJECT Q_DISABLE_COPY(ExtraRolesProxyModel) public: explicit ExtraRolesProxyModel(QObject* parent=Q_NULLPTR) :QIdentityProxyModel(parent) {} virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE{ const qint64 hashKey = (static_cast<qint64>(index.row()) << 32) | static_cast<qint64>(index.column()); auto tableIter = m_extraRoles.constFind(hashKey); if(tableIter==m_extraRoles.constEnd()) return QIdentityProxyModel::data(index,role); auto roleIter = tableIter.value().constFind(role); if(roleIter==tableIter.value().constEnd()) return QIdentityProxyModel::data(index,role); return roleIter.value(); } virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE { if(!index.isValid()) return false; Q_ASSERT(index.model()==this); const qint64 hashKey = (static_cast<qint64>(index.row()) << 32) | static_cast<qint64>(index.column()); if(value.isValid()){ m_extraRoles[hashKey][role] = value; emit dataChanged(index,index,QVector<int>(1,role)); return true; } auto tableIter = m_extraRoles.find(hashKey); if(tableIter==m_extraRoles.end()) return false; auto roleIter = tableIter.value().find(role); if(roleIter==tableIter.value().end()) return false; tableIter.value().erase(roleIter); if(tableIter.value().isEmpty()) m_extraRoles.erase(tableIter); emit dataChanged(index,index,QVector<int>(1,role)); return true; } private: QHash<qint64,QHash<qint32,QVariant> > m_extraRoles; };
-
-
I translated it likes this: (I get no error on this line, seems ok)
hashKey = index.row() << 32 | index.column()
But this one;
auto tableIter = m_extraRoles.constFind(hashKey);
Converted to python:
tableIter = m_extraRoles.constFind(hashKey)
Says variable m_extraRoles 'Unresolved reference'. It has not been declared anywhere.
-
Yes, you 're right VRonin:
tableIter = self.m_extraRoles.constFind(hashKey)
This shows no underlined code in Pychrm (if there were any errors, it would be underlined. With red color.)
But this look very hard to convert to python:
Q_ASSERT(index.model()==this)
Q_ASSERT?? omg
-