8

I want to loop through a QML Grid's children and destroy each of them using Javascript.

Grid {
  id: contentGrid
  spacing: 10

  ImageItem { imageSource: "file:/foo.jpeg"  } // destroy this
  ImageItem { imageSource: "file:/bar.jpeg"  } // destroy this as well
}

I tried to do something like this but it's not working so far.

for(var i = 0; contentGrid.children.length() < i; i++) {
    contentGrid.childAt(i).destroy();
}
alex
  • 4,922
  • 7
  • 37
  • 51

4 Answers4

16

You have a number of problems in your attempt above... First, you'll need to iterate backwards because you'd be shifting the contents of the children down as you advance (ie, if you delete #1, number #2 would become child #1 and then you'd go to delete #2 which would be the old child #3).

Second, you need to access the children differently. The childAt() function is for locating a child at a particular x,y on the screen, not a position in a list.

Try this instead:

import QtQuick 1.0

Rectangle {
  width: 400
  height: 400
  Grid {
    id: contentGrid
    spacing: 10

    Text { text: "foo"  } // destroy this
    Text { text: "bar"  } // destroy this as well
  }
  MouseArea {
    anchors.fill: parent
    onClicked: {
      for(var i = contentGrid.children.length; i > 0 ; i--) {
        console.log("destroying: " + i)
        contentGrid.children[i-1].destroy()
      }
    }
  }
}
Wes Hardaker
  • 21,735
  • 2
  • 38
  • 69
  • 18
    Ha ha! the best part is I had to come back to find my own answer to remember how to do this! – Wes Hardaker Jan 25 '12 at 17:23
  • in context of backwards: if destroying renumbers the children collection, why not while(grid.children.length>0) grid.children[0].destroy() ? – quetzalcoatl Oct 10 '12 at 12:33
  • 6
    Deleting the children in forward order as @quetzalcoatl suggested would work, but if you have a large list of children it would be much slower because each time you destroy the 0th element, all other elements would have to shift down, even though they are about to be deleted anyway. Doing it backward would be O(n) while forward would be O(n^2). – Carrotman42 Jan 29 '13 at 18:41
  • Hm.. as you say it.. If it really behaves that way, I of course agree with you - it is important. But I have to also point out that actually this is internal implementation detail of the framework. Were the "children" implemented as kind of list not array/vector, or were the container amortized, then trimming head or tail would cost the same. I have not researched this subject, my often-chaning collections never were larger than a dozen of items. Nevertheless, **if** you are sure that there is difference in performance, then this is a great point! – quetzalcoatl Jan 30 '13 at 10:33
  • 1
    @WesHardaker What is your opinion on the other answers? Especially the one of Atron indicating that your approach violates the documentation? – m7913d Jul 29 '17 at 11:40
  • 1
    @m7913d: I think that's a valid point. When I use the above, it is because I've created them dynamically. – Wes Hardaker Sep 12 '17 at 18:49
4

or you can just say: grid.children = "";

mshefiti
  • 103
  • 1
  • 7
  • This actually works, I'm just wondering how this behaves in performance / memory consumption, compared to the much more complicated solution in the other answer (http://stackoverflow.com/a/8852535/1202500) – mozzbozz Jan 08 '15 at 16:24
  • @mozzbozz there is no loop, so I would guess it behaves better. But still I am not very familiar with performance measurements. – mshefiti Jan 10 '15 at 20:18
  • 2
    My test shows that the children are not destroyed and remain in memory. – Hans One Jul 12 '17 at 11:37
  • @HansOne If this is the case (for statically created items), then it seems to be a bug and this should be reported to Qt using https://bugreports.qt.io/. Destroying them manually may work with your current Qt release, but there is no guaranty that it will work in future releases. – m7913d Jul 30 '17 at 12:47
3

I just want to copy & paste a fragment from documentation:

Note that you should never manually delete objects that were dynamically created by convenience QML object factories (such as Loader and Repeater). Also, you should avoid deleting objects that you did not dynamically create yourself.

Then, the answer is YOU SHOULDN'T do it! Try to create the object dynamically if you want to delete it later.

Documentation

albertTaberner
  • 1,969
  • 1
  • 26
  • 35
  • 1
    The documentation indeed says this. http://doc.qt.io/qt-4.8/qdeclarativedynamicobjects.html also says "Note also that if a SelfDestroyingRect instance was created statically like this: `Item { SelfDestroyingRect { // ... }}` This would result in an error, since items can only be dynamically destroyed if they were dynamically created." – Ayberk Özgür Jun 27 '16 at 06:12
0

As an addition to Atron's answer, note that the documentation explicitly mentions that destroying a statically created object manually is not allowed:

Item {
    SelfDestroyingRect {
        // ...
    }
}

This would result in an error, since objects can only be dynamically destroyed if they were dynamically created.

Therefore, I agree with mshefiti that the correct solution (for items that aren't dynamically created) is:

grid.children = [];
m7913d
  • 10,244
  • 7
  • 28
  • 56