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: updating the model and visible area
QtWS25 Last Chance

QTableView: updating the model and visible area

Scheduled Pinned Locked Moved General and Desktop
24 Posts 5 Posters 31.8k 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.
  • G Offline
    G Offline
    giesbert
    wrote on 14 Jan 2011, 08:10 last edited by
    #3

    To question1:

    there is an article in the online help regarding "Model-View":http://doc.qt.nokia.com/latest/model-view-programming.html which is quite long. If you change something inside your model, you have to call some methods emit some signals:

    • Changing a value MUST lead to emit dataChanged(...)
    • adding rows / columns must be sourounded by beginInsertRows(...) and endInsertRows(...) respectively beginInsertColumns(...) and endInsertColumns(...)
    • same applies to removing of rows / columns (beginRemove...)
    • if you are ching much, you could also call reset() inside the model, so the view must reinitialise itself (--> selections are away after that, the view starts in row 0, opened items are closed here)

    This all must be done from within model2 then.
    The connected views will update automatically then.

    In the German wiki, we are working on a MVC tutorial which is (hopefully) easy to understand later on, but it's in starting phase and will take some time to finish it. I think, when it's finished and the others say, it's good, we will also translate it to English and put it to the main wiki.

    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
    • G Offline
      G Offline
      giesbert
      wrote on 14 Jan 2011, 08:16 last edited by
      #4

      To question2:

      you could try columnAt / rowAt if you are using a QTableView.
      also "indexAt()":http://doc.qt.nokia.com/latest/qtableview.html#indexAt could help

      for restoring, you could use: "scrollTo()":http://doc.qt.nokia.com/latest/qabstractitemview.html#scrollTo

      You could also get the position out of the scrollbars:

      @
      QAbstractScrollArea::horizontalScrollBar ()->value ()
      @

      but that does not give you the model indexes.

      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
      • M Offline
        M Offline
        mohsen
        wrote on 14 Jan 2011, 08:57 last edited by
        #5

        @Gerolf: as i understand he need only those records which are visible to user; then he can limit the big process to lowless targeted for only few items. is this possible?

        1 Reply Last reply
        0
        • A Offline
          A Offline
          andre
          wrote on 14 Jan 2011, 09:18 last edited by
          #6

          No, that's not what dusktreader asked.

          If you want to know the model index at a certain point in your view, use QAbstractItemView::indexAt(). Create a QPersistentItemIndex, and use that index to restore the view later on with the scrollTo that Gerolf pointed out earlier.

          1 Reply Last reply
          0
          • M Offline
            M Offline
            mohsen
            wrote on 14 Jan 2011, 09:31 last edited by
            #7

            @Andre: so i'll make a threat to ask this

            EDIT: "in this thread":http://developer.qt.nokia.com/forums/viewthread/3194/ (Gerolf)

            1 Reply Last reply
            0
            • G Offline
              G Offline
              goetz
              wrote on 14 Jan 2011, 12:01 last edited by
              #8

              Regarding the first question:

              Model1 sends signals, which view1 connects to and redraws the changed parts.

              You can connect newly added slots of your model2 to the very same signals of model1 (dataChanged(), rowsInserted(), columnsInsert() etc.) and manipulate model2 accordingly. If you do it "the right" way (i.e. using beginInsertRows(), endInsertRows(), dataChanged(), etc. - see Gerolfs answer) your view2 is signaled too and updates itself.

              http://www.catb.org/~esr/faqs/smart-questions.html

              1 Reply Last reply
              0
              • D Offline
                D Offline
                dusktreader
                wrote on 14 Jan 2011, 19:21 last edited by
                #9

                [quote author="Gerolf" date="1294992644"]

                • Changing a value MUST lead to emit dataChanged(...)
                  [/quote]

                Do I need to explicitly connect this to a slot in my QTableView?

                “Machines take me by surprise with great frequency.” -- Alan Mathison Turing

                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  dusktreader
                  wrote on 14 Jan 2011, 19:24 last edited by
                  #10

                  [quote author="Gerolf" date="1294993008"]
                  you could try columnAt / rowAt if you are using a QTableView.
                  also "indexAt()"
                  [/quote]

                  That is all fine and good, but how do I find the positional coordinates of the view? Could I just call

                  @QModelIndex ul = tblView.indexAt( QPoint( 0, 0 ) );
                  // do some stuff
                  tblView.scrollTo( ul );@

                  “Machines take me by surprise with great frequency.” -- Alan Mathison Turing

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    andre
                    wrote on 14 Jan 2011, 19:45 last edited by
                    #11

                    [quote author="dusktreader" date="1295032882"][quote author="Gerolf" date="1294992644"]

                    • Changing a value MUST lead to emit dataChanged(...)
                      [/quote]

                    Do I need to explicitly connect this to a slot in my QTableView?
                    [/quote]
                    No, you don't. Your view will connect to the appropriate signals in the model when you set the model on the view using setModel(). You just need to make sure the signal is emitted (if you subclassed QAbstractItemModel or one of the other Qt item models; if you use an existing model, you can trust it will behave correctly.)

                    1 Reply Last reply
                    0
                    • D Offline
                      D Offline
                      dusktreader
                      wrote on 14 Jan 2011, 20:10 last edited by
                      #12

                      My Model implementation wraps a QMap, so each entry of the map is displayed as a row. If I add an entry into the QMap, do I first have to calculate the row on which the new entry will be displayed and call beginInsertRows(), or can I modify the QMap and then call begin/endInsertRows() after the fact?

                      “Machines take me by surprise with great frequency.” -- Alan Mathison Turing

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        andre
                        wrote on 14 Jan 2011, 20:13 last edited by
                        #13

                        The proper order is: call beginInsertRows, do the actual insert (modify your data), call endInsertRows. See also the first posting by Volker:
                        [quote]adding rows / columns must be sourounded by beginInsertRows(...) and endInsertRows(...) respectively beginInsertColumns(...) and endInsertColumns(...)[/quote]

                        1 Reply Last reply
                        0
                        • D Offline
                          D Offline
                          dusktreader
                          wrote on 14 Jan 2011, 20:34 last edited by
                          #14

                          [quote author="Andre" date="1295035987"]The proper order is: call beginInsertRows, do the actual insert (modify your data), call endInsertRows. See also the first posting by Volker:
                          [quote]adding rows / columns must be sourounded by beginInsertRows(...) and endInsertRows(...) respectively beginInsertColumns(...) and endInsertColumns(...)[/quote][/quote]

                          This is such an awkward interface. Also, it introduces a great deal of risk. What happens if one of the calls is made and not the other.

                          “Machines take me by surprise with great frequency.” -- Alan Mathison Turing

                          1 Reply Last reply
                          0
                          • G Offline
                            G Offline
                            giesbert
                            wrote on 14 Jan 2011, 21:14 last edited by
                            #15

                            Then the view does not update :-)

                            You could also call beginXXX endXXX after changing the values, theoretically... but it could lead to unexpected behavior... If you only have one thread, it could perhaps work....

                            but calling beginXXX endXXX tells the view NOT to call other methods of the model in between.

                            It's a bit tricky but it's well described and there are examples that also describe it.

                            [quote author="dusktreader" date="1295033080"][quote author="Gerolf" date="1294993008"]
                            you could try columnAt / rowAt if you are using a QTableView.
                            also "indexAt()"
                            [/quote]

                            That is all fine and good, but how do I find the positional coordinates of the view? Could I just call

                            @QModelIndex ul = tblView.indexAt( QPoint( 0, 0 ) );
                            // do some stuff
                            tblView.scrollTo( ul );@[/quote]

                            you want the visible indizes, so try the visible rect of the scrollarea (look at QAbstractScrollArea, which is a base class of all views)

                            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
                            • G Offline
                              G Offline
                              goetz
                              wrote on 14 Jan 2011, 22:51 last edited by
                              #16

                              [quote author="dusktreader" date="1295037273"]This is such an awkward interface. Also, it introduces a great deal of risk. What happens if one of the calls is made and not the other.[/quote]

                              It is well described in the docs. Programming is always a great deal of risk. If you forget the second call your program will probably fail. It's not different to, say, allocating new objects on the heap with new; you eventually will have to clean up the mess with delete some time. If you forget this you will run into problems too. That's awkward too - oddly enough nobody complains about this.

                              Some background:
                              It would work as you described, if the model is only used for at most one view and it is manipulated only from the GUI thread. Otherwise it is crucial to inform the view that some change in the model's data will happen, so that the view(s) can stop manipulating the data itself to prevent them from changing the same data from different places. See it as a kind of mutex or semaphore.

                              http://www.catb.org/~esr/faqs/smart-questions.html

                              1 Reply Last reply
                              0
                              • D Offline
                                D Offline
                                dusktreader
                                wrote on 15 Jan 2011, 00:36 last edited by
                                #17

                                [quote author="Volker" date="1295045477"]That's awkward too - oddly enough nobody complains about this.[/quote]

                                Surely you aren't serious? Allocation problems are almost the entire motivation for the development of garbage-collectors in the newer dynamic languages. Mis-allocation presents massive risks and results in unimaginable quantities of wasted time in debugging and testing. Every programmer I have ever met complains about this.

                                My main concern with this interface is that it requires the Model to know where new data is going to be inserted. If the model is wrapping a complex data structure, it may be very costly to calculate the index location of the new data.

                                I realize that any Model/View framework is going to plagued with synchronization problems. I'm just frustrated by having to know precisely where the new data is going to be inserted.

                                “Machines take me by surprise with great frequency.” -- Alan Mathison Turing

                                1 Reply Last reply
                                0
                                • G Offline
                                  G Offline
                                  giesbert
                                  wrote on 15 Jan 2011, 08:49 last edited by
                                  #18

                                  [quote author="dusktreader" date="1295051767"][quote author="Volker" date="1295045477"]That's awkward too - oddly enough nobody complains about this.[/quote]

                                  My main concern with this interface is that it requires the Model to know where new data is going to be inserted. If the model is wrapping a complex data structure, it may be very costly to calculate the index location of the new data.

                                  I realize that any Model/View framework is going to plagued with synchronization problems. I'm just frustrated by having to know precisely where the new data is going to be inserted.[/quote]

                                  If you don'T know where new data is going to, how do you know where to present it to the view? The view is not always asking for all data, it just queries the data of one cell... So you have to calculate the index and from the index to your structure anyways. I Implemented many models and I never had the problem of finding the position where some data will go to.

                                  The other posibility would be to do the MFC way: The document just tells: changed. and it's the views part to calculate, what was changed, its different and worse....

                                  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 15 Jan 2011, 09:51 last edited by
                                    #19

                                    [quote author="dusktreader" date="1295037273"]What happens if one of the calls is made and not the other.[/quote]
                                    What happens, I can not tell you, but I know what happend: you made a programming mistake :-)
                                    I am not saying it is ideal, but the problem is that you put the model in an inconsistent state if you change the data in the backend before telling that to the model (and connected views). That could lead to big problems. Perhaps it would be more convenient if it would (optionally?) work the other way around: you tell the model that you're going to insert rows, and when done, tell it where you did that. However, don't count on changes like that happening anymore.

                                    If you worry about forgetting the endInsertRows call, then I would suggest you create a RAII class to handle it for you. That way, you can be sure the corresponding method is always called. I do for other cases sometimes too (like for SQL transactions, and for painter save/restores). They are simple enough to write

                                    About the multi-threaded argument made by Volker above: I don't think that this makes it any safer to do multi-threaded models at all. I think that is one of it's shortcommings: it is hard to make a good multi-threaded model. Could you (Volker) perhaps explain how this API helps in getting a nice multi-threaded model implementation?

                                    1 Reply Last reply
                                    0
                                    • G Offline
                                      G Offline
                                      giesbert
                                      wrote on 15 Jan 2011, 10:03 last edited by
                                      #20

                                      It does not help in doing this, but it prevents the views from aquiring data from the model if the model accesses data that is stored in some backend class that is changed from another thread.

                                      Think of some threads in the background working on the data, and from time to time changing the data. Thats the point where you have to tell the view: don't access or change the data in the range of a to b. If everything is inside a single thread and you emit no signals, it's nearly save to just call beginXXX() and endXXX() directly at the end, as no view can access the data at any time (it's only one thread).

                                      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 15 Jan 2011, 10:33 last edited by
                                        #21

                                        I don't think the suggestion that you can safely call beginXXX() and endXXX() directly at the end of your operation is good advice. You never know what happens in other parts of the code. If somebody calls processEvents(), you may already be screwed.

                                        I understand that the mechanism could help, but I think you need quite a bit more to make it work properly. For instance, I think that you would need the beginXXX() to be a synchronization point: don't start to change the data untill you are sure that the GUI thread has actually called beginXXX(), otherwise you may still have data access while changing that data from another thread.

                                        1 Reply Last reply
                                        0
                                        • G Offline
                                          G Offline
                                          giesbert
                                          wrote on 15 Jan 2011, 15:06 last edited by
                                          #22

                                          ThatÄ's why I said it's nearly safe not it's safe. If there are no asynchronous things inside your program, I mean really no, then it could work, I already saw code where it worked. But then you MUST ensure, that this never changes. I did not say, do it that way. I will never say that it's a good solution to do it in the end, do beginXXX() at the beginning and endXXX() at the end.

                                          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

                                          12/24

                                          14 Jan 2011, 20:10

                                          • Login

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