PDA

View Full Version : Change color of a row of a QSqlQueryModel (QTableView)?



panoss
29th May 2017, 12:33
I 'm trying to change the color of rows in a QTableView which has a QSqlQueryModel as it's model.

Here is a compilable code sample in python:

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)#QtGui.QStandardItemMode l(0, 2)
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 am I doing wrong?

panoss
29th May 2017, 17:54
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?

d_stranz
29th May 2017, 22:26
But how can I make it paint only the rows I want?
How can I pass the color to function data?

You can't pass any additional parameters to the data() method. If you need to set the color on an item-by-item basis, then you need to look at the row and column of the QModelIndex argument. Unless you can decide based on the row and column alone, generally you will need to implement an extra data structure in your custom model where you can look up the color for the index.

panoss
30th May 2017, 09:50
Finally, I ended in a, relatively, good solution:


from PyQt4 import QtGui, QtCore, QtSql
#from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

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');")
query.exec("INSERT INTO games (hometeam, visitorteam) VALUES ('NonWinners', 'Loosers');")
query.exec("INSERT INTO games (hometeam, visitorteam) VALUES ('North', 'South');")
query.exec("INSERT INTO games (hometeam, visitorteam) VALUES ('East', 'west');")

# set the model
model = CustomSqlModel(self)#QtGui.QStandardItemModel(0, 2)
self.setModel(model)
model.setQuery("SELECT * FROM games")

# paint first two rows
model.setRowsToBeColored([0,3])
for i in range(0, 2):
index = QtCore.QModelIndex(model.index(i, 0))
model.setData(index, QtCore.Qt.red, QtCore.Qt.BackgroundRole)


class CustomSqlModel(QtSql.QSqlQueryModel):
def __init__(self, dbcursor=None):
super(CustomSqlModel, self).__init__()
def setRowsToBeColored(self, rows):
self.rows = rows

def data(self, index, role):
row = index.row()
print("row=", row, " row in self.rows=", row in self.rows)
if role == QtCore.Qt.BackgroundRole and row in self.rows:
return QBrush(QtCore.Qt.red)
return QtSql.QSqlQueryModel.data(self, index, role);


if __name__ == "__main__":
main()


Added after 14 minutes:

I have this c++ code, I want to 'translate' it (to python of course):


#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;
};


How do I translate this line?

const qint64 hashKey = (static_cast<qint64>(index.row()) << 32) | static_cast<qint64>(index.column());

Ok, I translated it to:


hashKey = index.row() << 32 | index.column()

Seems ok.

But how about this one?

auto tableIter = m_extraRoles.constFind(hashKey);