Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How can you know when all the delegates of a View or Repeater have been created once the model is set?
QtWS25 Last Chance

How can you know when all the delegates of a View or Repeater have been created once the model is set?

Scheduled Pinned Locked Moved Solved QML and Qt Quick
8 Posts 3 Posters 1.6k 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.
  • DiracsbracketD Offline
    DiracsbracketD Offline
    Diracsbracket
    wrote on last edited by Diracsbracket
    #1

    Hi
    I am having synchronization problems within my C++/QML application.

    After I set the model property of a Repeater inside a Column which functions as a drawer of sorts. Then, I reparent some of the items in that Column to a Grid.

    In my first version, the model was a QML XmlListModel, and then the above worked fine.
    Now, I have replaced the XmlListModel by an equivalent C++ model, exposed as a custom QML type, but things now no longer work, because the reparenting is now apparently started before the Repeater items are created.

    In this new approach, I therefore need to wait until all Repeater items have been created. Is there an event I can use for this, other than to count (in the delegate's onCompleted()) the number of instantiated items myself? (I am already using that convoluted approach for another model/view part, but I'm wondering if there is a better way).

    1 Reply Last reply
    0
    • DiackneD Offline
      DiackneD Offline
      Diackne
      wrote on last edited by
      #2

      Hi,

      maybe the problem is in c++, how are you linking c++ to qml you Register the Type in c++?

      DiracsbracketD 1 Reply Last reply
      0
      • DiackneD Diackne

        Hi,

        maybe the problem is in c++, how are you linking c++ to qml you Register the Type in c++?

        DiracsbracketD Offline
        DiracsbracketD Offline
        Diracsbracket
        wrote on last edited by
        #3

        Hi @Diackne
        Thanks for reacting.

        you Register the Type in c++

        Yes, I register the model as a QML-type in C++, having implemented, amongst others, the following methods:

            int rowCount(const QModelIndex & parent = QModelIndex()) const;
            QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
            bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
        
            Q_INVOKABLE QVariantMap get(int row);
        
        1 Reply Last reply
        0
        • DiackneD Offline
          DiackneD Offline
          Diackne
          wrote on last edited by Diackne
          #4

          @Diracsbracket said in How can you know when all the delegates of a View or Repeater have been created once the model is set?:

          Q_INVOKABLE QVariantMap get(int row);

          Q_INVOKABLE is the problem, you maybe in your qml code call this get(N) but not the reactive way!! if c++ ends after the first call of get(N) your result of get(N) return empty
          maybe you need follow this idea

              ctxt->setContextProperty("myModel", &model);
          
          Repeater {
              model: myModel  // this notify c++ --> Qml
              delegate: Text { text:  type + ", " + size }
          }
          

          Model Views Data

          but in qml who you pass the model only get(N) or inside repeater and the repeater have the model?

          DiracsbracketD 1 Reply Last reply
          0
          • DiackneD Diackne

            @Diracsbracket said in How can you know when all the delegates of a View or Repeater have been created once the model is set?:

            Q_INVOKABLE QVariantMap get(int row);

            Q_INVOKABLE is the problem, you maybe in your qml code call this get(N) but not the reactive way!! if c++ ends after the first call of get(N) your result of get(N) return empty
            maybe you need follow this idea

                ctxt->setContextProperty("myModel", &model);
            
            Repeater {
                model: myModel  // this notify c++ --> Qml
                delegate: Text { text:  type + ", " + size }
            }
            

            Model Views Data

            but in qml who you pass the model only get(N) or inside repeater and the repeater have the model?

            DiracsbracketD Offline
            DiracsbracketD Offline
            Diracsbracket
            wrote on last edited by Diracsbracket
            #5

            @Diackne

            At the time I created this post, I did it as follows:

            Flickable{
                        id: sourceFlick
                        ....
                         Column {
                            id: buttonList
            
                            Repeater {
                                model: xmlButtonModel
                                ...
                                delegate: DragTile {}
                            }
                   }
            }
            

            I used a Repeater because I needed all the delegates to be instanciated at all times (as opposed to only when they are visible). But in the meanwhile, I learned that I could do the same with a ListView by setting the cacheBuffer to an appropriate value, and now I do things like this:

            ListView {
                        id: buttonList
                        ...
                        model: xmlButtonModel
                        ....
                        delegate: DragTile {}
            }
            

            The model and ListView are part of an Item, of which several instances are created dynamically, based on the number of XML files found in a directory:

            Item {
                id: layout
            
                XmlListModel {
                    id: xmlButtonModel
                    ...
                    onStatusChanged: {
                        if (status == XmlListModel.Ready) {
                            ...
                            Js.createGridPages()
                             ...
                        }
                    }
                }
            
                Rectangle {
                    id: drawer
                    ...
                    ListView {
                        id: buttonList
                        ...
                        model: xmlButtonModel
                        ....
                        delegate: DragTile {}
                   }
                }
            
                Item {
                    id: layoutItem
                    ...
                    SwipeView {
                        id: swipeView
                        ...
                        contentItem: ListView {
                            ...
                            model: ListModel {
                                id: viewModel
                            }
            
                            delegate: ButtonGrid {}
                        }
                    }
                }
            }
            

            So for a given layout Item, once the XML model is loaded, the layout is populated by Js.createGridPages(), which creates the pages in swipeView, each page containing a Grid of cells to which items of buttonList are reparented based on a user-preferences file...

            I must note that this reparenting process even fails occasionally when simply rebuilding + autolaunching the app via Qt Creator (target device is Android), even when I don't use my faster C++ XML model. The error is always the same: some of the DragTile delegates of my buttonList is still undefined.

            DiracsbracketD 1 Reply Last reply
            0
            • DiracsbracketD Diracsbracket

              @Diackne

              At the time I created this post, I did it as follows:

              Flickable{
                          id: sourceFlick
                          ....
                           Column {
                              id: buttonList
              
                              Repeater {
                                  model: xmlButtonModel
                                  ...
                                  delegate: DragTile {}
                              }
                     }
              }
              

              I used a Repeater because I needed all the delegates to be instanciated at all times (as opposed to only when they are visible). But in the meanwhile, I learned that I could do the same with a ListView by setting the cacheBuffer to an appropriate value, and now I do things like this:

              ListView {
                          id: buttonList
                          ...
                          model: xmlButtonModel
                          ....
                          delegate: DragTile {}
              }
              

              The model and ListView are part of an Item, of which several instances are created dynamically, based on the number of XML files found in a directory:

              Item {
                  id: layout
              
                  XmlListModel {
                      id: xmlButtonModel
                      ...
                      onStatusChanged: {
                          if (status == XmlListModel.Ready) {
                              ...
                              Js.createGridPages()
                               ...
                          }
                      }
                  }
              
                  Rectangle {
                      id: drawer
                      ...
                      ListView {
                          id: buttonList
                          ...
                          model: xmlButtonModel
                          ....
                          delegate: DragTile {}
                     }
                  }
              
                  Item {
                      id: layoutItem
                      ...
                      SwipeView {
                          id: swipeView
                          ...
                          contentItem: ListView {
                              ...
                              model: ListModel {
                                  id: viewModel
                              }
              
                              delegate: ButtonGrid {}
                          }
                      }
                  }
              }
              

              So for a given layout Item, once the XML model is loaded, the layout is populated by Js.createGridPages(), which creates the pages in swipeView, each page containing a Grid of cells to which items of buttonList are reparented based on a user-preferences file...

              I must note that this reparenting process even fails occasionally when simply rebuilding + autolaunching the app via Qt Creator (target device is Android), even when I don't use my faster C++ XML model. The error is always the same: some of the DragTile delegates of my buttonList is still undefined.

              DiracsbracketD Offline
              DiracsbracketD Offline
              Diracsbracket
              wrote on last edited by Diracsbracket
              #6

              I finally found what was happening.

              I incorrectly assumed (from a few debug output samples) that when using a Repeater to instantiate the cells of my Grid, the cells would always be listed first in the children list of Grid and that the Repeater item would always be listed as the last child (i.e. cells would be "inserted" in the list before the Repeater as they got instantiated) .

              Based on that assumption, I directly used the cell index (let's say i) to get the corresponding item as children[i].

              The above assumption was apparently wrong: once in a while, the Repeater item would not always be the last child, and a cell could come after it... Therefore, my above approach of using the grid cell index to retrieve the item sometimes resulted in getting the Repeater item instead...

              To avoid this, I have eliminated the Repeater, and simply instantiate the cells dynamically in the Component.onCompleted() handler. This allows me to directly use the grid cell index to retrieve the item from the children list, not having to worry about other types of children...

              1 Reply Last reply
              0
              • GrecKoG Offline
                GrecKoG Offline
                GrecKo
                Qt Champions 2018
                wrote on last edited by
                #7

                Why not use the Repeater's itemAt(index) method?

                DiracsbracketD 1 Reply Last reply
                1
                • GrecKoG GrecKo

                  Why not use the Repeater's itemAt(index) method?

                  DiracsbracketD Offline
                  DiracsbracketD Offline
                  Diracsbracket
                  wrote on last edited by
                  #8

                  @GrecKo
                  That's a good one, I didn't think there would be such a method! Thanks for pointing it out!

                  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