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 and redrawing on window up-fronting "efficiency"
Qt 6.11 is out! See what's new in the release blog

QTableView and redrawing on window up-fronting "efficiency"

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 4 Posters 1.8k Views 3 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 have a standard Qt (5.7) GUI app.
    • I am under Linux, if that makes any difference.
    • I have a QTableView on a dialog/window.
    • The QTableView is linked to a populated QSqlQueryModel.
    • I have overridden the QSqlQueryModel::data() method.
    • I had placed a breakpoint in my debugger on that overridden method.
    • To my surprise, I find that every time I click to bring the app window up-front during debugging, QSqlQueryModel::data() is being called. Hundreds of times, with all its different indexes & roles.

    I did not think up-fronting would cause this. I can only imagine that in some shape or form the QTableView is being re-painted, as a result of some obscured part of the window now being uncovered, and its implementation is to re-execute all the code to get values to display for the data, colors, etc. etc., which would presumably have been called in the first place to draw the table.

    This scares me! I had intuitively assumed that, once having been drawn, up-fronting/unobscuration would be handled at some level by some kind of caching/retrieving of the required rectangle, probably by the native windowing system itself. But it appears not.

    What's going on here, please?!

    raven-worxR 1 Reply Last reply
    0
    • JonBJ JonB
      • I have a standard Qt (5.7) GUI app.
      • I am under Linux, if that makes any difference.
      • I have a QTableView on a dialog/window.
      • The QTableView is linked to a populated QSqlQueryModel.
      • I have overridden the QSqlQueryModel::data() method.
      • I had placed a breakpoint in my debugger on that overridden method.
      • To my surprise, I find that every time I click to bring the app window up-front during debugging, QSqlQueryModel::data() is being called. Hundreds of times, with all its different indexes & roles.

      I did not think up-fronting would cause this. I can only imagine that in some shape or form the QTableView is being re-painted, as a result of some obscured part of the window now being uncovered, and its implementation is to re-execute all the code to get values to display for the data, colors, etc. etc., which would presumably have been called in the first place to draw the table.

      This scares me! I had intuitively assumed that, once having been drawn, up-fronting/unobscuration would be handled at some level by some kind of caching/retrieving of the required rectangle, probably by the native windowing system itself. But it appears not.

      What's going on here, please?!

      raven-worxR Offline
      raven-worxR Offline
      raven-worx
      Moderators
      wrote on last edited by
      #2

      @JonB said in QTableView and redrawing on window up-fronting "efficiency":

      What's going on here, please?!

      your assumption is right - the calls are caused by the repaint.

      Why did you override the data() method?

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      JonBJ 1 Reply Last reply
      0
      • raven-worxR raven-worx

        @JonB said in QTableView and redrawing on window up-fronting "efficiency":

        What's going on here, please?!

        your assumption is right - the calls are caused by the repaint.

        Why did you override the data() method?

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

        @raven-worx

        your assumption is right - the calls are caused by the repaint.

        Hmm, interesting. I had not expected it to have redraw from scratch in this way. I had expected the windowing system to handle un-obscuration itself, having in effect saved in a buffer what the obscured area looked like. Presumably my expectations were wrong! Unfortunately, it sure makes debugging a pain :( Would this apply just as much to, say, a QLineEdit as to a QTableView?

        Why did you override the data() method?

        Well, since you're interested enough to ask... :) Here are my present reasons. Please feel free to suggest if you think any are the wrong way to do it:

        Reason #1

        I have inherited an existing project with a large body of code. It is "not well written". That means, it would not surprise me if there are bugs lurking all over the place, potentially serious ones.

        My first "clean up" is to ensure all data accesses/updates are thoroughly checked for any hidden errors. http://doc.qt.io/qt-5/qsqlquerymodel.html#data states:

        If item is out of bounds or if an error occurred, an invalid QVariant is returned.

        That's no good at all! Thousands of calls to this function exist, without error checking on the result. I have to change that case to throw, else we'll never be aware of them....

        Reason #2

        Nearly all the floating-point columns in the database are actually defined in MySQL as DECIMAL(8, 2). That means, 2 decimal places, without any loss of precision (yes, they are money amounts). Unfortunately for me, the Qt SQL code converts all these database types to a generic float. So when data() is called with Qt::DisplayRole to generate string representation, I do not get what I need for the format. I have to check for that by overriding and return "%.2f" to get back what it should be.

        Reason #3

        I now want to make numbers (such as above) to be right-justified. So I want to intercept Qt::TextAlignmentRole to return Qt::AlignRight. (Having said that, I am presently investigating why it does not seem to be working for me as per https://forum.qt.io/topic/90777/qsqlquerymodel-data-not-called-with-qt-textalignmentrole)

        Over time I may add more cases, e.g. I may decide to display negative amounts in color red via Qt::ForegroundRole.

        All this as per, say, examples code in http://doc.qt.io/qt-5/modelview.html

        raven-worxR 1 Reply Last reply
        0
        • JonBJ JonB

          @raven-worx

          your assumption is right - the calls are caused by the repaint.

          Hmm, interesting. I had not expected it to have redraw from scratch in this way. I had expected the windowing system to handle un-obscuration itself, having in effect saved in a buffer what the obscured area looked like. Presumably my expectations were wrong! Unfortunately, it sure makes debugging a pain :( Would this apply just as much to, say, a QLineEdit as to a QTableView?

          Why did you override the data() method?

          Well, since you're interested enough to ask... :) Here are my present reasons. Please feel free to suggest if you think any are the wrong way to do it:

          Reason #1

          I have inherited an existing project with a large body of code. It is "not well written". That means, it would not surprise me if there are bugs lurking all over the place, potentially serious ones.

          My first "clean up" is to ensure all data accesses/updates are thoroughly checked for any hidden errors. http://doc.qt.io/qt-5/qsqlquerymodel.html#data states:

          If item is out of bounds or if an error occurred, an invalid QVariant is returned.

          That's no good at all! Thousands of calls to this function exist, without error checking on the result. I have to change that case to throw, else we'll never be aware of them....

          Reason #2

          Nearly all the floating-point columns in the database are actually defined in MySQL as DECIMAL(8, 2). That means, 2 decimal places, without any loss of precision (yes, they are money amounts). Unfortunately for me, the Qt SQL code converts all these database types to a generic float. So when data() is called with Qt::DisplayRole to generate string representation, I do not get what I need for the format. I have to check for that by overriding and return "%.2f" to get back what it should be.

          Reason #3

          I now want to make numbers (such as above) to be right-justified. So I want to intercept Qt::TextAlignmentRole to return Qt::AlignRight. (Having said that, I am presently investigating why it does not seem to be working for me as per https://forum.qt.io/topic/90777/qsqlquerymodel-data-not-called-with-qt-textalignmentrole)

          Over time I may add more cases, e.g. I may decide to display negative amounts in color red via Qt::ForegroundRole.

          All this as per, say, examples code in http://doc.qt.io/qt-5/modelview.html

          raven-worxR Offline
          raven-worxR Offline
          raven-worx
          Moderators
          wrote on last edited by
          #4

          @JonB said in QTableView and redrawing on window up-fronting "efficiency":

          Would this apply just as much to, say, a QLineEdit as to a QTableView?

          yes, this is the painting system of Qt.

          That's no good at all! Thousands of calls to this function exist, without error checking on the result. I have to change that case to throw, else we'll never be aware of them....

          When you only use the model in a QAbstractItemView the case of an invalid index is not very common. So don't worry too much about it.
          Just a side note (for Qt 5.11).

          --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
          If you have a question please use the forum so others can benefit from the solution in the future

          JonBJ 1 Reply Last reply
          0
          • raven-worxR raven-worx

            @JonB said in QTableView and redrawing on window up-fronting "efficiency":

            Would this apply just as much to, say, a QLineEdit as to a QTableView?

            yes, this is the painting system of Qt.

            That's no good at all! Thousands of calls to this function exist, without error checking on the result. I have to change that case to throw, else we'll never be aware of them....

            When you only use the model in a QAbstractItemView the case of an invalid index is not very common. So don't worry too much about it.
            Just a side note (for Qt 5.11).

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

            @raven-worx
            Unfortunately, it is not the case that, say, QSqlQueryModel::data(QModelIndex, ...) is only called via QTableView etc.

            There are thousands of occurrences of straight, explicit:

            index = QModelIndex(naught_row, naughty_column)
            value = model.data(index, [role])
            

            dotted through existing code, and similarly for setData(index), which is even more worrying! So I need to trap those, don't I?

            Are you suggesting that user code should not explicitly call QSqlQueryModel::data(QModelIndex, ...) to get data value from a model, say outside of anything table-viewy? If so, how should it access the data? I have been meaning to ask this anyway, as I do not see a ItemDataRole value which means "just get the underlying data value, however the model read it from the database and stored it", I don't always want it converted to, say, a string for DisplayRole. I'd be obliged if you'd enlighten me? Thanks.

            raven-worxR 1 Reply Last reply
            0
            • JonBJ JonB

              @raven-worx
              Unfortunately, it is not the case that, say, QSqlQueryModel::data(QModelIndex, ...) is only called via QTableView etc.

              There are thousands of occurrences of straight, explicit:

              index = QModelIndex(naught_row, naughty_column)
              value = model.data(index, [role])
              

              dotted through existing code, and similarly for setData(index), which is even more worrying! So I need to trap those, don't I?

              Are you suggesting that user code should not explicitly call QSqlQueryModel::data(QModelIndex, ...) to get data value from a model, say outside of anything table-viewy? If so, how should it access the data? I have been meaning to ask this anyway, as I do not see a ItemDataRole value which means "just get the underlying data value, however the model read it from the database and stored it", I don't always want it converted to, say, a string for DisplayRole. I'd be obliged if you'd enlighten me? Thanks.

              raven-worxR Offline
              raven-worxR Offline
              raven-worx
              Moderators
              wrote on last edited by
              #6

              @JonB said in QTableView and redrawing on window up-fronting "efficiency":

              There are thousands of occurrences of straight, explicit:
              index = QModelIndex(naught_row, naughty_column)
              value = model.data(index, [role])

              But anyway. If data is requested with an invalid index it's the responsibility of the caller. All you could do is to return an invalid QVariant. Would the code still run correct with such an invalid value?

              I don't always want it converted to, say, a string for DisplayRole

              are you sure it's always converted to a QString by the QSqlQueryModel? IIRC the returned variant follows the data type from the database as much as possible.

              Beside that you can also add custom roles and return whatever you like:

              enum CustomItemRole {
                  MyItemRole = Qt::UserRole+1
              };
              

              --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
              If you have a question please use the forum so others can benefit from the solution in the future

              JonBJ 1 Reply Last reply
              0
              • raven-worxR raven-worx

                @JonB said in QTableView and redrawing on window up-fronting "efficiency":

                There are thousands of occurrences of straight, explicit:
                index = QModelIndex(naught_row, naughty_column)
                value = model.data(index, [role])

                But anyway. If data is requested with an invalid index it's the responsibility of the caller. All you could do is to return an invalid QVariant. Would the code still run correct with such an invalid value?

                I don't always want it converted to, say, a string for DisplayRole

                are you sure it's always converted to a QString by the QSqlQueryModel? IIRC the returned variant follows the data type from the database as much as possible.

                Beside that you can also add custom roles and return whatever you like:

                enum CustomItemRole {
                    MyItemRole = Qt::UserRole+1
                };
                
                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @raven-worx

                But anyway. If data is requested with an invalid index it's the responsibility of the caller. All you could do is to return an invalid QVariant. Would the code still run correct with such an invalid value?

                It may well be the responsibility of the caller. But unfortunately the hundreds of callers have not been written (by other people) to check that! The danger is they will proceed with an incorrect value. If I'm lucky they will later run into some error, but if I'm not they will proceed without error but not behave correctly, and I would never know about it. That's why I need to override it to throw, so that I can track them down!

                are you sure it's always converted to a QString by the QSqlQueryModel? IIRC the returned variant follows the data type from the database as much as possible.

                It's the role of, say, DisplayRole (and most of the others) passed to the data() method which causes a conversion to happen (in this case to QString).

                What I am asking is: which ItemDataRole value passed to data() method will return the data as close as possible to whatever the underlying QVariant(?) is which QSqlQueryModel has (presumably) actually stored somewhere when it received the value from the database? It's not, say, DisplayRole or EditRole as these both convert to QString. So which ItemDataRole does return the underlying QVariant as-is?

                Beside that you can also add custom roles and return whatever you like:

                I would be happy to do that. The problem is not defining an extra custom item role, it's what code to write to return the desired value for that role? How do I access the underlying data value stored without going via QSqlQueryModel::data(some-ItemDataRole) if there is no existing ItemDataRole which will just return the stored QVariant? Can I access the stored data in some direct fashion to get this, e.g. not via QSqlQueryModel::data()?

                raven-worxR 1 Reply Last reply
                0
                • JonBJ JonB

                  @raven-worx

                  But anyway. If data is requested with an invalid index it's the responsibility of the caller. All you could do is to return an invalid QVariant. Would the code still run correct with such an invalid value?

                  It may well be the responsibility of the caller. But unfortunately the hundreds of callers have not been written (by other people) to check that! The danger is they will proceed with an incorrect value. If I'm lucky they will later run into some error, but if I'm not they will proceed without error but not behave correctly, and I would never know about it. That's why I need to override it to throw, so that I can track them down!

                  are you sure it's always converted to a QString by the QSqlQueryModel? IIRC the returned variant follows the data type from the database as much as possible.

                  It's the role of, say, DisplayRole (and most of the others) passed to the data() method which causes a conversion to happen (in this case to QString).

                  What I am asking is: which ItemDataRole value passed to data() method will return the data as close as possible to whatever the underlying QVariant(?) is which QSqlQueryModel has (presumably) actually stored somewhere when it received the value from the database? It's not, say, DisplayRole or EditRole as these both convert to QString. So which ItemDataRole does return the underlying QVariant as-is?

                  Beside that you can also add custom roles and return whatever you like:

                  I would be happy to do that. The problem is not defining an extra custom item role, it's what code to write to return the desired value for that role? How do I access the underlying data value stored without going via QSqlQueryModel::data(some-ItemDataRole) if there is no existing ItemDataRole which will just return the stored QVariant? Can I access the stored data in some direct fashion to get this, e.g. not via QSqlQueryModel::data()?

                  raven-worxR Offline
                  raven-worxR Offline
                  raven-worx
                  Moderators
                  wrote on last edited by
                  #8

                  @JonB said in QTableView and redrawing on window up-fronting "efficiency":

                  It's the role of, say, DisplayRole (and most of the others) passed to the data() method which causes a conversion to happen (in this case to QString).

                  As i said, are you sure a conversion happens?!
                  Check the type of the variant returned from QSqlModel::data() for Qt::DisplayRole.

                  --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                  If you have a question please use the forum so others can benefit from the solution in the future

                  JonBJ 1 Reply Last reply
                  1
                  • raven-worxR raven-worx

                    @JonB said in QTableView and redrawing on window up-fronting "efficiency":

                    It's the role of, say, DisplayRole (and most of the others) passed to the data() method which causes a conversion to happen (in this case to QString).

                    As i said, are you sure a conversion happens?!
                    Check the type of the variant returned from QSqlModel::data() for Qt::DisplayRole.

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

                    @raven-worx
                    Hmm, this is very interesting after all, thanks....

                    Look at the documentation page I have been following, http://doc.qt.io/qt-5/qt.html#ItemDataRole-enum. See for example how it states:

                    Qt::DisplayRole 0 The key data to be rendered in the form of text. (QString)

                    See that QString at the end? All of the enumerated values have some similar type annotation.

                    Now, I took this to mean: the base QSqlQueryModel::data(), when called with Qt::DisplayRole for the ItemDataRole, will actually return a QVariant for a QString to be used for the data.

                    However, debugging I see that the base returns, for example for an int received from the database, a QVariant with QVariant::type() == QMetaType::Int. And presumably callers are required to convert that to string for display if required. I had assumed the docs meant it should return an already converted to QVariant::type() == QMetaType::QString for, say, an int, which would have lost me further underlying information. But so far it seems not so....

                    I am investigating further. If you have a comment on your understanding of the docs/behaviour that would be great. From what we are seeing, if I do want to return as close as possible to the underlying value QVariant, are you suggesting that role DisplayRole or EditRole are basically going to do that for me after all?

                    raven-worxR 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @raven-worx
                      Hmm, this is very interesting after all, thanks....

                      Look at the documentation page I have been following, http://doc.qt.io/qt-5/qt.html#ItemDataRole-enum. See for example how it states:

                      Qt::DisplayRole 0 The key data to be rendered in the form of text. (QString)

                      See that QString at the end? All of the enumerated values have some similar type annotation.

                      Now, I took this to mean: the base QSqlQueryModel::data(), when called with Qt::DisplayRole for the ItemDataRole, will actually return a QVariant for a QString to be used for the data.

                      However, debugging I see that the base returns, for example for an int received from the database, a QVariant with QVariant::type() == QMetaType::Int. And presumably callers are required to convert that to string for display if required. I had assumed the docs meant it should return an already converted to QVariant::type() == QMetaType::QString for, say, an int, which would have lost me further underlying information. But so far it seems not so....

                      I am investigating further. If you have a comment on your understanding of the docs/behaviour that would be great. From what we are seeing, if I do want to return as close as possible to the underlying value QVariant, are you suggesting that role DisplayRole or EditRole are basically going to do that for me after all?

                      raven-worxR Offline
                      raven-worxR Offline
                      raven-worx
                      Moderators
                      wrote on last edited by
                      #10

                      @JonB
                      yes the docs may be a bit confusing on that point.
                      But basically the view is responsible to display the value. Which in ~99% of the cases is a string. But this is done by the view/delegate by calling toString() on the variant.

                      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                      If you have a question please use the forum so others can benefit from the solution in the future

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

                        Hi,

                        To add to @raven-worx, QStyledItemDelegate::displayText will be used (unless a different delegate has been set)

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

                        1 Reply Last reply
                        0
                        • Christian EhrlicherC Offline
                          Christian EhrlicherC Offline
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote on last edited by
                          #12

                          @JonB said in QTableView and redrawing on window up-fronting "efficiency":

                          Qt::DisplayRole 0 The key data to be rendered in the form of text. (QString)

                          I don't see any problems here. It just says that the returned QVariant is converted into a string for displaying and not e.g. into a QImage (like .e.g. for the DecorationRole) or QRect for the SizeHintRole or anything else. If the returned QVariant can't be converted into a QString, nothing can be displayed.

                          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                          Visit the Qt Academy at https://academy.qt.io/catalog

                          JonBJ 1 Reply Last reply
                          0
                          • Christian EhrlicherC Christian Ehrlicher

                            @JonB said in QTableView and redrawing on window up-fronting "efficiency":

                            Qt::DisplayRole 0 The key data to be rendered in the form of text. (QString)

                            I don't see any problems here. It just says that the returned QVariant is converted into a string for displaying and not e.g. into a QImage (like .e.g. for the DecorationRole) or QRect for the SizeHintRole or anything else. If the returned QVariant can't be converted into a QString, nothing can be displayed.

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

                            @Christian-Ehrlicher
                            I can only say that I personally interpreted it as: if, say, Qt::DisplayRole was documented with (QString) at the end of line, it meant that the data() method itself was responsible for converting the underlying value and returning it is a QVariant with a type of QMetaType::QString. And similarly for all the other ItemDataRole cases as appropriate. If the docs had stated "the returned QVariant must be convertible to the specified type for each role" I would have understood. It's always the case that documentation can imply different things to different readers; I did not find it clear. But there you are.

                            Anyway, in the light of this discovery I now understand better what is actually going on, thank you.

                            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