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. Set background color to a cell of a tableView
Qt 6.11 is out! See what's new in the release blog

Set background color to a cell of a tableView

Scheduled Pinned Locked Moved General and Desktop
54 Posts 5 Posters 55.3k Views 1 Watching
  • 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
    poporacer
    wrote on last edited by
    #1

    I have a tableview that is using a QSqlRelationalTableModel. The table view has a column that I want to color the cell (or row) with the highest sales total (column 5). I can iterate through the model and get the row that the highest value is in. I have tried several methods to color the cell to no avail. I have read that it can be done with a custom proxy or delegate but no samples of code so I am not sure what they mean. From what I have read, the following should work.
    @ printModel= new QSqlRelationalTableModel (this);
    printModel-> setEditStrategy(QSqlTableModel::OnRowChange);
    printModel-> setTable (mTableName);

    printModel-> setRelation (2, QSqlRelation("customer", "id", "Name"));
    printModel->select();
    

    QAbstractItemModel *model = ui->printView->model();
    QModelIndex modelIdx = model->index(rowHighSales, 5, QModelIndex()); //rowHighSales is the row with the highest sales
    model->setData(modelIdx, yellow, Qt::BackgroundRole); //this returns false if I use debug. red is a QBrush
    @
    Can this work or is there a better way to do it?

    Thanks

    1 Reply Last reply
    0
    • Z Offline
      Z Offline
      ZapB
      wrote on last edited by
      #2

      I'm not sure. You would need to look at the source for QSqlRelationalTableModel::setData() to see how it handles the background role - I suspect it doesn't support it.

      If that is the case a simple approach would be to use a very simple proxy model that returns the correct background color in the data() function.

      Nokia Certified Qt Specialist
      Interested in hearing about Qt related work

      1 Reply Last reply
      0
      • G Offline
        G Offline
        giesbert
        wrote on last edited by
        #3

        Using a simple proxy model or a delegate is the safe way of doing it.
        I, personally, would like to use a proxy model, derived from QSortFilterProxyModel.
        You only have to overwrite data() and return the correct color if needed. In all other cases, you just call the default impl.

        Nokia Certified Qt Specialist.
        Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

        1 Reply Last reply
        0
        • Z Offline
          Z Offline
          ZapB
          wrote on last edited by
          #4

          Agreed, plus you also get all the nice features of QSFPM too so you could even sort on yoru column too if you like.

          Nokia Certified Qt Specialist
          Interested in hearing about Qt related work

          1 Reply Last reply
          0
          • A Offline
            A Offline
            andre
            wrote on last edited by
            #5

            Yes, indeed, a proxy model is the way to go.

            What you do is that you subclass QSortFilterProxyModel, and reimplement the data() method to return the source data for the DisplayRole and the EditRole, and returns your color for the BackgroundRole when asked for it.

            I have written a generic proxy model that basically just overlays an existing table-type model (that is: it doesn't work on trees, only on a specific level of one). The overlay model supplies one set of roles, while the underlying model supplies the rest. You can use setData() on it to set data on all roles, and it will either store the value in the overlay model or forward the call to the source model. You can also use it to adjust flags. You could use a setup like that to set your color like you do now, but store it in your own "overlay model" instead of in the QSqlRelationalTableModel. It is not very hard to implement.

            1 Reply Last reply
            0
            • P Offline
              P Offline
              poporacer
              wrote on last edited by
              #6

              Ok, as I am new to all this, I am not sure how to use a proxy model, derived from QSortFilterProxyModel. Could you give me some code to get me started? I will research this as well, but from reading the docs, I am not sure how to do what you recommend. Thanks

              1 Reply Last reply
              0
              • G Offline
                G Offline
                giesbert
                wrote on last edited by
                #7

                You could start reading the "docs":http://doc.qt.nokia.com/4.7/model-view-programming.html#proxy-models , they are really good.

                Nokia Certified Qt Specialist.
                Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                1 Reply Last reply
                0
                • P Offline
                  P Offline
                  poporacer
                  wrote on last edited by
                  #8

                  Ok so I re read the docs, and searched, but couldn't get it to work. Here is what I have....where did I go wrong? In setting up the table I use
                  @QAbstractItemModel myModel;
                  QSortFilterProxyModel *printModel = new QSortFilterProxyModel(parent);
                  printModel->setSourceModel(myModel);
                  ui->printView->setModel(printModel);@
                  and I get an error: cannot declare variable 'myModel' to be of abstract type 'QAbstractItemModel' because the following virtual functions are pure within 'QAbstractItemModel': virtual QModelIndex QAbstractItemModel::index(int, int, const QModelIndex&) const .(and many more)
                  I think I have to add something else...how and what do I need to do? I copied the code almost exactly.

                  1 Reply Last reply
                  0
                  • G Offline
                    G Offline
                    giesbert
                    wrote on last edited by
                    #9

                    It tells you what is wrong, QAbstractItemModel is not creatable. It is the abstract base class of all Models, and it is ABSTRACT. you normally go this way:

                    @
                    printModel= new QSqlRelationalTableModel (this);
                    printModel-> setEditStrategy(QSqlTableModel::OnRowChange);
                    printModel-> setTable (mTableName);

                    printModel-> setRelation (2, QSqlRelation("customer", "id", "Name"));
                    printModel->select();

                    MyQSFPM* proxy = new MyQSFPM(this);
                    proxy->setSourceModel(printModel);
                    ui->printView->setModel(proxy);
                    @

                    now you have to create MyQSFPM as derived class of QSortFilterProxyModel abd reimplement data.

                    @
                    class MyQSFPM : public QSortFilterProxyModel
                    {
                    ...
                    }
                    @

                    Nokia Certified Qt Specialist.
                    Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                    1 Reply Last reply
                    0
                    • P Offline
                      P Offline
                      poporacer
                      wrote on last edited by
                      #10

                      I feel stupid. I have read several docs and searched and still do not understand how to reimplement the data in the derived class. Do I simply copy the implementation of the functions I need to use and put them in the derived class? I am going to continue reading and trying things. Sorry for not understanding.

                      1 Reply Last reply
                      0
                      • G Offline
                        G Offline
                        giesbert
                        wrote on last edited by
                        #11

                        Hi poporacer.

                        Overwriting methods is standard C++ knowledge.
                        For more information about model / view, look here:

                        "Qt documentation - Model/View Programming":http://doc.qt.nokia.com/4.7/model-view-programming.html

                        Nokia Certified Qt Specialist.
                        Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                        1 Reply Last reply
                        0
                        • A Offline
                          A Offline
                          andre
                          wrote on last edited by
                          #12

                          [quote author="poporacer" date="1301546336"]I feel stupid. I have read several docs and searched and still do not understand how to reimplement the data in the derived class. Do I simply copy the implementation of the functions I need to use and put them in the derived class? I am going to continue reading and trying things. Sorry for not understanding.[/quote]

                          As Gerolf points out, overriding virtual methods is a key feature of object oriented programming in C++. It is an essential part of subclassing.

                          What you need to do in this case, is to handle the cases you want to handle in your reimplementation of data() in your subclass, and use the base implementation for all other cases. Note that it is often a good idea to call the base class implementation of an overridden method in the reimplementation.

                          In your case, your data method might look something like this*:

                          @
                          QVariant myProxyModel::data ( const QModelIndex & index, int role ) const
                          {
                          if (!index.isValid())
                          return QVariant();

                          QModelIndex sourceIndex = mapToSource( index );
                          if ( role == Qt::BackgroundRole ) {
                          if (sourceIndex.data( Qt::DisplayRole ).toDouble == m_theValueIWant ) {
                          return Qt::red;
                          } else {
                          return QVariant();
                          }
                          } else {
                          return sourceIndex.data( role );
                          }
                          }
                          @

                          Perhaps that can help you get started.

                          *) That means: typed in the forum editor, don't expect this to compile or be complete

                          Edit: changed sample to return a color, not a checkbox state. I was confused with another question

                          1 Reply Last reply
                          0
                          • Z Offline
                            Z Offline
                            ZapB
                            wrote on last edited by
                            #13

                            [quote author="Andre" date="1301558057"]
                            In your case, your data method might look something like this*:
                            [/quote]

                            I think you got two threads mixed up, this one is about the background role ;-)

                            So in this case you reimplementation may look something like:

                            @
                            QVariant myProxyModel::data ( const QModelIndex & index, int role ) const
                            {
                            if (!index.isValid())
                            return QVariant();

                            if ( sourceIndex.row() == m_maxRow && role == Qt::BackgroundRole ) {
                            QModelIndex sourceIndex = mapToSource( index );
                            return QVariant( Qt::red );
                            } else {
                            return QSortFilterProxyModel::data( index, role );
                            }
                            }
                            @

                            where m_maxRow is a member variable that you need to set.

                            Nokia Certified Qt Specialist
                            Interested in hearing about Qt related work

                            1 Reply Last reply
                            0
                            • A Offline
                              A Offline
                              andre
                              wrote on last edited by
                              #14

                              [quote author="ZapB" date="1301558444"][quote author="Andre" date="1301558057"]
                              In your case, your data method might look something like this*:
                              [/quote]

                              I think you got two threads mixed up, this one is about the background role ;-)
                              [/quote]

                              Yeah, that's what I just realized. There is another running question on putting checkboxes from an SQL model in a QTableView, and I confused the two. I was already editing my response.

                              1 Reply Last reply
                              0
                              • Z Offline
                                Z Offline
                                ZapB
                                wrote on last edited by
                                #15

                                Yeah, I thought so. I'm following that thread too. Easily done ;-)

                                Nokia Certified Qt Specialist
                                Interested in hearing about Qt related work

                                1 Reply Last reply
                                0
                                • P Offline
                                  P Offline
                                  poporacer
                                  wrote on last edited by
                                  #16

                                  I have read the code, read the docs you suggested and yet have not been able to get it to work. I am not sure if I am reading too much into this. So let me explain what I understand that I shoul do so far. I need to create a new class (MyProxyModel) and inherit QSortFilterProxyModel. Then in my class reimplement the data function ( I think that in ZapB's code the declaration
                                  @QModelIndex sourceIndex = mapToSource( index ); @
                                  should go at the top of the function?) I am not sure what is meant by having to set m_maxRow is this to the total number of rows or the row number that I want to set the background color? Then in my main class I set up the table following Gerolf's suggestion. Here is what I have:
                                  myproxymodel.h
                                  @
                                  #ifndef MYPROXYMODEL_H
                                  #define MYPROXYMODEL_H

                                  #include <QSortFilterProxyModel>

                                  class MyProxyModel : QSortFilterProxyModel
                                  {
                                  Q_OBJECT

                                  public:
                                  MyProxyModel();
                                  ~MyProxyModel();
                                  QVariant data ( const QModelIndex & index, int role );
                                  void setSourceModel ( QAbstractItemModel * sourceModel );

                                  };
                                  #endif //MYPROXYMODEL_H@

                                  myproxymmodel.cpp:
                                  @
                                  #include "myproxymodel.h"

                                  MyProxyModel::MyProxyModel (QObject *parent) :
                                  QSortFilterProxyModel(parent)
                                  {

                                  }

                                  QVariant MyProxyModel::data ( const QModelIndex & index, int role ) const
                                  {
                                  QModelIndex sourceIndex = mapToSource( index );
                                  if (!index.isValid())
                                  return QVariant();
                                  if ( sourceIndex.row() == m_maxRow && role == Qt::BackgroundRole )
                                  {

                                  return QVariant( Qt::red ); 
                                  } 
                                  else 
                                  { 
                                  return QSortFilterProxyModel::data( index, role ); 
                                  } 
                                  

                                  }@
                                  And in my main class I have
                                  @#include "myproxymodel.h"
                                  .
                                  .
                                  .
                                  void MainClass::createReportTable(QStringList stringList)
                                  {
                                  printModel= new QSqlRelationalTableModel (this);
                                  printModel-> setEditStrategy(QSqlTableModel::OnRowChange);
                                  printModel-> setTable (mTableName);
                                  printModel-> setRelation (2, QSqlRelation("customer", "id", "Name"));
                                  printModel->select();
                                  MyProxyModel* proxy = new MyProxyModel(this);
                                  proxy->setSourceModel(printModel);
                                  ui->printView->setModel(proxy);
                                  @

                                  I get several compile errors and I have tried to figure out why, but can't figure it out.
                                  Line 12 in the main class gives me the error
                                  no matching function for call to 'MyProxyModel::MyProxyModel(MainClass* const)

                                  Line 14 in the main class gives me the error
                                  'QAbstractItemModel' is an inaccessible base of 'MyProxyModel'

                                  Am I going about this correctly? I am trying to figure it out on my own by "reading the docs" but the docs I have trouble understanding. Where am I going wrong?

                                  In reading, I see this function:
                                  bool QAbstractItemModel::setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ) [virtual] Is this of any use?

                                  1 Reply Last reply
                                  0
                                  • A Offline
                                    A Offline
                                    andre
                                    wrote on last edited by
                                    #17

                                    In your myproxymodel.h code, you declare setSourceModel on line 14. You don't need that; QSortFilterProxyModel already has a good implementation of that method. You can reimplement it if you want to do something special when the source model is set, but it doesn't seem to be the case.

                                    m_maxRow is supposed to indicate the row you want to highlight. Of course, this is only one way to do that; you can also invent something more flexible that allows you to highlight different rows with different colors.

                                    Note that you need to publicly inherit from QSortFilterProxyModel. That is: change the first line of your myproxymodel.h to:

                                    @
                                    class MyProxyModel : public QSortFilterProxyModel
                                    @

                                    That should get rid of your error on line 14 of your main: ‘QAbstractItemModel’ is an inaccessible base of ‘MyProxyModel’. Remember, C++ uses private as the default, not public.

                                    bool QAbstractItemModel::setData is used to modify data through the QAbstractItemModel interface, so, mostly through the views themselves. In your case, you don't need to reimplement this method. You do, of course, need to have some other method to determine or set the row number to highlight.

                                    1 Reply Last reply
                                    0
                                    • G Offline
                                      G Offline
                                      giesbert
                                      wrote on last edited by
                                      #18

                                      Hi,

                                      there is one more bug in your code. This error:

                                      bq. no matching function for call to ‘MyProxyModel::MyProxyModel(MainClass* const)

                                      is issued due to this code:

                                      @
                                      class MyProxyModel : QSortFilterProxyModel
                                      {
                                      Q_OBJECT
                                      public:
                                      MyProxyModel(); // <-- !!!
                                      };
                                      @

                                      It should be like this;

                                      @
                                      class MyProxyModel : QSortFilterProxyModel
                                      {
                                      Q_OBJECT
                                      public:
                                      MyProxyModel(QObject* parent); // <-- !!!
                                      };
                                      @

                                      Nokia Certified Qt Specialist.
                                      Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                                      1 Reply Last reply
                                      0
                                      • P Offline
                                        P Offline
                                        poporacer
                                        wrote on last edited by
                                        #19

                                        Thanks for your help. What would be the best way to pass the m_maxRow variable to the MyProxyModel class? The two options I can think are, create a global variable (usually considered bad) or create a signal/slot to pass the variable? I tried to pass it via a signal/slot and my class declaration is not working correctly. In my mainclass.h I have:
                                        @#include "myproxymodel.h"
                                        class MyProxyModel;@

                                        in my mainclass.cpp I have:
                                        @void MainClass::colorCells()
                                        {
                                        float lowSales=99999999;
                                        float highSales=0;
                                        int rowLow=0;
                                        int rowHigh=0;
                                        int totalRows = 0;

                                        MyProxyModel myProxyModel; //error here

                                        connect(this,SIGNAL(sendRows(int, int)),
                                        &myProxyModel, SLOT(getRows(int, int))); //to pass the high and low sales

                                        int numRows =ui->printView->model()->rowCount();

                                        for (int r=0; r<numRows; r++ )
                                        {
                                        if (ui->printView->isRowHidden(r))
                                        continue;
                                        float currentSales = ui->printView->model()->index(r,32).data(Qt::DisplayRole).toFloat();
                                        if (currentSales <lowSales)
                                        {
                                        lowSales = currentRunTime;
                                        rowLow = r;
                                        }
                                        if (currentSales > highSales)
                                        {
                                        highSales = currentSales;
                                        rowhigh = r;
                                        }
                                        totalRows++;
                                        totalTime += currentRunTime;
                                        }

                                        emit sendRows (rowSlow, rowFast);
                                        QModelIndex modelIdx = printModel->index(rowFast,32, QModelIndex());
                                        printModel->data(modelIdx, Qt::BackgroundRole);//Is this correct implementation?
                                        @
                                        where I try to declare the MyProxyModel variable I get the error:
                                        no matching function for call to 'MyProxyModel::MyProxyModel()'
                                        candidates are: MyProxyModel::MyProxyModel(QObject*)
                                        MyProxyModel::MyProxyModel(const MyProxyModel&)
                                        I don't see why it thinks I am trying to declare a function.
                                        I keep reading, trying to keep from asking questions here but I keep coming back!
                                        Again, I appreciate your patience with my questions.

                                        1 Reply Last reply
                                        0
                                        • A Offline
                                          A Offline
                                          andre
                                          wrote on last edited by
                                          #20

                                          Don't create your proxy model on the stack, create it on the heap with a proper parent. Otherwise, it will be deleted as soon as the method finishes (so before a result is even drawn). What's more, the code as you wrote it now can only be run once. Otherwise, you'll keep creating more proxy models. That can't be what you want. You also don't set the proxy model as the model for your view, nor do you give the proxy model a source model.

                                          I think, you should calculate the row to highlight in the proxy model itself. That nicely encapsulates the functionality you're after in a single class. Or, make a more flexible API on the proxy model to add highlights to selected rows at will, so you can re-use it later on. Your mid-way solution doesn't look very nice to me. Also: what happens if two rows share the same maximum or minimum value?

                                          I don't quite get your implementation. Especially the last two lines are quite mystifying. Why to you request data from your model, and then don't use it? Also, I would not initialize to 0 and 99999999. Those are rather arbitrairy. Instead, initialize to the maximum and minimum values of float. You can find those by including <float.h>.

                                          First, however, try to get the proxy model working with a fixed (set of) row(s) of to highlight. If that works ok, take the next step and determine the rows dymanically. I would do that by responding to changes in the (source) model, so you can update the source model and be sure that the highlights will be properly updated as well.

                                          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