Python Forum
Change color of a row of a QTableView?
Thread Rating:
  • 1 Vote(s) - 1 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Change color of a row of a QTableView?
#1
How can I change the color of a row of QTableView which has as model a QStandardItemModel?

I tried this with no success:
index = self.games_model.index(0, 0)
model.setData(index, QtCore.Qt.red, QtCore.Qt.BackgroundRole)
model.emit(QtCore.SIGNAL('dataChanged(QModelIndex)'), index)
Reply
#2
I changed the 'QtCore.Qt.red' to 'QBrush(Qt.red)' and works!

Here is a small working example:

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

def main():
   app = QApplication(sys.argv)
   w = MyWindow()
   w.show()
   sys.exit(app.exec_())

class MyWindow(QTableView):
   def __init__(self, *args):
       QTableView.__init__(self, *args)

       model = QtGui.QStandardItemModel(0, 2)
       self.setModel(model)

       for i in range(0,6):
           newRow = model.rowCount();
           model.insertRow(newRow);

       # paint first two rows
       for i in range(0, 2):
           model.setData(model.index(i, 0), QBrush(Qt.red), QtCore.Qt.BackgroundRole)
           model.setData(model.index(i, 1), QBrush(Qt.red), QtCore.Qt.BackgroundRole)


if __name__ == "__main__":
   main()
But I do have a question:
when I comment out the line 'from PyQt4.QtCore import *', I get an error 'Qt unresolved reference' even though I have the line 'from PyQt4 import QtGui, QtCore'.
So, what is the proper way to import QtCore without having to import it twice?
Reply
#3
It's good to get rid of import *.
It's annoying that many think that * is okay when using a GUI framework,it's really not Angry

So have to add QtGui, QtCore to all plasses * has taken it away.
Don't like to see main first in code.
from PyQt4 import QtGui, QtCore
import sys

class MyWindow(QtGui.QTableView):
   def __init__(self, *args):
       QtGui.QTableView.__init__(self, *args)
       model = QtGui.QStandardItemModel(0, 2)
       self.setModel(model)
       for i in range(0, 6):
           newRow = model.rowCount()
           model.insertRow(newRow)

       # 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)

def main():
   app = QtGui.QApplication(sys.argv)
   w = MyWindow()
   w.show()
   sys.exit(app.exec_())

if __name__ == "__main__":
   main()
Reply
#4
I 'm trying to do the same with QSqlQueryModel but it doesn't work!

Here is a compilable code sample:
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.QStandardItemModel(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 could be the problem?
Reply
#5
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?
Reply
#6
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 = ColorfullSqlQueryModel(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 ColorfullSqlQueryModel(QtSql.QSqlQueryModel):
    def __init__(self, dbcursor=None):
        super(ColorfullSqlQueryModel, 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()
Reply
#7
I 'm trying to 'translate' c++ to python.
With some help from qt forum, I got to this (it's compilable):

from PyQt4 import QtGui, QtCore, QtSql
from PyQt4.QtCore import QModelIndex, QByteArray, QDataStream, QIODevice
from PyQt4.QtGui import *
import sys

QString = type("")
from past.builtins import unicode


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 = QtSql.QSqlQueryModel(self)
       model.setQuery("SELECT * FROM games")

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

       # create the proxy model
       proxy_model = ExtraRolesProxyModel(self)  # QtGui.QStandardItemModel(0, 2)
       # set the proxy 's source
       proxy_model.setSourceModel(model)
       # set the proxy as TableView 's source
       self.setModel(proxy_model)

class ExtraRolesProxyModel(QIdentityProxyModel):
   def __init__(self, dbcursor=None):
       super(ExtraRolesProxyModel, self).__init__()
       self.m_extraRoles = dict()

   def data(self, index, role):
       if role == QtCore.Qt.BackgroundRole: role_str = "BackgroundRole"
       if role == QtCore.Qt.DisplayRole: role_str = "DisplayRole"
       print("ExtraRolesProxyModel data was called row=", index.row(), " role=", role)
       hashKey = QByteArray()
       keyStream = QDataStream(hashKey, QIODevice.WriteOnly)
       keyStream.writeInt32(index.row())
       keyStream.writeInt32(index.column())
       keyStream.writeInt32(role)
       #if self.m_extraRoles.has_key(hashKey):
       if hashKey in self.m_extraRoles:
           hashKey = unicode([QString(u'hashKey')])
           return self.m_extraRoles[hashKey]
       return QIdentityProxyModel.data(self, index, role)


   def setData(self, index, value, role=None):
       print("ExtraRolesProxyModel setData was called=")
       if not index.isValid():
           return False
       hashKey = QByteArray()
       keyStream = QDataStream(hashKey, QIODevice.WriteOnly)
       keyStream.writeInt32(index.row())
       keyStream.writeInt32(index.column())
       keyStream.writeInt32(role)
       print("value=", value)
       if value.isValid():
           self.m_extraRoles[hashKey] = value
           self.dataChanged.emit(index, index)
           return True
       #if self.m_extraRoles.has_key(hashKey):
       if hashKey not in self.m_extraRoles:
           del self.m_extraRoles[hashKey]
           self.dataChanged.emit(index, index)
           return True
       return False

if __name__ == "__main__":
   main()
The original c++ code for the class ExtraRolesProxyModel is this:
   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;
};
Well, python code does not make colored rows.
Can you spot any problems in the 'tranlsation'?
Reply
#8
Hi Panoss,

I saw your post about colouring some rows in your qsqltablemodel. I have managed to colour some my rows using the data() mathod and make them uneditable with the flag method. Before I did this my model was editable and could automatically update my table. However soon as i color some columns, it my edits just disappear soon as I move to next Field. Have u came across this problem before and if so, how did u get around it.

Thanks
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyQt] PyQt5 QTableView SQLite : edit cell HeinKurz 2 2,281 Mar-27-2023, 10:41 AM
Last Post: HeinKurz
  [PyQt] QStyledItemDelegate and QTableView malonn 1 1,597 Feb-07-2023, 07:15 PM
Last Post: malonn
  [PyQt] QTableView set header labels HeinKurz 2 6,407 Jan-23-2023, 08:46 AM
Last Post: HeinKurz
  [PyQt] Determine whether text in QTableView cell is fully visible or not random_nick 0 952 Oct-27-2022, 09:29 PM
Last Post: random_nick
  [PyQt] QTableView: scroll to top cell of the screen random_nick 2 2,764 Oct-08-2022, 12:29 AM
Last Post: random_nick
  [PyQt] [Solved]Add a Blank Row To QTableView Extra 3 5,361 Oct-02-2022, 04:53 PM
Last Post: Extra
  [PyQt] [Solved]Change text color of one line in TextBrowser Extra 2 4,755 Aug-23-2022, 09:11 PM
Last Post: Extra
  Tkinter - How can I change the default Notebook border color? TurboC 5 14,629 May-23-2022, 03:44 PM
Last Post: bigmac
Question [Tkinter] Change Treeview column color? water 3 9,406 Mar-04-2022, 11:20 AM
Last Post: Larz60+
  Can't get tkinter button to change color based on changes in data dford 4 3,361 Feb-13-2022, 01:57 PM
Last Post: dford

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020