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
Forum Updated to NodeBB v4.3 + New Features

QTableView: updating the model and visible area

Scheduled Pinned Locked Moved General and Desktop
24 Posts 5 Posters 31.9k 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.
  • M Offline
    M Offline
    mohsen
    wrote on 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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
                                  • G Offline
                                    G Offline
                                    goetz
                                    wrote on last edited by
                                    #23

                                    [quote author="dusktreader" date="1295051767"][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.
                                    [/quote][/quote]

                                    Of course I am serious. I know not any C++ programmer who complains about this. And please notice I am talking of C++ programmers. I do not care about Java or any other GC enabled programming language. These do have other drawbacks. If you use C++ you accept its concepts and usage. If you feel too uncomfortable you choose another tool.

                                    [quote author="dusktreader" date="1295051767"]
                                    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]

                                    So you're lost and you'd better choose a programming language or environment or GUI toolkit that is not using model/view for the data display and that does not support multithreading. These environments do not have a need to care about the awkward stuff you're complaining about.

                                    What are you moaning about calculating the location of your data? You must eventually decide where in the view it has to go. The view does not have a crystal ball that tells it that some magic woodaboo in the model has happend and that it has to insert some rows in the table but it's unkown which rows and where to find them... Your model has to tell the view! And you have to in any other toolkit too. If it is really the beginInsertXXX() and endInsertXXX() that makes you feel so uncomfortable then you always could consider using another framework.

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

                                    1 Reply Last reply
                                    0
                                    • D Offline
                                      D Offline
                                      dusktreader
                                      wrote on last edited by
                                      #24

                                      [quote author="Volker" date="1295218048"]
                                      I am angry and condescending. I can't contribute anything useful to the conversation because I am too busy telling other people that they don't know what they are talking about
                                      [/quote]

                                      Volker, thank you for adding some comic relief to my thread.

                                      Gerolf and Andre, thank you for your help and input. I have successfully implemented a solution for my model/view infrastructure. I finished the primary development of my solution today. It comprises a data model bundled with 3 views in single widget that inherits from QFrame. Two of the views provides frozen headers for the columns and rows of arbitrary size. The frozen headers can be toggled on and off. The solution provides an API for easily wrapping a client's custom data structure in a table view format. The client only has to implement a few API functions for data access and view organization. The client doesn't have to know much about Qt's model/view framework to use this solution.

                                      I realized that the cost of calculating locations for row insertions and deletions is not significant as such calculations have to be done repeatedly in the data(), setData(), and flags() functions anyway. Using the beginXXX() and endXXX() paradigm still seems unsatisfactory to me, but I have figured out a solution that works well.

                                      If it is wanted, I may post my solution with a working example in a few days

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

                                      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