Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Change color of a row of a QSqlQueryModel (QTableView)?
Qt 6.11 is out! See what's new in the release blog

Change color of a row of a QSqlQueryModel (QTableView)?

Scheduled Pinned Locked Moved Unsolved General and Desktop
27 Posts 3 Posters 16.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    Panoss
    wrote on last edited by Panoss
    #1

    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?

    1 Reply Last reply
    1
    • P Offline
      P Offline
      Panoss
      wrote on last edited by
      #2

      Maybe I should subclass QSqlQueryModel?

      1 Reply Last reply
      0
      • P Offline
        P Offline
        Panoss
        wrote on last edited by
        #3

        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?

        C 1 Reply Last reply
        0
        • P Panoss

          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?

          C Offline
          C Offline
          c64zottel
          wrote on last edited by
          #4

          @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

          1 Reply Last reply
          2
          • P Offline
            P Offline
            Panoss
            wrote on last edited by Panoss
            #5

            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.

            C 1 Reply Last reply
            0
            • P Panoss

              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.

              C Offline
              C Offline
              c64zottel
              wrote on last edited by
              #6

              @Panoss You really have to read up on the documentation. If you intend to work further with Qt's model system, there is no way around it. For this case, look here:
              http://doc.qt.io/qt-5/qabstractitemmodel.html#setData

              1 Reply Last reply
              1
              • P Offline
                P Offline
                Panoss
                wrote on last edited by
                #7

                c64zottel thank you, I saw in the link you posted that I have to emit the signal.
                I tried with:

                 self.dataChanged.emit(QModelIndex, QModelIndex)
                

                But doesn't seem to work.
                For sure, I 'm doing something wrong.

                C 1 Reply Last reply
                0
                • P Panoss

                  c64zottel thank you, I saw in the link you posted that I have to emit the signal.
                  I tried with:

                   self.dataChanged.emit(QModelIndex, QModelIndex)
                  

                  But doesn't seem to work.
                  For sure, I 'm doing something wrong.

                  C Offline
                  C Offline
                  c64zottel
                  wrote on last edited by
                  #8

                  @Panoss Ok, this is Python anyway, I am out of my league here. But, as a last resort, you can try to call:
                  beginResetModel();
                  endResetModel();

                  1 Reply Last reply
                  0
                  • P Offline
                    P Offline
                    Panoss
                    wrote on last edited by
                    #9

                    I tried with beginResetModel() and endResetModel() in many places witihn the function setData, but with no success.
                    I don't know what else should I try, any ideas are welcome.

                    C 1 Reply Last reply
                    0
                    • P Panoss

                      I tried with beginResetModel() and endResetModel() in many places witihn the function setData, but with no success.
                      I don't know what else should I try, any ideas are welcome.

                      C Offline
                      C Offline
                      c64zottel
                      wrote on last edited by
                      #10

                      @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

                      P 1 Reply Last reply
                      0
                      • C c64zottel

                        @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

                        P Offline
                        P Offline
                        Panoss
                        wrote on last edited by Panoss
                        #11

                        @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.

                        C 1 Reply Last reply
                        0
                        • P Panoss

                          @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.

                          C Offline
                          C Offline
                          c64zottel
                          wrote on last edited by
                          #12

                          @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.

                          1 Reply Last reply
                          0
                          • VRoninV Offline
                            VRoninV Offline
                            VRonin
                            wrote on last edited by
                            #13

                            First of all, let me start by saying that using a QStandardItemModel filled manually from a QSqlQuery 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;
                            };
                            

                            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                            ~Napoleon Bonaparte

                            On a crusade to banish setIndexWidget() from the holy land of Qt

                            1 Reply Last reply
                            2
                            • P Offline
                              P Offline
                              Panoss
                              wrote on last edited by Panoss
                              #14

                              How can this line be explained in plain english?

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

                              If index.row() is smaller than 32 thne hashkey = index.row().
                              Else hashkey = index.column()?

                              VRoninV 1 Reply Last reply
                              0
                              • P Panoss

                                How can this line be explained in plain english?

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

                                If index.row() is smaller than 32 thne hashkey = index.row().
                                Else hashkey = index.column()?

                                VRoninV Offline
                                VRoninV Offline
                                VRonin
                                wrote on last edited by
                                #15

                                @Panoss That row means: prepare an integer with 64 bits, the 32 leftmost bits will contain the row, the 32 rightmost the column. The bitshift operator is the same even in python https://wiki.python.org/moin/BitwiseOperators

                                "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                ~Napoleon Bonaparte

                                On a crusade to banish setIndexWidget() from the holy land of Qt

                                1 Reply Last reply
                                2
                                • P Offline
                                  P Offline
                                  Panoss
                                  wrote on last edited by
                                  #16

                                  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.

                                  1 Reply Last reply
                                  0
                                  • VRoninV Offline
                                    VRoninV Offline
                                    VRonin
                                    wrote on last edited by
                                    #17

                                    shouldn't it be this.m_extraRoles.constFind(hashKey) ?

                                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                    ~Napoleon Bonaparte

                                    On a crusade to banish setIndexWidget() from the holy land of Qt

                                    1 Reply Last reply
                                    1
                                    • P Offline
                                      P Offline
                                      Panoss
                                      wrote on last edited by
                                      #18

                                      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

                                      1 Reply Last reply
                                      0
                                      • VRoninV Offline
                                        VRoninV Offline
                                        VRonin
                                        wrote on last edited by
                                        #19

                                        You can actually remove that line altogether, it's just a check that is done only in debug mode

                                        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                        ~Napoleon Bonaparte

                                        On a crusade to banish setIndexWidget() from the holy land of Qt

                                        1 Reply Last reply
                                        0
                                        • P Offline
                                          P Offline
                                          Panoss
                                          wrote on last edited by Panoss
                                          #20

                                          Only one (!!) line is left:

                                          emit dataChanged(index,index,QVector<int>(1,role));
                                          

                                          Translated to:

                                          self.dataChanged.emit(index,index,QVector(int((1,role)))
                                          

                                          But there is no QVector in Python.
                                          (I mean it doesn't exist in any library like PyQt4.QtCore)

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved