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. Choose between model/view or other approach
QtWS25 Last Chance

Choose between model/view or other approach

Scheduled Pinned Locked Moved Unsolved General and Desktop
15 Posts 5 Posters 1.2k 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.
  • M Offline
    M Offline
    mix359
    wrote on last edited by
    #1

    Hi to all,

    I'm working on a custom widget for a project that should became a timeline editor, like the one used in the video/audio editing software.

    I'm relatively new to the Qt framework and facing some issue projecting and implementing the structure I have in mind with this framework.

    My basic idea is that I will have a main component that should work as a list of tracks or track groups (that should contains their relative tracks or other groups).
    Every track have his own data and have as child a list of clips.
    Every clips have his own data.

    I've a general idea of how to implement that structure visually, but I'm struggling projecting the class structure that should keep the data and communicate with the widgets.
    My first implementation was based on some simple class Track, TrackGroup and Clip, that's the simplest/lightest structure come to my mind, but with this structure I can't update the widget dynamically when a data is set.
    I've request here on the forum a way to implement something like the reactivity that some javascript framework like vuejs have and someone point me to the model/view structure in Qt (a sort of Observable Pattern), used for example for the QListView component, that can solve part of my problem: a view that react to the data change.
    So I've studied how to implement the model/view pattern in my structure finding many little doubt that it's stopping me from considering the model/view the right path from my project (at least the Qt implementation):

    • First of all, looking at the implementation like in the Simple Tree Model Example, I don't understand why I have to implement a Model object that doesn't contain the real data, and I should put the real data in an Item object that is referenced in the Model. Cannot I put the data directly in the Model? Doesn't this Model-Item approach consume more memory?
    • Second, In my case I have a sort of tree structure, at least for the Tracks and Track Groups structure, so probably the best idea is to implement the QAbstractItemModel interface. The doubt is because those type of objects are different: they have different data and different type of child, and should be rendered completely differently. Is the tree structure the right way?
    • Third, looking how many thing I have to implement with this pattern I've noticed that I should use many generic call/data type, like the data/setData function, based on column concept, and the QVariant, while I have many specific data and function that should do particular thing when the data is set.

    So my question is if the model/view pattern is the right choice for my project.
    Looking at the pros I have an event based system that update the view when I change the data and I have a system that manage the selection and the drag&drop ready to use (only to implement/adjust), the cons is that I should implement many thing in my widgets to make some of the function present in some other standard widget less generic and like I want (or completely rewrite it from a basic widget if it's less harder that completely change something like a QListView/QTreeView in something other).

    I hope someone could help me clarifying my ideas :)

    PS: If you can, please, argue why you think a solution is better than another.
    Thanks to all
    Cheers
    Mix

    JonBJ 1 Reply Last reply
    0
    • M mix359

      Hi to all,

      I'm working on a custom widget for a project that should became a timeline editor, like the one used in the video/audio editing software.

      I'm relatively new to the Qt framework and facing some issue projecting and implementing the structure I have in mind with this framework.

      My basic idea is that I will have a main component that should work as a list of tracks or track groups (that should contains their relative tracks or other groups).
      Every track have his own data and have as child a list of clips.
      Every clips have his own data.

      I've a general idea of how to implement that structure visually, but I'm struggling projecting the class structure that should keep the data and communicate with the widgets.
      My first implementation was based on some simple class Track, TrackGroup and Clip, that's the simplest/lightest structure come to my mind, but with this structure I can't update the widget dynamically when a data is set.
      I've request here on the forum a way to implement something like the reactivity that some javascript framework like vuejs have and someone point me to the model/view structure in Qt (a sort of Observable Pattern), used for example for the QListView component, that can solve part of my problem: a view that react to the data change.
      So I've studied how to implement the model/view pattern in my structure finding many little doubt that it's stopping me from considering the model/view the right path from my project (at least the Qt implementation):

      • First of all, looking at the implementation like in the Simple Tree Model Example, I don't understand why I have to implement a Model object that doesn't contain the real data, and I should put the real data in an Item object that is referenced in the Model. Cannot I put the data directly in the Model? Doesn't this Model-Item approach consume more memory?
      • Second, In my case I have a sort of tree structure, at least for the Tracks and Track Groups structure, so probably the best idea is to implement the QAbstractItemModel interface. The doubt is because those type of objects are different: they have different data and different type of child, and should be rendered completely differently. Is the tree structure the right way?
      • Third, looking how many thing I have to implement with this pattern I've noticed that I should use many generic call/data type, like the data/setData function, based on column concept, and the QVariant, while I have many specific data and function that should do particular thing when the data is set.

      So my question is if the model/view pattern is the right choice for my project.
      Looking at the pros I have an event based system that update the view when I change the data and I have a system that manage the selection and the drag&drop ready to use (only to implement/adjust), the cons is that I should implement many thing in my widgets to make some of the function present in some other standard widget less generic and like I want (or completely rewrite it from a basic widget if it's less harder that completely change something like a QListView/QTreeView in something other).

      I hope someone could help me clarifying my ideas :)

      PS: If you can, please, argue why you think a solution is better than another.
      Thanks to all
      Cheers
      Mix

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

      @mix359
      This is a big question! Certainly model-view may help you. It's just a generic way to approach this.

      For others to maybe comment further, you might like to clarify the following:

      • but with this structure I can't update the widget dynamically when a data is set.

      Why/what?

      • I don't understand why I have to implement a Model object that doesn't contain the real data, and I should put the real data in an Item object that is referenced in the Model. Cannot I put the data directly in the Model?

      I don't get this?

      • Where are you going to get all your track/group/clip data from? For example, are they coming out of a database?
      M 1 Reply Last reply
      2
      • JonBJ JonB

        @mix359
        This is a big question! Certainly model-view may help you. It's just a generic way to approach this.

        For others to maybe comment further, you might like to clarify the following:

        • but with this structure I can't update the widget dynamically when a data is set.

        Why/what?

        • I don't understand why I have to implement a Model object that doesn't contain the real data, and I should put the real data in an Item object that is referenced in the Model. Cannot I put the data directly in the Model?

        I don't get this?

        • Where are you going to get all your track/group/clip data from? For example, are they coming out of a database?
        M Offline
        M Offline
        mix359
        wrote on last edited by
        #3

        @JonB Thanks for the reply

            For others to maybe comment further, you might like to clarify the following:
        
                    but with this structure I can't update the widget dynamically when a data is set.
        

        Well, I can do that but not with a simple c++ object. I would probably have to use a simple QObject and implement some signal/event to emit when a change is done (or is going to append).
        As at first that sound better to me, because I will implement only the signal I really need and it will be cleaner, but to reach all the feature I have in mind, I would probably have to make many signals similar to the one used in the QAbstractItemModel (or some descendant implementation) so I wouldn't end reinventing the wheel.
        At the moment I don't have a full idea of how QAbstractItemModel work/is implemented so that's why I was asking here, otherwise I should probably read all the framework code to understand if is worth to use it or it's better to not use it. (The documentation is not enough to understand that)

            Why/what?
        
                    I don't understand why I have to implement a Model object that doesn't contain the real data, and I should put the real data in an Item object that is referenced in the Model. Cannot I put the data directly in the Model?
        

        Looking at the Simple Tree Model Example I see that the real data is stored in a QList<QVariant> m_itemData inside the TreeItem object.
        I don't understand why this data and the parent/child relationship aren't stored directly inside the TreeModel class?

            Where are you going to get all your track/group/clip data from? For example, are they coming out of a database?
        

        I would probably load all the data from a file into the heap (as objects).

        Thanks again
        Cheers Mix

        1 Reply Last reply
        0
        • KillerSmathK Offline
          KillerSmathK Offline
          KillerSmath
          wrote on last edited by KillerSmath
          #4

          @mix359

          Looking at the Simple Tree Model Example I see that the real data is stored in a QList<QVariant> m_itemData inside the TreeItem object.
          I don't understand why this data and the parent/child relationship aren't stored directly inside the TreeModel class?

          The advantage of ​​this separatation is related with class cohesion. In this example, the TreeItem resposability is child, data and parent management. While the model is responsible for how to insert, edit or remove the data.
          However, the point of this modeling idea is that TreeItem has parent that is another TreeItem that can be list of datas and another parent...

          Third, looking how many thing I have to implement with this pattern I've noticed that I should use many generic call/data type, like the data/setData function, based on column concept, and the QVariant, while I have many specific data and function that should do particular thing when the data is set.

          In model design, you should consider how the date will be retrieved and manipulated. This partitioning makes it easier to locate the problem.

          @Computer Science Student - Brazil
          Web Developer and Researcher
          “Sometimes it’s the people no one imagines anything of who do the things that no one can imagine.” - Alan Turing

          M 1 Reply Last reply
          2
          • KillerSmathK KillerSmath

            @mix359

            Looking at the Simple Tree Model Example I see that the real data is stored in a QList<QVariant> m_itemData inside the TreeItem object.
            I don't understand why this data and the parent/child relationship aren't stored directly inside the TreeModel class?

            The advantage of ​​this separatation is related with class cohesion. In this example, the TreeItem resposability is child, data and parent management. While the model is responsible for how to insert, edit or remove the data.
            However, the point of this modeling idea is that TreeItem has parent that is another TreeItem that can be list of datas and another parent...

            Third, looking how many thing I have to implement with this pattern I've noticed that I should use many generic call/data type, like the data/setData function, based on column concept, and the QVariant, while I have many specific data and function that should do particular thing when the data is set.

            In model design, you should consider how the date will be retrieved and manipulated. This partitioning makes it easier to locate the problem.

            M Offline
            M Offline
            mix359
            wrote on last edited by
            #5

            @KillerSmath thanks

            Can you please make me an example of why it's easier work in this way?
            What's the disavvantage of having the data and the method that use/manipule that inside the same object?

            Meanwhile I'm doing some test with the QAbstractItemModel and I've found another "disadvantage" of this method: the data is required using a row or a row + column system, but let say I want to have the color of a track, if I understand well I have to define that for example the column 2 is the color, the column 1 is the name, etc, so to have the color of a track I need to create an index that point to the row + column 2?
            Or I should ignore the column and use the Role to have the right information? In that case, how could I set that?
            I'm finding this way of working with the model more confusing than having a model with some getter/setter for his properties, that emit signal when a setter is called.

            Thanks
            Cheers Mix ;)

            JonBJ 1 Reply Last reply
            0
            • M mix359

              @KillerSmath thanks

              Can you please make me an example of why it's easier work in this way?
              What's the disavvantage of having the data and the method that use/manipule that inside the same object?

              Meanwhile I'm doing some test with the QAbstractItemModel and I've found another "disadvantage" of this method: the data is required using a row or a row + column system, but let say I want to have the color of a track, if I understand well I have to define that for example the column 2 is the color, the column 1 is the name, etc, so to have the color of a track I need to create an index that point to the row + column 2?
              Or I should ignore the column and use the Role to have the right information? In that case, how could I set that?
              I'm finding this way of working with the model more confusing than having a model with some getter/setter for his properties, that emit signal when a setter is called.

              Thanks
              Cheers Mix ;)

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

              @mix359

              I'm finding this way of working with the model more confusing than having a model with some getter/setter for his properties, that emit signal when a setter is called.

              But you do have that? QAbstractItemModel::data(), QAbstractItemModel::setData(), and the QAbstractItemModel::dataChanged() signal, do each of these respectively. Meanwhile, you write your class(es) to inherit from that and expose stuff as dedicated getter/setters as you see fit.

              M 1 Reply Last reply
              1
              • JonBJ JonB

                @mix359

                I'm finding this way of working with the model more confusing than having a model with some getter/setter for his properties, that emit signal when a setter is called.

                But you do have that? QAbstractItemModel::data(), QAbstractItemModel::setData(), and the QAbstractItemModel::dataChanged() signal, do each of these respectively. Meanwhile, you write your class(es) to inherit from that and expose stuff as dedicated getter/setters as you see fit.

                M Offline
                M Offline
                mix359
                wrote on last edited by
                #7

                @JonB thanks :)
                So you're suggesting to implement the setters and calling the QAbstractItemModel::dataChanged() signal? Is that enough?
                And for the QAbstractItemModel::data() and QAbstractItemModel::setData()? I have to implement that like a sort of noop? Or I have to implement that for compatibility, for example returning the track/clip name when data is called with DisplayRole?

                Thanks again
                Cheers Mix

                JonBJ 1 Reply Last reply
                0
                • M mix359

                  @JonB thanks :)
                  So you're suggesting to implement the setters and calling the QAbstractItemModel::dataChanged() signal? Is that enough?
                  And for the QAbstractItemModel::data() and QAbstractItemModel::setData()? I have to implement that like a sort of noop? Or I have to implement that for compatibility, for example returning the track/clip name when data is called with DisplayRole?

                  Thanks again
                  Cheers Mix

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

                  @mix359
                  I don't really understand your question (this is often the case for me!). Given that you have whatever data structures you want for your tracks etc., your derived class will implement QAbstractItemModel::data() to return whatever is appropriate out of your data model. And if you need setData() (only read-write models do) that will set whatever in your model, and raise dataChanged. In this derived class you can also write whatever methods you feel like to "wrap" certain data/setData() methods with dedicated get/setters, for your convenience.

                  M 1 Reply Last reply
                  1
                  • JonBJ JonB

                    @mix359
                    I don't really understand your question (this is often the case for me!). Given that you have whatever data structures you want for your tracks etc., your derived class will implement QAbstractItemModel::data() to return whatever is appropriate out of your data model. And if you need setData() (only read-write models do) that will set whatever in your model, and raise dataChanged. In this derived class you can also write whatever methods you feel like to "wrap" certain data/setData() methods with dedicated get/setters, for your convenience.

                    M Offline
                    M Offline
                    mix359
                    wrote on last edited by
                    #9

                    @JonB Sorry, probably the question wasn't clear...

                    Looking at the QAbstractItemModel system I see that al the data is requested and passed pointing at with an index and using a role. I would have many types of data and is not represented by the role system, so I would benefit from having a normal getter/setter (for example name/setName) system on the model instead of the data/setData methods.
                    If I understand well, I simply need to emit the dataChanged signal when one of my setter is called, right?
                    Or this way of using the model upset the idea of how the models work here in Qt?

                    Thanks
                    Cheers Mix

                    mrjjM JonBJ 2 Replies Last reply
                    0
                    • M mix359

                      @JonB Sorry, probably the question wasn't clear...

                      Looking at the QAbstractItemModel system I see that al the data is requested and passed pointing at with an index and using a role. I would have many types of data and is not represented by the role system, so I would benefit from having a normal getter/setter (for example name/setName) system on the model instead of the data/setData methods.
                      If I understand well, I simply need to emit the dataChanged signal when one of my setter is called, right?
                      Or this way of using the model upset the idea of how the models work here in Qt?

                      Thanks
                      Cheers Mix

                      mrjjM Offline
                      mrjjM Offline
                      mrjj
                      Lifetime Qt Champion
                      wrote on last edited by mrjj
                      #10

                      @mix359
                      Hi If you don't follow the Model View convention using roles and ModelIndex, none
                      of the normal view would be able to use your model.
                      The virtual function for the QAbstractItemModel defines the interfaces to the view so
                      you must return data via QAbstractItemModel::data()
                      However, its up to you how the actual data is stored behind the scene as long as
                      you follow the interface.
                      If you look at this sample
                      https://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html
                      it stores the data in
                      QVector<QVariant> itemData;
                      However, that could have been anything as the Views dont care, they just ask for data/setData as always.

                      1 Reply Last reply
                      2
                      • M mix359

                        @JonB Sorry, probably the question wasn't clear...

                        Looking at the QAbstractItemModel system I see that al the data is requested and passed pointing at with an index and using a role. I would have many types of data and is not represented by the role system, so I would benefit from having a normal getter/setter (for example name/setName) system on the model instead of the data/setData methods.
                        If I understand well, I simply need to emit the dataChanged signal when one of my setter is called, right?
                        Or this way of using the model upset the idea of how the models work here in Qt?

                        Thanks
                        Cheers Mix

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

                        @mix359
                        Briefly: You are attempting to by-pass/replace the data/setData() methodology. No, you cannot emit dataChanged in such a case.

                        What @mrjj is saying is 100% correct. If you wish to use model/view you must respect the data() way of working. If not, then either there is no point using model/view or things will actually go wrong. You may supply dedicated get/setters in your derived class which present the data in that way, but underneath still call data/setData() to do the work; you must not have them be "standalone" and not use data() at all.

                        1 Reply Last reply
                        2
                        • M Offline
                          M Offline
                          mix359
                          wrote on last edited by mix359
                          #12

                          Thanks for the answers, I'm taking the piece of the puzzle together :)
                          So back to the original question: I'll probably doesn't need to use my model with other widget, I will create custom widgets that use my data.
                          Does it worth to use the model/view system if I have to adapt it (creating many custom roles, etc) to my necessities?

                          Cheers Mix

                          1 Reply Last reply
                          0
                          • fcarneyF Offline
                            fcarneyF Offline
                            fcarney
                            wrote on last edited by
                            #13

                            @mix359,
                            I am curious. What data do you think would not be able to be represented efficiently by the roles approach of data?

                            C++ is a perfectly valid school of magic.

                            M 1 Reply Last reply
                            0
                            • fcarneyF fcarney

                              @mix359,
                              I am curious. What data do you think would not be able to be represented efficiently by the roles approach of data?

                              M Offline
                              M Offline
                              mix359
                              wrote on last edited by
                              #14

                              @fcarney It's not a matter of efficiency, because many of the data are simple data that can be represented with a derivation of QVariant, so I can probably put all of this data in a QList o QMap.

                              It's a matter of control of data and operation that I can do to it, for example parse an input that is given to me from the widget and save it in some other way i need (thing that can be normally done in a getter or setter function).
                              With the model/view interface I will have to do the operation for all of the properties in the same data/setData function.

                              The problem with the roles system is that I have many particular data like for an audio track if it's enabled (bool), if it's soloed (bool), his volume (float), a send volume (float), his height (int), his output channel, and so on... So I would have to create many custom roles to represent they.
                              Also in some case that custom roles couldn't be enough: let's say I have to save the volume to a send channel, and the number of send channel can change globally. How could I use a role in that case that should also take some data with him (in this case the send channel number)?

                              Generally speaking I find more cleaner call the name of a properties on an object instead of save the value with a numeric index on a QList and access it defining many custom roles, but maybe I'm missing something so that's why I'm asking here ;)

                              Finally, talking of efficiency, correct me if I'm wrong, but using something like a QList or QMap for all the properties consume more memory then a simple object?

                              Thanks again ;)
                              Cheers Mix

                              1 Reply Last reply
                              0
                              • fcarneyF Offline
                                fcarneyF Offline
                                fcarney
                                wrote on last edited by
                                #15

                                @mix359 said in Choose between model/view or other approach:

                                It's not a matter of efficiency, because many of the data are simple data that can be represented with a derivation of QVariant, so I can probably put all of this data in a QList o QMap.

                                You can use any storage/class/structure you want. It could be a database backend or anything. Also, you are not limited to using only the data() function. You could use that for a standard roles for listing things, but also define more getters/setters for the model object or another object if wanted. Use the index returned from the standard interface in getter/setter calls on that object to do more complex stuff. Just make sure you couch changes in the model that could affect what is shown in the views inside the correct begin/end data changed calls.

                                We use qml for a lot or our work and it is common for there to be stuff we do outside the model if it makes sense. Like you might want to return a custom object to the qml interface we may have more methods defined on the model itself. I don't know if your using qml, but it is nice for doing complex interactions. I am sure you could do the same if your using widgets.

                                The model/view code in Qt is really good at displaying lists and trees. No reason to reinvent that. Then add complex functionality if needed, where needed.

                                C++ is a perfectly valid school of magic.

                                1 Reply Last reply
                                2

                                • Login

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