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

Garbage collector issue

Scheduled Pinned Locked Moved Solved QML and Qt Quick
10 Posts 2 Posters 559 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.
  • jeanmilostJ Offline
    jeanmilostJ Offline
    jeanmilost
    wrote on last edited by jeanmilost
    #1

    Hello,

    I have an issue similar to this one:
    https://forum.qt.io/topic/105749/remove-dynamically-created-item-from-a-stacklayout

    I'm using a StackLayout to show a set of pages dynamically. The pages can be added, deleted or selected on runtime by the user, so there is no way to know in advance when these actions will happen. For that reason the most appropriate component to own the pages is a StackLayout (due to the possible random access to any item), and AFAIK I cannot use another one.

    Also, each page provides an unique identifier to be recognized in the list.

    My issue happens when I need to select another page after one was deleted, because this enters in conflict with the Garbage Collector.

    Here is the problematic code:

            function onShowSelectedPage(uid)
            {
                // if no unique identifier defined, don't show page
                if (!uid || !uid.length)
                {
                    slPageStack.currentIndex = -1;
                    return;
                }
    
                let idx = 0;
    
            console.log("--------------> 1 - " + slPageStack.children.length);
            console.log("--------------> 2 - " + slPageStack.count);
    
                // FIXME for Jean: Possible unsafe code, check better how the garbage collector is working
                // iterate through page view stack until find the matching page unique identifier
                for (var i = 0; i < slPageStack.children.length; ++i)
                {
                    // is child a page?
                    if (slPageStack.children[i].m_Type === "TSP_PageView")
                    {
                        // is page deleted but still not collected by the garbage collector?
                        if (slPageStack.children[i].m_Deleted)
                        {
                            console.log("--------------> 3 - STILL USED!!!");
                            continue;
                        }
    
                        // found page to show?
                        if (slPageStack.children[i].pageProxy.uid === uid)
                        {
                            // use manually counted idx instead of i, because it may be shifted
                            // if a deleting page was still not removed by the garbage collector
                            slPageStack.currentIndex = idx;
                            break;
                        }
                    }
    
                    ++idx;
                }
            console.log("--------------> 4 - " + slPageStack.children.length);
            console.log("--------------> 5 - " + slPageStack.count);
            }
        }
    

    This code is problematic for several reasons:

    1. I'm aware that this code is over-complicated but I don't know how to simplify it. For example I needed to add a m_Deleted flag, which I set to true on delete, to certify that the page I try to access is not currently deleted, but still not cleaned by the Garbage Collector, and should no longer be considered.
    2. Even with the current loop, I'm not sure that the Garbage Collector will not perform the cleanup while my loop is executed, which may cause a very hard to detect bug later.

    In the above post I mentioned, the first answer (change to StackView and use push/pop) cannot be applied in my case, due to the random access to the items I said above.

    The second solution seems promising, but I have no idea about how to implement it in my case.

    My questions are:

    • How may I use a Repeater which take care of completely dynamic objects, managed randomly in a random view during the life cycle of my application?
    • Or how may I at least guarantee that the Garbage Collector doesn't interfere with my loop

    Also a simple example of using a StackLayout with a Repeater managing dynamic components would be welcome.

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

      main.qml:

      import QtQuick 2.15
      import QtQuick.Controls 2.15
      import QtQuick.Window 2.15
      import QtQuick.Layouts 1.15
      
      Window
      {
          property int m_PageCount: 0
      
          // common properties
          id: wnMain
          width: 640
          height: 480
          visible: true
          title: qsTr("Dynamic page creation")
      
          Rectangle
          {
              // common properties
              id: rcButtons
              anchors.left: parent.left
              anchors.top: parent.top
              anchors.right: parent.right
              height: 45
              color: "gray"
      
              Button
              {
                  // common properties
                  id: btAdd
                  anchors.left: parent.left
                  anchors.leftMargin: 5
                  anchors.top: parent.top
                  anchors.topMargin: 5
                  anchors.bottom: parent.bottom
                  anchors.bottomMargin: 5
                  text: "Add page"
      
                  onClicked:
                  {
                      lmViewModel.append({color: "lightblue", "pageNb": ++m_PageCount});
                      slView.currentIndex = slView.count - 1;
                  }
              }
      
              Button
              {
                  // common properties
                  id: btDel
                  anchors.left: btAdd.right
                  anchors.leftMargin: 5
                  anchors.top: parent.top
                  anchors.topMargin: 5
                  anchors.bottom: parent.bottom
                  anchors.bottomMargin: 5
                  text: "Delete page"
      
                  onClicked:
                  {
                      if (!slView.count)
                          return;
      
                      lmViewModel.remove(slView.currentIndex);
                  }
              }
      
              Button
              {
                  // common properties
                  id: btPrev
                  anchors.left: btDel.right
                  anchors.leftMargin: 5
                  anchors.top: parent.top
                  anchors.topMargin: 5
                  anchors.bottom: parent.bottom
                  anchors.bottomMargin: 5
                  text: "< Prev"
      
                  onClicked: slView.prevPage()
              }
      
              Button
              {
                  // common properties
                  id: btNext
                  anchors.left: btPrev.right
                  anchors.leftMargin: 5
                  anchors.top: parent.top
                  anchors.topMargin: 5
                  anchors.bottom: parent.bottom
                  anchors.bottomMargin: 5
                  text: "Next >"
      
                  onClicked: slView.nextPage()
              }
          }
      
          ListModel
          {
              // common properties
              id: lmViewModel
          }
      
          StackLayout
          {
              // common properties
              id: slView
              anchors.left: parent.left
              anchors.top: rcButtons.bottom
              anchors.right: parent.right
              anchors.bottom: parent.bottom
      
              Repeater
              {
                  property int pageNb
      
                  // common properties
                  id: rpView
                  model: lmViewModel
      
      
                  //delegate: PageItem
                  PageItem
                  {
                      // bind color property contained in Page item to this loader
                      /*
                      Binding
                      {
                          // common properties
                          target: rpView
                          property: "color"
                          value: color
                      }
                      */
      
                      // you could have kept name of property as color inside PageItem and then
                      // accessed color here as: color: model.color
                      // I prefer to keep names distinct
                      m_color: color
                      m_Index: index  // index provided by Repeater
                      m_PageNb: pageNb
      
                      /// Called when the component was opened
                      Component.onCompleted:
                      {
                          // index provided by Repeater
                          //index = Qt.binding(function() { return slView.currentIndex; });
      
                          // link remove signal between list model and page item
                          remove.connect(lmViewModel.remove);
                      }
                  }
      
      
                  /*
                  Loader
                  {
                      // common properties
                      source: "PageItem.qml"
      
                      // bind color property contained in Page item to this loader
                      Binding
                      {
                          // common properties
                          target: item
                          property: "color"
                          value: color
                      }
      
                      // bind pageNb property contained in Page item to this loader
                      Binding
                      {
                          // common properties
                          target: item
                          property: "m_PageNb"
                          value: pageNb
                      }
      
                      // bind index property contained in Page child item to this loader
                      Binding
                      {
                          // common properties
                          target: item
                          property: "m_Index"
                          value: index
                      }
      
                      /// Called when the component was opened
                      Component.onCompleted:
                      {
                          // link remove signal between list model and page item
                          item.remove.connect(lmViewModel.remove);
      
                          console.log("Page Nb. - " + pageNb + " - " + item.m_PageNb);
                      }
                  }
                  */
      
                  onPageNbChanged:
                  {
                      console.log("Page Nb. Changed - " + pageNb + " - " + item.m_PageNb);
                  }
              }
      
              function prevPage()
              {
                  if (!count)
                  {
                      currentIndex = -1;
                      return;
                  }
      
                  let index = currentIndex;
      
                  --index;
      
                  if (index < 0)
                      index = count - 1;
      
                  currentIndex = index;
              }
      
              function nextPage()
              {
                  if (!count)
                  {
                      currentIndex = -1;
                      return;
                  }
      
                  let index = currentIndex;
      
                  ++index;
      
                  if (index >= count)
                      index = 0;
      
                  currentIndex = index;
              }
          }
      
          Component.onCompleted:
          {
              lmViewModel.append({"color": "pink", "pageNb": ++m_PageCount});
          }
      }
      

      PageItem.qml:

      import QtQuick 2.15
      import QtQuick.Controls 2.15
      import QtQuick.Templates 2.15 as T
      
      T.Control
      {
          // aliases
          property alias m_color: rcBackground.color
      
          // advanced properties
          property int m_PageNb
          property int m_Index
      
          // common properties
          id: ctPage
      
          signal remove(int index)
      
          Rectangle
          {
              // common properties
              id: rcBackground
              anchors.fill: parent
      
              Text
              {
                  // common properties
                  id: txText
                  anchors.centerIn: parent
                  text: "Page %1 - Index %2".arg(m_PageNb).arg(m_Index)
              }
      
              MouseArea
              {
                  // common properties
                  anchors.fill: parent
      
                  onClicked:
                  {
                      remove(m_Index)
                  }
              }
          }
      }
      

      Just to show how it looks using only PageItem as child of Repeater.
      I renamed color to m_color. I have a comment about how that could be different.

      C++ is a perfectly valid school of magic.

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

        Do what @GrecKo said in that other post and use a model:

        import QtQuick 2.15
        import QtQuick.Controls 2.15
        import QtQuick.Window 2.15
        import QtQuick.Layouts 1.15
        
        Window {
            width: 640
            height: 480
            visible: true
            title: qsTr("Stack Layout")
        
            ListModel {
                id: listmodel
        
                Component.onCompleted: {
                    append({ctype: type1, bcolor:"pink"})
                    append({ctype: type1, bcolor:"lightblue"})
                    append({ctype: type2, bcolor:"green"})
                }
            }
        
            Column {
                Button {
                    text: "inc layout"
                    onClicked: stacklayout.rotateLayout()
                }
        
                StackLayout {
                    id: stacklayout
        
                    width: 200
                    height: 200
        
                    function rotateLayout(){
                        let ind = currentIndex
                        ind++
                        if(ind >= count){
                            ind = 0
                        }
                        currentIndex = ind
                    }
        
                    Repeater {
                        model: listmodel
        
                        Loader {
                            sourceComponent: ctype
        
                            Binding {
                                target: item
                                property: "color"
                                value: bcolor
                            }
                            Binding {
                                target: item
                                property: "index"
                                value: index
                            }
        
                            Component.onCompleted: {
                                item.remove.connect(listmodel.remove)
                            }
                        }
                    }
                }
            }
        
            Component {
                id: type1
        
                Rectangle {
                    property int index
                    signal remove(int ind)
        
                    Text {
                        id: type1_text
        
                        anchors.centerIn: parent
        
                        text: "type1 %1".arg(index)
                    }
        
                    MouseArea {
                        anchors.fill: parent
        
                        onClicked: {
                            remove(index)
                        }
                    }
                }
            }
            Component {
                id: type2
        
                Item {
                    property alias color: type2_text.color
                    property int index
                    signal remove(int ind)
        
                    Rectangle {
                        anchors.fill: parent
        
                        color: "lightgrey"
                        border.width: 1
                        border.color: parent.color
                    }
        
                    Text {
                        id: type2_text
        
                        anchors.centerIn: parent
        
                        text: "type2 %1".arg(index)
                    }
        
                    MouseArea {
                        anchors.fill: parent
        
                        onClicked: {
                            remove(index)
                        }
                    }
                }
            }
        }
        

        C++ is a perfectly valid school of magic.

        1 Reply Last reply
        1
        • jeanmilostJ Offline
          jeanmilostJ Offline
          jeanmilost
          wrote on last edited by jeanmilost
          #3

          @fcarney Thank you for your answer.

          Based on the above fcarney code, I tried to write my own code to load dynamically a child component and to add it on a stack view. But it doesn't work and I cannot figure out how to achieve that correctly.

          Below is the code I tried to write, can someone point me what I'm doing wrong, and explain me with further details how to use a Repeater/Loader to load and manage dynamic components in a view?

          import QtQuick 2.15
          import QtQuick.Controls 2.15
          import QtQuick.Window 2.15
          import QtQuick.Layouts 1.15
          
          Window
          {
              property int m_GenID: 0
          
              width: 640
              height: 480
              visible: true
              title: qsTr("Stack Layout")
          
              ListModel
              {
                  id: listmodel
          
                  Component.onCompleted:
                  {
                  /*
                      append({ctype: type1, bcolor:"pink"})
                      append({ctype: type1, bcolor:"lightblue"})
                      append({ctype: type2, bcolor:"green"})
                      */
                  }
              }
          
              Column
              {
                  Button
                  {
                      text: "add layout"
          
                      onClicked:
                      {
                      }
                  }
          
                  Button
                  {
                      text: "inc layout"
          
                      onClicked: stacklayout.rotateLayout()
                  }
          
                  StackLayout
                  {
                      id: stacklayout
          
                      width: 200
                      height: 200
          
                      function rotateLayout()
                      {
                          let ind = currentIndex
          
                          ind++
          
                          if (ind >= count)
                              ind = 0
          
                          currentIndex = ind
                      }
          
                      Repeater
                      {
                          model: listmodel
          
                          Loader
                          {
                              sourceComponent: ctype
          
                              // bind color property contained in ChildComponent child item to this repeater
                              Binding
                              {
                                  target: item
                                  property: "color"
                                  value: bcolor
                              }
          
                              // bind index property contained in ChildComponent child item to this repeater
                              Binding
                              {
                                  target: item
                                  property: "index"
                                  value: index
                              }
          
                              /// Called when the component was opened
                              Component.onCompleted:
                              {
                                  // link remove signal between list model and the ChildComponent child item
                                  item.remove.connect(listmodel.remove);
                              }
                          }
                      }
                  }
              }
          
              /*REM
              Component
              {
                  id: type1
          
                  ChildComponent
                  {}
              }
          
              Component
              {
                  id: type2
          
                  ChildComponent
                  {}
              }
              */
              Component.onCompleted:
              {
                  let component = Qt.createComponent('ChildComponent.qml');
          
                  // succeeded?
                  if (component.status !== Component.Ready)
                  {
                      console.error("Add child - an error occurred while the item was created - " + component.errorString());
                      return;
                  }
          
                  // build page identifier
                  const pageId = "ccChild_" + m_GenID;
          
                  // create and show new item object
                  let item = component.createObject(listmodel.ctype, {"id":         pageId,
                                                                "objectName": pageId,
                                                                //REM "ctype":      pageId,
                                                                "color":      "pink"});
          
                  // succeeded?
                  if (!item)
                  {
                      console.error("Add child - an error occurred while the item was added to view");
                      return;
                  }
          
                  listmodel.append(item);
          
                  ++m_GenID
              }
          }
          

          Here is the ChildComponent.qml file:

          import QtQuick 2.15
          import QtQuick.Controls 2.15
          import QtQuick.Templates 2.15 as T
          
          T.Control
          {
              property alias color: rcRect.color
          
              property int index
          
              id: ctChild
          
              signal remove(int ind)
          
              Rectangle
              {
                  id: rcRect
                  anchors.fill: parent
          
                  Text
                  {
                      id: txText
          
                      anchors.centerIn: parent
          
                      text: "type1 %1".arg(index)
                  }
          
                  MouseArea
                  {
                      anchors.fill: parent
          
                      onClicked:
                      {
                          remove(index)
                      }
                  }
              }
          }
          
          1 Reply Last reply
          0
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on last edited by
            #4

            @jeanmilost said in Garbage collector issue:

            let component = Qt.createComponent('ChildComponent.qml');

                // succeeded?
                if (component.status !== Component.Ready)
                {
                    console.error("Add child - an error occurred while the item was created - " + component.errorString());
                    return;
                }
            
                // build page identifier
                const pageId = "ccChild_" + m_GenID;
            
                // create and show new item object
                let item = component.createObject(listmodel.ctype, {"id":         pageId,
                                                              "objectName": pageId,
                                                              //REM "ctype":      pageId,
                                                              "color":      "pink"});
            
                // succeeded?
                if (!item)
                {
                    console.error("Add child - an error occurred while the item was added to view");
                    return;
                }
            

            I don't understand why you are doing any of this. The Repeater makes the object via the Loader. Just fill out a JS structure to define what component type gets loaded. The whole point of using a Loader with a Repeater is so you don't have to use the dynamic gen functions.

            Also, there is a "better" way to use Loader that maybe I should have pointed out. Use the "source" property and give it the qml file path. Then use Component.onCompleted to select what gets loaded based upon a value fed from the model:

                                          Loader {
                                                // this makes it so you don't have to use Binding
                                                property var passedIn: ({
                                                    name: name,
                                                    param: param
                                                })
            
                                                Component.onCompleted: {
                                                    switch(type){
                                                    case "type1":
                                                        setSource("SomeQMLFile.qml",
                                                                  passedIn)
                                                        break;
                                                    case "type2:
                                                        setSource("AnotherQMLFile.qml",
                                                                  passedIn)
                                                        break;
                                                    }
                                                }
                                            }
            

            I just used this latter version of a Loader with a ListView. It works very nicely and cleans up the code.

            C++ is a perfectly valid school of magic.

            1 Reply Last reply
            1
            • jeanmilostJ Offline
              jeanmilostJ Offline
              jeanmilost
              wrote on last edited by jeanmilost
              #5

              @fcarney Once again, thank you for your answer, it was really useful for me. Indeed my code isn't very optimal, and it was the reason of my above questions. I felt that the Repeater / Loader association was a better concept from what I'm tried to achieve, but I could not understand how to use them in my particular situation. And as I am self-taught, I needed to start from my imperfect concept to try to understand how to do better :-)

              So I played around your code, and I think I understood how the things work. I have a new code (below) which is close to what I wanted to achieve on the beginning. I have an unique remaining issue: In the below code, the binding around the pageNb property is not working. On runtime, this property seems correctly linked between the item and the loader (The value changes in the item if I hadrcode it in the loader), but when I try to execute the following code:
              lmViewModel.append({color: "lightblue", pageNb: 5678});
              The value doesn't change in the item. Also the onPageNbChanged signal is never called. Can you please explain me what I'm doing wrong?

              import QtQuick 2.15
              import QtQuick.Controls 2.15
              import QtQuick.Window 2.15
              import QtQuick.Layouts 1.15
              
              Window
              {
                  property int m_GenID: 0
              
                  // common properties
                  id: wnMain
                  width: 640
                  height: 480
                  visible: true
                  title: qsTr("Dynamic page creation")
              
                  Rectangle
                  {
                      // common properties
                      id: rcButtons
                      anchors.left: parent.left
                      anchors.top: parent.top
                      anchors.right: parent.right
                      height: 45
                      color: "gray"
              
                      Button
                      {
                          // common properties
                          id: btAdd
                          anchors.left: parent.left
                          anchors.leftMargin: 5
                          anchors.top: parent.top
                          anchors.topMargin: 5
                          anchors.bottom: parent.bottom
                          anchors.bottomMargin: 5
                          text: "Add page"
              
                          onClicked:
                          {
                              lmViewModel.append({color: "lightblue", pageNb: 5678});
                              slView.currentIndex = slView.count - 1;
                          }
                      }
              
                      Button
                      {
                          // common properties
                          id: btDel
                          anchors.left: btAdd.right
                          anchors.leftMargin: 5
                          anchors.top: parent.top
                          anchors.topMargin: 5
                          anchors.bottom: parent.bottom
                          anchors.bottomMargin: 5
                          text: "Delete page"
              
                          onClicked:
                          {
                              if (!slView.count)
                                  return;
              
                              lmViewModel.remove(slView.currentIndex);
                          }
                      }
              
                      Button
                      {
                          // common properties
                          id: btPrev
                          anchors.left: btDel.right
                          anchors.leftMargin: 5
                          anchors.top: parent.top
                          anchors.topMargin: 5
                          anchors.bottom: parent.bottom
                          anchors.bottomMargin: 5
                          text: "< Prev"
              
                          onClicked: slView.prevPage()
                      }
              
                      Button
                      {
                          // common properties
                          id: btNext
                          anchors.left: btPrev.right
                          anchors.leftMargin: 5
                          anchors.top: parent.top
                          anchors.topMargin: 5
                          anchors.bottom: parent.bottom
                          anchors.bottomMargin: 5
                          text: "Next >"
              
                          onClicked: slView.nextPage()
                      }
                  }
              
                  ListModel
                  {
                      // common properties
                      id: lmViewModel
                  }
              
                  StackLayout
                  {
                      // common properties
                      id: slView
                      anchors.left: parent.left
                      anchors.top: rcButtons.bottom
                      anchors.right: parent.right
                      anchors.bottom: parent.bottom
              
                      Repeater
                      {
                          // common properties
                          id: rpView
                          model: lmViewModel
              
                          Loader
                          {
                              property int pageNb
              
                              // common properties
                              source: "PageItem.qml"
              
                              // bind color property contained in Page item to this loader
                              Binding
                              {
                                  // common properties
                                  target: item
                                  property: "color"
                                  value: color
                              }
              
                              // bind pageNb property contained in Page item to this loader
                              Binding
                              {
                                  // common properties
                                  target: item
                                  property: "pageNb"
                                  value: pageNb
                              }
              
                              // bind index property contained in Page child item to this loader
                              Binding
                              {
                                  // common properties
                                  target: item
                                  property: "index"
                                  value: index
                              }
              
                              onPageNbChanged:
                              {
                                  console.log("Page Nb. Changed - " + pageNb + " - " + item.pageNb);
                              }
              
                              /// Called when the component was opened
                              Component.onCompleted:
                              {
                                  // link remove signal between list model and page item
                                  item.remove.connect(lmViewModel.remove);
              
                                  console.log("Page Nb. - " + pageNb + " - " + item.pageNb);
                              }
                          }
                      }
              
                      function prevPage()
                      {
                          if (!count)
                          {
                              currentIndex = -1;
                              return;
                          }
              
                          let index = currentIndex;
              
                          --index;
              
                          if (index < 0)
                              index = count - 1;
              
                          currentIndex = index;
                      }
              
                      function nextPage()
                      {
                          if (!count)
                          {
                              currentIndex = -1;
                              return;
                          }
              
                          let index = currentIndex;
              
                          ++index;
              
                          if (index >= count)
                              index = 0;
              
                          currentIndex = index;
                      }
                  }
              
                  Component.onCompleted:
                  {
                      lmViewModel.append({color: "pink"});
                  }
              }
              
              import QtQuick 2.15
              import QtQuick.Controls 2.15
              import QtQuick.Templates 2.15 as T
              
              T.Control
              {
                  property alias color: rcBackground.color
                  property int   pageNb
                  property int   index
              
                  // common properties
                  id: ctPage
              
                  signal remove(int index)
              
                  Rectangle
                  {
                      // common properties
                      id: rcBackground
                      anchors.fill: parent
              
                      Text
                      {
                          // common properties
                          id: txText
                          anchors.centerIn: parent
                          text: "Page %1 - Index %2".arg(pageNb).arg(index)
                      }
              
                      MouseArea
                      {
                          // common properties
                          anchors.fill: parent
              
                          onClicked:
                          {
                              remove(index)
                          }
                      }
                  }
              }
              
              1 Reply Last reply
              0
              • fcarneyF Offline
                fcarneyF Offline
                fcarney
                wrote on last edited by fcarney
                #6

                @jeanmilost said in Garbage collector issue:

                Component.onCompleted:
                {
                lmViewModel.append({color: "pink"});
                }

                This must have pageNb defined if you add later entries to your model.
                There is a way to turn that requirement off in the ListModel, but I don't recommend that.
                Aren't you getting an error when you click the add button? It should be showing an error about having pageNb when you didn't have that in the first entry added during onComplete.

                Make sure everything that you add to the model has the proper entries.
                One way to do that is write a function that you call for this:

                ListModel {
                    id: lmodel
                
                    function addNewThing(color, ind){
                        lmodel.append({color:color, ind:ind})
                    }
                }
                
                This ensures everything has parity.
                
                Loader
                            {
                                property int pageNb
                

                Don't define pageNb here. It should be coming from your model. This probably occluding what gets sent from the model. I am not 100% sure though. Maybe test that a bit. I know there is syntax to ensure you get something from a model that involves properties using the term "required". But I don't see you using that. Again, play with this to see if it occludes it or not.

                Edit: If you get stuck just say so. I will look later this weekend when I get a chance.

                C++ is a perfectly valid school of magic.

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

                  Are you using multiple versions of qml delegates? If not you could get rid of the Loader as well:

                  Repeater {
                      PageItem {
                          ...
                      }
                  }
                  

                  C++ is a perfectly valid school of magic.

                  1 Reply Last reply
                  1
                  • jeanmilostJ Offline
                    jeanmilostJ Offline
                    jeanmilost
                    wrote on last edited by
                    #8

                    @fcarney This solution (below) seems to work for me. I just moved the pageNb property to the Repeater level and I encapsulated the property name in quotes, and voila!

                    On the other hand, I also tried to replace the Loader by PageItem directly, as I have indeed only one type of child item, but without success. You can take a look to the commented code (but it is experimental).

                    Anyway, thank you very much for your help.

                    import QtQuick 2.15
                    import QtQuick.Controls 2.15
                    import QtQuick.Window 2.15
                    import QtQuick.Layouts 1.15
                    
                    Window
                    {
                        property int m_PageCount: 0
                    
                        // common properties
                        id: wnMain
                        width: 640
                        height: 480
                        visible: true
                        title: qsTr("Dynamic page creation")
                    
                        Rectangle
                        {
                            // common properties
                            id: rcButtons
                            anchors.left: parent.left
                            anchors.top: parent.top
                            anchors.right: parent.right
                            height: 45
                            color: "gray"
                    
                            Button
                            {
                                // common properties
                                id: btAdd
                                anchors.left: parent.left
                                anchors.leftMargin: 5
                                anchors.top: parent.top
                                anchors.topMargin: 5
                                anchors.bottom: parent.bottom
                                anchors.bottomMargin: 5
                                text: "Add page"
                    
                                onClicked:
                                {
                                    lmViewModel.append({color: "lightblue", "pageNb": ++m_PageCount});
                                    slView.currentIndex = slView.count - 1;
                                }
                            }
                    
                            Button
                            {
                                // common properties
                                id: btDel
                                anchors.left: btAdd.right
                                anchors.leftMargin: 5
                                anchors.top: parent.top
                                anchors.topMargin: 5
                                anchors.bottom: parent.bottom
                                anchors.bottomMargin: 5
                                text: "Delete page"
                    
                                onClicked:
                                {
                                    if (!slView.count)
                                        return;
                    
                                    lmViewModel.remove(slView.currentIndex);
                                }
                            }
                    
                            Button
                            {
                                // common properties
                                id: btPrev
                                anchors.left: btDel.right
                                anchors.leftMargin: 5
                                anchors.top: parent.top
                                anchors.topMargin: 5
                                anchors.bottom: parent.bottom
                                anchors.bottomMargin: 5
                                text: "< Prev"
                    
                                onClicked: slView.prevPage()
                            }
                    
                            Button
                            {
                                // common properties
                                id: btNext
                                anchors.left: btPrev.right
                                anchors.leftMargin: 5
                                anchors.top: parent.top
                                anchors.topMargin: 5
                                anchors.bottom: parent.bottom
                                anchors.bottomMargin: 5
                                text: "Next >"
                    
                                onClicked: slView.nextPage()
                            }
                        }
                    
                        ListModel
                        {
                            // common properties
                            id: lmViewModel
                        }
                    
                        StackLayout
                        {
                            // common properties
                            id: slView
                            anchors.left: parent.left
                            anchors.top: rcButtons.bottom
                            anchors.right: parent.right
                            anchors.bottom: parent.bottom
                    
                            Repeater
                            {
                                property int pageNb
                    
                                // common properties
                                id: rpView
                                model: lmViewModel
                    
                                /*REM
                                //delegate: PageItem
                                PageItem
                                {
                                    // bind color property contained in Page item to this loader
                                    Binding
                                    {
                                        // common properties
                                        target: rpView
                                        property: "color"
                                        value: color
                                    }
                    
                                    /// Called when the component was opened
                                    Component.onCompleted:
                                    {
                                        index = Qt.binding(function() { return slView.currentIndex; });
                    
                                        // link remove signal between list model and page item
                                        remove.connect(lmViewModel.remove);
                                    }
                                }
                                */
                    
                                Loader
                                {
                                    // common properties
                                    source: "PageItem.qml"
                    
                                    // bind color property contained in Page item to this loader
                                    Binding
                                    {
                                        // common properties
                                        target: item
                                        property: "color"
                                        value: color
                                    }
                    
                                    // bind pageNb property contained in Page item to this loader
                                    Binding
                                    {
                                        // common properties
                                        target: item
                                        property: "m_PageNb"
                                        value: pageNb
                                    }
                    
                                    // bind index property contained in Page child item to this loader
                                    Binding
                                    {
                                        // common properties
                                        target: item
                                        property: "m_Index"
                                        value: index
                                    }
                    
                                    /// Called when the component was opened
                                    Component.onCompleted:
                                    {
                                        // link remove signal between list model and page item
                                        item.remove.connect(lmViewModel.remove);
                    
                                        console.log("Page Nb. - " + pageNb + " - " + item.m_PageNb);
                                    }
                                }
                    
                                onPageNbChanged:
                                {
                                    console.log("Page Nb. Changed - " + pageNb + " - " + item.m_PageNb);
                                }
                            }
                    
                            function prevPage()
                            {
                                if (!count)
                                {
                                    currentIndex = -1;
                                    return;
                                }
                    
                                let index = currentIndex;
                    
                                --index;
                    
                                if (index < 0)
                                    index = count - 1;
                    
                                currentIndex = index;
                            }
                    
                            function nextPage()
                            {
                                if (!count)
                                {
                                    currentIndex = -1;
                                    return;
                                }
                    
                                let index = currentIndex;
                    
                                ++index;
                    
                                if (index >= count)
                                    index = 0;
                    
                                currentIndex = index;
                            }
                        }
                    
                        Component.onCompleted:
                        {
                            lmViewModel.append({"color": "pink", "pageNb": ++m_PageCount});
                        }
                    }
                    
                    import QtQuick 2.15
                    import QtQuick.Controls 2.15
                    import QtQuick.Templates 2.15 as T
                    
                    T.Control
                    {
                        // aliases
                        property alias color: rcBackground.color
                    
                        // advanced properties
                        property int m_PageNb
                        property int m_Index
                    
                        // common properties
                        id: ctPage
                    
                        signal remove(int index)
                    
                        Rectangle
                        {
                            // common properties
                            id: rcBackground
                            anchors.fill: parent
                    
                            Text
                            {
                                // common properties
                                id: txText
                                anchors.centerIn: parent
                                text: "Page %1 - Index %2".arg(m_PageNb).arg(m_Index)
                            }
                    
                            MouseArea
                            {
                                // common properties
                                anchors.fill: parent
                    
                                onClicked:
                                {
                                    remove(m_Index)
                                }
                            }
                        }
                    }
                    
                    1 Reply Last reply
                    1
                    • fcarneyF Offline
                      fcarneyF Offline
                      fcarney
                      wrote on last edited by
                      #9

                      main.qml:

                      import QtQuick 2.15
                      import QtQuick.Controls 2.15
                      import QtQuick.Window 2.15
                      import QtQuick.Layouts 1.15
                      
                      Window
                      {
                          property int m_PageCount: 0
                      
                          // common properties
                          id: wnMain
                          width: 640
                          height: 480
                          visible: true
                          title: qsTr("Dynamic page creation")
                      
                          Rectangle
                          {
                              // common properties
                              id: rcButtons
                              anchors.left: parent.left
                              anchors.top: parent.top
                              anchors.right: parent.right
                              height: 45
                              color: "gray"
                      
                              Button
                              {
                                  // common properties
                                  id: btAdd
                                  anchors.left: parent.left
                                  anchors.leftMargin: 5
                                  anchors.top: parent.top
                                  anchors.topMargin: 5
                                  anchors.bottom: parent.bottom
                                  anchors.bottomMargin: 5
                                  text: "Add page"
                      
                                  onClicked:
                                  {
                                      lmViewModel.append({color: "lightblue", "pageNb": ++m_PageCount});
                                      slView.currentIndex = slView.count - 1;
                                  }
                              }
                      
                              Button
                              {
                                  // common properties
                                  id: btDel
                                  anchors.left: btAdd.right
                                  anchors.leftMargin: 5
                                  anchors.top: parent.top
                                  anchors.topMargin: 5
                                  anchors.bottom: parent.bottom
                                  anchors.bottomMargin: 5
                                  text: "Delete page"
                      
                                  onClicked:
                                  {
                                      if (!slView.count)
                                          return;
                      
                                      lmViewModel.remove(slView.currentIndex);
                                  }
                              }
                      
                              Button
                              {
                                  // common properties
                                  id: btPrev
                                  anchors.left: btDel.right
                                  anchors.leftMargin: 5
                                  anchors.top: parent.top
                                  anchors.topMargin: 5
                                  anchors.bottom: parent.bottom
                                  anchors.bottomMargin: 5
                                  text: "< Prev"
                      
                                  onClicked: slView.prevPage()
                              }
                      
                              Button
                              {
                                  // common properties
                                  id: btNext
                                  anchors.left: btPrev.right
                                  anchors.leftMargin: 5
                                  anchors.top: parent.top
                                  anchors.topMargin: 5
                                  anchors.bottom: parent.bottom
                                  anchors.bottomMargin: 5
                                  text: "Next >"
                      
                                  onClicked: slView.nextPage()
                              }
                          }
                      
                          ListModel
                          {
                              // common properties
                              id: lmViewModel
                          }
                      
                          StackLayout
                          {
                              // common properties
                              id: slView
                              anchors.left: parent.left
                              anchors.top: rcButtons.bottom
                              anchors.right: parent.right
                              anchors.bottom: parent.bottom
                      
                              Repeater
                              {
                                  property int pageNb
                      
                                  // common properties
                                  id: rpView
                                  model: lmViewModel
                      
                      
                                  //delegate: PageItem
                                  PageItem
                                  {
                                      // bind color property contained in Page item to this loader
                                      /*
                                      Binding
                                      {
                                          // common properties
                                          target: rpView
                                          property: "color"
                                          value: color
                                      }
                                      */
                      
                                      // you could have kept name of property as color inside PageItem and then
                                      // accessed color here as: color: model.color
                                      // I prefer to keep names distinct
                                      m_color: color
                                      m_Index: index  // index provided by Repeater
                                      m_PageNb: pageNb
                      
                                      /// Called when the component was opened
                                      Component.onCompleted:
                                      {
                                          // index provided by Repeater
                                          //index = Qt.binding(function() { return slView.currentIndex; });
                      
                                          // link remove signal between list model and page item
                                          remove.connect(lmViewModel.remove);
                                      }
                                  }
                      
                      
                                  /*
                                  Loader
                                  {
                                      // common properties
                                      source: "PageItem.qml"
                      
                                      // bind color property contained in Page item to this loader
                                      Binding
                                      {
                                          // common properties
                                          target: item
                                          property: "color"
                                          value: color
                                      }
                      
                                      // bind pageNb property contained in Page item to this loader
                                      Binding
                                      {
                                          // common properties
                                          target: item
                                          property: "m_PageNb"
                                          value: pageNb
                                      }
                      
                                      // bind index property contained in Page child item to this loader
                                      Binding
                                      {
                                          // common properties
                                          target: item
                                          property: "m_Index"
                                          value: index
                                      }
                      
                                      /// Called when the component was opened
                                      Component.onCompleted:
                                      {
                                          // link remove signal between list model and page item
                                          item.remove.connect(lmViewModel.remove);
                      
                                          console.log("Page Nb. - " + pageNb + " - " + item.m_PageNb);
                                      }
                                  }
                                  */
                      
                                  onPageNbChanged:
                                  {
                                      console.log("Page Nb. Changed - " + pageNb + " - " + item.m_PageNb);
                                  }
                              }
                      
                              function prevPage()
                              {
                                  if (!count)
                                  {
                                      currentIndex = -1;
                                      return;
                                  }
                      
                                  let index = currentIndex;
                      
                                  --index;
                      
                                  if (index < 0)
                                      index = count - 1;
                      
                                  currentIndex = index;
                              }
                      
                              function nextPage()
                              {
                                  if (!count)
                                  {
                                      currentIndex = -1;
                                      return;
                                  }
                      
                                  let index = currentIndex;
                      
                                  ++index;
                      
                                  if (index >= count)
                                      index = 0;
                      
                                  currentIndex = index;
                              }
                          }
                      
                          Component.onCompleted:
                          {
                              lmViewModel.append({"color": "pink", "pageNb": ++m_PageCount});
                          }
                      }
                      

                      PageItem.qml:

                      import QtQuick 2.15
                      import QtQuick.Controls 2.15
                      import QtQuick.Templates 2.15 as T
                      
                      T.Control
                      {
                          // aliases
                          property alias m_color: rcBackground.color
                      
                          // advanced properties
                          property int m_PageNb
                          property int m_Index
                      
                          // common properties
                          id: ctPage
                      
                          signal remove(int index)
                      
                          Rectangle
                          {
                              // common properties
                              id: rcBackground
                              anchors.fill: parent
                      
                              Text
                              {
                                  // common properties
                                  id: txText
                                  anchors.centerIn: parent
                                  text: "Page %1 - Index %2".arg(m_PageNb).arg(m_Index)
                              }
                      
                              MouseArea
                              {
                                  // common properties
                                  anchors.fill: parent
                      
                                  onClicked:
                                  {
                                      remove(m_Index)
                                  }
                              }
                          }
                      }
                      

                      Just to show how it looks using only PageItem as child of Repeater.
                      I renamed color to m_color. I have a comment about how that could be different.

                      C++ is a perfectly valid school of magic.

                      1 Reply Last reply
                      1
                      • jeanmilostJ Offline
                        jeanmilostJ Offline
                        jeanmilost
                        wrote on last edited by
                        #10

                        @fcarney Wow excellent, this work very well. Thank you very much for your help

                        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