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. QTableView item color to vary by value

QTableView item color to vary by value

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 2 Posters 3.6k Views 2 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.
  • JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by JonB
    #1

    I need to have the colors of items shown in a QTableView vary depending on the value in each cell. [Specifically, some values/columns are monetary amounts, if the amount in a cell is negative I want it in red, else the default black.]

    As some of you may know, I do research things, so you may be assured I have considered different approaches. I do not need detailed code for an answer, but I do need to know what approach you are recommending.

    Some of my constraints include:

    • The code has to be generic for all my (sub-classed) QTableViews. I may need for QTableWidgets too. Therefore I do not know in advance which columns will need this.

    • My tables can have any model type from: QSqlQueryModel, QSqlTableModel, QStandardItemModel. Solution must work for all 3.

    • I can recognise a "monetary value" by the fact that the value is "a floating point number". For me, all such values will be monetary.

    I suspect/presume it comes down to a choice between model.data(ForegroundRole) vs QStyledItemDelegate.
    My natural preference, for both simplicity & general applicability, is data(ForegroundRole), but I admit I'm finding it messy when that depends on the value.

    At this point I'd really like to put this question out there to see whether (a) anybody is going to answer(!) and (b) what they're going to suggest. Then I'll respond from there. TIA!

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      What about a proxy model like QIdentityProxyModel ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      JonBJ 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi,

        What about a proxy model like QIdentityProxyModel ?

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #3

        @SGaist
        You are a man of few words! :) I have read up about QIdentityProxyModel. Let's see if I understand what you are suggesting.

        For example, a proxy model could be created to define the font used, or the background colour, or the tooltip etc. This removes the need to implement all data handling in the same class that creates the structure of the model, and can also be used to create re-usable components.

        So, I think this could be used because I said I have a variety of model types. This would then allow me to put the logic for foreground color/role in one place, rather than in each of my 3 sub-classes of these. Is that what you had in mind?

        However, that itself is not my problem. My question revolves around the fact that in order to decide what color I want I need to look at the value of each item. This is the case whether I implement via data(ForegroundRole) or via QStyledItemDelegate (which represent very different ways of approaching setting the color).

        So, for example, if I go down my (preferred) route of doing it by role instead of render delegate, whether or not I use a proxy model I will end with code for sub-classed model.data() which has to look like:

        def data(self, index: QtCore.QModelIndex, role: QtCore.Qt.ItemDataRole=QtCore.Qt.DisplayRole) -> typing.Any:
            if role == Qt.ForegroundRole:
                dataVal = super().data(index, Qt.EditRole):
                if isinstance(dataVal, float):
                    if dataVal < 0.0:
                        return QtGui.QColor(QtCore.Qt.red)
            ...
        

        The point here is that when called for data(index, ForegroundRole) my code has to in turn call data(index, EditRole) to retrieve the data value in order to decide what to return for the color. I would still need to do same access to data value if I did my color via QStyledItemDelegate::paint().

        That is what "worries" me. I don't know how "costly" that is, or whether there is any better way. If this is "fine" & "normal" for accessing the data value when deciding the color then please say so and I am good to go?

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          I would say that this is the normal way but likely not the most efficient.

          One alternative would to store the foreground color when a value changes. It will cost memory in place of time spent to access each value when the role is requested.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          JonBJ 1 Reply Last reply
          2
          • SGaistS SGaist

            I would say that this is the normal way but likely not the most efficient.

            One alternative would to store the foreground color when a value changes. It will cost memory in place of time spent to access each value when the role is requested.

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #5

            @SGaist
            Thank you for replying.

            I have implemented the data() approach and it works.

            I did consider overriding setData() to store the color against the value at assignment time. I rejected it for 2 reasons:

            • When using QSqlTableModel, query result set population do not cause setData() to be called. So colors would not get set initially.

            • When using QSqlQueryModel, as above, plus as it's read-only, there is a data() but not a setData().

            Am I right about these? Did you mean that I could have written the code in slot for QAbstractItemModel::dataChanged signal instead of overriding setData()?

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              dataChanged is only a signal, but yes, you could connect it to a slot to update the foreground color if you keep it somewhere.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              JonBJ 1 Reply Last reply
              2
              • SGaistS SGaist

                dataChanged is only a signal, but yes, you could connect it to a slot to update the foreground color if you keep it somewhere.

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @SGaist
                Yes, I re-phrased. Last question, promise: would query/table models emit it as result set is read back in, whereas setData() does not get called there? [Cannot test atm.]

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  Sorry, I'm not sure I'm following that last question.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  JonBJ 1 Reply Last reply
                  0
                  • SGaistS SGaist

                    Sorry, I'm not sure I'm following that last question.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #9

                    @SGaist
                    When result set is received from db via something like QSqlQueryModel::setQuery() rows/columns in model are populated. I believe setData() is not called/involved. How would I recognise this (so as to populate colors for initial values received): will model emit dataChanged(), or would I need to handle rowsAboutToBeInserted() or beginInsertRows() or modelReset() or what?

                    1 Reply Last reply
                    0
                    • SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      Since it's pretty heavy change, I would check for the modelReset signal in this case.

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      JonBJ 1 Reply Last reply
                      1
                      • SGaistS SGaist

                        Since it's pretty heavy change, I would check for the modelReset signal in this case.

                        JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on last edited by
                        #11

                        @SGaist
                        OK, it was really for interest, thanks for your time. In my case as I said I have implemented via calculated return result from data() rather than setting the color by pre-storing it. It seems efficient enough for my purposes.

                        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