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. QTreeView::visualRect and QTreeView::indexAt don't appear to work
Forum Updated to NodeBB v4.3 + New Features

QTreeView::visualRect and QTreeView::indexAt don't appear to work

Scheduled Pinned Locked Moved Solved General and Desktop
qtreeviewqt5.15.1visualrect
12 Posts 4 Posters 2.0k 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.
  • J Offline
    J Offline
    Jos_Rarebit
    wrote on last edited by
    #1

    I'm trying to cache data from the top index so I can scroll the treeview to the right spot after a serious update to the data.

    I've got a slot to handle the modelAboutToBeReset() signal, and it's getting called correctly, and I see that the model is still populated (about 82 rows, for example).

    ttv() is a member accessor to get the QTreeView object. (And further below, tvm() is an accessor for the model, which is custom-made.)

    If I try:

    QModelIndex top = ttv()->indexAt(ttv()->rect().topLeft());

    I get an invalid index. I have also tried passing in QPoint(0,0) and QPoint(5,5), and got the same result.

    I thought I know, I'll reverse engineer this by iterating through the items in the model and get the visualArea, and stop at the first valid one. Then I might get a clue as to what indexAt() is looking for. So, I updated the test code:

    QModelIndex top = ttv()->indexAt(ttv()->rect().topLeft());
    QModelIndex bot = ttv()->indexAt(ttv()->rect().bottomLeft());
    bool found = top.isValid();
    for (int r = 0, nr = tvm()->rowCount();
         !found && r < nr; ++r)
    {
        for (int c = 0, nc = tvm()->columnCount();
             !found && c < nc; ++c)
        {
            auto inx = tvm()->index(r,c);
            QRect vt = ttv()->visualRect(inx);
            qDebug() << inx << vt;
            if (!vt.isValid()) {
                continue;
            }
            found = true;
            auto ctr = vt.center();
            auto zzz = ttv()->indexAt(ctr);
            top = inx;
        }
    }
    if (!top.isValid()) return;
    

    That call to visualRect() never yields a valid rect. I see it iterating through all items in the model, and each one yields a QRect(0,0 0x0). I can imagine I might need to pass in a slightly massaged coordinate to indexAt(), but shouldn't visualRect() return some proper rectangles for any of the items? About 40 or so rows are visible!

    Not sure what I'm doing wrong here, but I'm not getting any traction with either of these APIs.

    1 Reply Last reply
    0
    • J Jos_Rarebit

      @nagesh Thanks for the suggestion. Might be what I have to do. However:

      I think this might be a signal-slot order issue that I'll have to work-around. Or use a different signal/slot. I have been using modelAboutToBeReset() signal, but the treeview itself also uses that, and it gets it first.

      I set a breakpoint in QTreeViewPrivate::_q_modelAboutToBeReset(),

      void QTreeViewPrivate::_q_modelAboutToBeReset()
      {
          viewItems.clear();
      }
      

      which is the treeview's handler, and it is getting called before my own handler.

      Makes sense, given how the signals/slots are generally processed in order of creation.

      J Offline
      J Offline
      Jos_Rarebit
      wrote on last edited by
      #12

      Okay, I had absolutely believed that I had tried making the call to my savePos() function to try to diagnose whether the signal had something to do with it, yet when I disable the connect()ion altogether and call it explicitly, now these APIs want to behave like good little children and do what they're supposed to.

      So, essentially I shot myself in the foot by handling this with modelAboutToBeReset(), which implicitly trashes the internal cache of visible indexes.

      D'oh! Argh, etc.

      Thanks for the help, folks.

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

        Hi and welcome to devnet,

        I may be missing your goal but wouldn't use QTreeView::scrollTo do the job ?

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

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

          Apart from @SGaist 's question - is ttv()->model() really tvm() or is there a proxy model in between?

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

          J 1 Reply Last reply
          0
          • SGaistS SGaist

            Hi and welcome to devnet,

            I may be missing your goal but wouldn't use QTreeView::scrollTo do the job ?

            J Offline
            J Offline
            Jos_Rarebit
            wrote on last edited by
            #4

            @SGaist Thanks for the speedy reply.

            scrollTo() will be what I will use when I've recovered the index based on what I've cached. The model may be changing quite a bit, so I'm trying to find the locale of the currently viewed set of objects, cache that information, then when the model is reset, I'll try to scroll back to the approximate location, perhaps simply bringing that item back to the top if I can, or finding data in the same range (it's a table of date-stamped rows).

            Since I can't see what's currently in the viewport, I can't figure out what data to grab onto, which I would use to find on the flip side after the model update.

            Does that make sense? Surely I'm making some simple mistake or have a wrong assumption. Why wouldn't these APIs "just work"?

            1 Reply Last reply
            0
            • Christian EhrlicherC Christian Ehrlicher

              Apart from @SGaist 's question - is ttv()->model() really tvm() or is there a proxy model in between?

              J Offline
              J Offline
              Jos_Rarebit
              wrote on last edited by
              #5

              @Christian-Ehrlicher Yes, ttv()->model() == tvm(). No proxy. At some point I may use a sort proxy, but I wanted to keep it simple for the time being.

              1 Reply Last reply
              0
              • nageshN Offline
                nageshN Offline
                nagesh
                wrote on last edited by
                #6

                @Jos_Rarebit said in QTreeView::visualRect and QTreeView::indexAt don't appear to work:

                modelAboutToBeReset()

                @Jos_Rarebit you have mentioned about handling model reset in modelAboutToBeReset() slot.
                If model is getting reset, then old index may not valid for the new model.

                https://doc.qt.io/qt-5/qabstractitemmodel.html#modelReset

                J 1 Reply Last reply
                0
                • nageshN nagesh

                  @Jos_Rarebit said in QTreeView::visualRect and QTreeView::indexAt don't appear to work:

                  modelAboutToBeReset()

                  @Jos_Rarebit you have mentioned about handling model reset in modelAboutToBeReset() slot.
                  If model is getting reset, then old index may not valid for the new model.

                  https://doc.qt.io/qt-5/qabstractitemmodel.html#modelReset

                  J Offline
                  J Offline
                  Jos_Rarebit
                  wrote on last edited by
                  #7

                  @nagesh I'm not intending to cache any indexes, just find what the visible indexes are. This code is being invoked in response to modelAboutToBeReset(), so the index changes haven't happened yet, anyway. In fact, if I explicitly call the function before the call which causes the model reset, it still does not work.

                  Anyone have any ideas?

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

                    Shouldn't you store some identifying data of the visible indexes before the model is changed, then look for the same data and call scrollTo with the appropriate index ?

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

                    J 1 Reply Last reply
                    0
                    • SGaistS SGaist

                      Shouldn't you store some identifying data of the visible indexes before the model is changed, then look for the same data and call scrollTo with the appropriate index ?

                      J Offline
                      J Offline
                      Jos_Rarebit
                      wrote on last edited by
                      #9

                      @SGaist Yes. That's exactly what I intend to do. Sorry if that wasn't clear.
                      The issue is that there doesn't seem to be a way of determining what the visible indexes are. Hence the title of this topic. Or, rather, there is a presumed way to do this, but the API(s) to be used do)es(n't seem to work as expected. So, that's weird!

                      Stepping into the Qt code a bit (what I wanted to avoid!) it seems that QTreeView::visualRect() has no "viewIndex" data for the items in the model. I.e., here's the spot in QTreeView::visualRect() where it appears to be punting:

                      // QTreeView::visualRect...
                      Q_D(const QTreeView);
                      
                      if (!d->isIndexValid(index) || isIndexHidden(index))
                          return QRect();
                      
                      d->executePostedLayout();
                      
                      int vi = d->viewIndex(index);
                      if (vi < 0)
                          return QRect();
                      

                      It returns because vi == -1.

                      I am wondering if my model implementation is deficient in some way. It compiles, so the basic overrides are present. It's basically a model interface of a std::list<> of some class objects, so I don't do anything with insertRows(), I just pretend to reset the model when the underlying data gets rebuilt. But I kind of wonder if the view needs some extra hints to cache some geometry about what it's displaying for this purpose. But it's displaying everything in my model perfectly well, so what could it be? If I emit signals about rows being inserted, that doesn't seem to do anything magical, but then again I'm still not implementing insertRows directly...

                      Hmm... I guess I'll step into that viewIndex function...

                      1 Reply Last reply
                      0
                      • nageshN Offline
                        nageshN Offline
                        nagesh
                        wrote on last edited by
                        #10

                        @Jos_Rarebit

                        so I don't do anything with insertRows(), I just pretend to reset the model when the underlying data gets rebuilt.
                        

                        Refer to addressbook example in Qt for dynamic model.
                        I think you should implement insertRows() if your model is dynamic

                        J 1 Reply Last reply
                        0
                        • nageshN nagesh

                          @Jos_Rarebit

                          so I don't do anything with insertRows(), I just pretend to reset the model when the underlying data gets rebuilt.
                          

                          Refer to addressbook example in Qt for dynamic model.
                          I think you should implement insertRows() if your model is dynamic

                          J Offline
                          J Offline
                          Jos_Rarebit
                          wrote on last edited by
                          #11

                          @nagesh Thanks for the suggestion. Might be what I have to do. However:

                          I think this might be a signal-slot order issue that I'll have to work-around. Or use a different signal/slot. I have been using modelAboutToBeReset() signal, but the treeview itself also uses that, and it gets it first.

                          I set a breakpoint in QTreeViewPrivate::_q_modelAboutToBeReset(),

                          void QTreeViewPrivate::_q_modelAboutToBeReset()
                          {
                              viewItems.clear();
                          }
                          

                          which is the treeview's handler, and it is getting called before my own handler.

                          Makes sense, given how the signals/slots are generally processed in order of creation.

                          J 1 Reply Last reply
                          0
                          • J Jos_Rarebit

                            @nagesh Thanks for the suggestion. Might be what I have to do. However:

                            I think this might be a signal-slot order issue that I'll have to work-around. Or use a different signal/slot. I have been using modelAboutToBeReset() signal, but the treeview itself also uses that, and it gets it first.

                            I set a breakpoint in QTreeViewPrivate::_q_modelAboutToBeReset(),

                            void QTreeViewPrivate::_q_modelAboutToBeReset()
                            {
                                viewItems.clear();
                            }
                            

                            which is the treeview's handler, and it is getting called before my own handler.

                            Makes sense, given how the signals/slots are generally processed in order of creation.

                            J Offline
                            J Offline
                            Jos_Rarebit
                            wrote on last edited by
                            #12

                            Okay, I had absolutely believed that I had tried making the call to my savePos() function to try to diagnose whether the signal had something to do with it, yet when I disable the connect()ion altogether and call it explicitly, now these APIs want to behave like good little children and do what they're supposed to.

                            So, essentially I shot myself in the foot by handling this with modelAboutToBeReset(), which implicitly trashes the internal cache of visible indexes.

                            D'oh! Argh, etc.

                            Thanks for the help, folks.

                            1 Reply Last reply
                            1

                            • Login

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