Hi,
I am trying to implement a simple collision detection. I am experiencing some strange behaviour with items that should not exist and are not visible (while invisibly having a location on the screen, see below) - but are found while iterating through QQuickWindow::contentItem's childItems.
I do find the expected Items:
Ok, that looks reasonable.
The unexpected Items go by this name:
CustomButton_QMLTYPE_17_QML_34
Where does the _QML_34 come from? Are they "invalid"/"old" in any way, just not yet deleted by QML?
I should add, that both numbers (here 17/34) change every time I run the program, (e.g. 67/72, 63/68, 45/62). The numbers seem to be somewhat random, the latter being always higher than the first. While the program is running, they stay constant.
For my view I am using a c++-model-driven QML Repeater which uses a rather complex "CustomButton.qml" as a delegate. Those CustomButtons are built from my own "CollidingItem" class, which inherits from QQuickItem. Works well.
collidingquickitem.h:
class CollidingQuickItem: public QQuickItem
{
Q_OBJECT
public:
CollidingQuickItem();
...
class CollidingQuickItem: public QQuickItem
{
Q_OBJECT
public:
CollidingQuickItem();
...
To copy to clipboard, switch view to plain text mode
CustomButton.qml:
CollidingQuickItem {
id: personButtonBasis
objectName: "unknownCustomButton"
x: 0
y: 0
width: 100
height: 100
....
CollidingQuickItem {
id: personButtonBasis
objectName: "unknownCustomButton"
x: 0
y: 0
width: 100
height: 100
....
To copy to clipboard, switch view to plain text mode
ClassroomScene.qml:
...
Repeater {
id: personRepeater
model: groupContent.personButtonContents
delegate: CustomButton {
id: customButtonDelegate
objectName: personRepeater.model[index].nameTop+" "+personRepeater.model[index].nameBottom
...
x: personRepeater.model[index].position.x
y: personRepeater.model[index].position.y
height: 90
width: 90
...
}
}
...
Repeater {
id: personRepeater
model: groupContent.personButtonContents
delegate: CustomButton {
id: customButtonDelegate
objectName: personRepeater.model[index].nameTop+" "+personRepeater.model[index].nameBottom
...
x: personRepeater.model[index].position.x
y: personRepeater.model[index].position.y
height: 90
width: 90
...
}
}
To copy to clipboard, switch view to plain text mode
To find collisions I am crawling through the childItems of QQuickWindow::contentItem, to find all "CollidingQuickItem"-Items, yet without actual collision testing. After this, the resultList contains both expected and unexpected items:
QList<QQuickItem *> Controller::findAllCollidingChildItemsRecursively(QQuickItem *item)
{
QList<QQuickItem*> resultList;
if (!item) {
return resultList;
}
bool isCollider=(dynamic_cast<CollidingQuickItem*>(item));
if ((isCollider)&&(!resultList.contains(item))) {
resultList.append(item);
//no further checking
} else {
foreach (QQuickItem* childItem, item->childItems()) {
resultList.append(findAllCollidingChildItemsRecursively(childItem));
}
}
return resultList;
}
QList<QQuickItem *> Controller::findAllCollidingChildItemsRecursively(QQuickItem *item)
{
QList<QQuickItem*> resultList;
if (!item) {
return resultList;
}
bool isCollider=(dynamic_cast<CollidingQuickItem*>(item));
if ((isCollider)&&(!resultList.contains(item))) {
resultList.append(item);
//no further checking
} else {
foreach (QQuickItem* childItem, item->childItems()) {
resultList.append(findAllCollidingChildItemsRecursively(childItem));
}
}
return resultList;
}
To copy to clipboard, switch view to plain text mode
The actual collisionCheck reveals the strange "ghost"-Items that I've never (willingly) instantiated, mainly in the upper left of the screen:
QList<QQuickItem
*> Controller
::itemsCollidingWith(QRectF rect
){
QList<QQuickItem *> resultList;
QQuickWindow* w = this->topLevelWindow();
foreach (QQuickItem* i, findAllCollidingChildItemsRecursively(w->contentItem())) {
if (rect.
intersects(QRectF(i
->x
(),i
->y
(),i
->width
(),i
->height
()))) { resultList.append(i);
qDebug()<<"Detection for "<<i->objectName()<<" / "<<i->metaObject()->className();
qDebug()<<typeid(i).name();
}
}
return resultList;
}
QList<QQuickItem *> Controller::itemsCollidingWith(QRectF rect)
{
QList<QQuickItem *> resultList;
QQuickWindow* w = this->topLevelWindow();
foreach (QQuickItem* i, findAllCollidingChildItemsRecursively(w->contentItem())) {
if (rect.intersects(QRectF(i->x(),i->y(),i->width(),i->height()))) {
resultList.append(i);
qDebug()<<"Detection for "<<i->objectName()<<" / "<<i->metaObject()->className();
qDebug()<<typeid(i).name();
}
}
return resultList;
}
To copy to clipboard, switch view to plain text mode
Interestingly, the typeId is always the same, the className differs between those items that are visible and should be there - and the others.
Normal output (hitting a visible item):
Detection for "Carsten Ernst" / CustomButton_QMLTYPE_17
P10QQuickItem
Unexpected output (testing an empty area on the top / topLeft of the screen):
"unknownCustomButton" / CustomButton_QMLTYPE_17_QML_34
P10QQuickItem
There are several of these "unknownCustomButton"s.
Any information about QML's className generation or a possible origin of those items would be cool.
Bookmarks