PDA

View Full Version : Eliminate Binding loop warning



laszlo.gosztola
17th August 2011, 19:18
Hello,

I have a sample code listed below. It works well, but always writes a debug message:
QML QDeclarativeRectangle_QML_0: Binding loop detected for property "parent"

Do anybode have any idea, how could I eliminate this warning?



import QtQuick 1.0

Rectangle {
id: rect1
color: "lightblue"
width: 800
height: 600

Item {
width: 600
height: 600

Rectangle {
id: test
parent: getRootObject()
anchors.fill: parent
color: "yellow"
opacity: 0.5

//! goes to the root object via the item's parent property
function getRootObject() {
var item = test.parent
while (item.parent != undefined) {
item = item.parent
//console.log("w: "+ item.width + " h: " + item.height)
}
return item
}
}
}
}

wysota
17th August 2011, 19:25
What's the point of what you are trying to do? Why not simply declare the object with a proper parent in the first place?

laszlo.gosztola
17th August 2011, 21:03
It's a MessageBox component. I have to fill the screen with a MouseArea to 'eat' the mouse click events.
There is a controller logic in QML which loads different QML files. But I want an universal messagebox, and not always really know, 'who' is the root object, that's why I wanted to use this approach.
Maybe I can solve simply returning from the C++ side a pointer of the rootObject, but I wanted to keep it in the QML side.

wysota
17th August 2011, 21:12
You can keep it in QML. Create the component on the fly when you need it and just put it on top of everything, you don't need to reparent it.

laszlo.gosztola
17th August 2011, 21:28
Do You have a sample how do you think? If I not reparent the item, then positioning will be strange. For example I have an info and a task bar at the upper and the lower parts of the screen. If I don't reparent the item and set x and y to 200, it will be relative to the parent item - the upper side of the screen or the lower. Or not?

wysota
17th August 2011, 21:39
If you create the item parentless, it will be working in scene (aka absolute) coordinates. Or you can declare it as a child of your root element and work in this element's coordinates.

However wouldn't it be simpler to make your message box modal simply by disabling all other mouse areas? You can do that with one property binding.

laszlo.gosztola
17th August 2011, 22:09
Maybe disabling the Mouse Areas is possible but I also use a dimmer component to fade a bit out the background.
So, if I create the MessageBox without parent as You said, get the root item with my getRootItem function I can set the Dimmer's width and height to it's height and width, and it's tha same than the original problem.
I try it...

Added after 10 minutes:

Not perfect. In the sample I wrote in the first post, works well.
But in the real code not OK.

Maybe the problem is that I don't create the component on the fly, and it get a parent.
I have something like this:
InfoBar.qml


import QtQuick 1.0
Item {
id: container
....
Button {
onClicked: errorMessage.show()
}

MessageBox {
id: errorMessage
...
}
}


I removed the parent property from the MessageBox, but it stayed relative to the item

wysota
17th August 2011, 23:10
I removed the parent property from the MessageBox, but it stayed relative to the item
QML is a declarative language. If you declare one item within the scope of another, it will be its child.

I don't know why you're so reluctant to create the element just when you need it. Especially that you're trying to use it in imperative manner anyway.

Added after 23 minutes:

Here is a crude but working example of a completely declarative way of approaching the problem:

import QtQuick 1.0



Rectangle {
id: rectangle1
width: 360
height: 360

function showBox() {
messagebox.state = "shown"
}

Rectangle {
// some button

width: 100
height: 50
color: 'red'
anchors.left: parent.left
anchors.leftMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
MouseArea {
anchors.fill: parent
onClicked: showBox()
}
}

Rectangle {
id: messagebox
anchors.fill: parent
color: '#dd000000'
opacity: 0
z: 1000
Rectangle { // box
width: 200
height: 100
radius: 10
anchors.centerIn: parent
color: 'white'

Rectangle {
width: 50
height: 30
radius: 3
border.color: "#000055"
border.width: 1
color: "#5555FF"
anchors.centerIn: parent

Text {
text: 'OK'
anchors.centerIn: parent
color: "white"
}
MouseArea {
anchors.fill: parent
onClicked: messagebox.state = 'hidden'
}
}

}
states: [
State {
name: "hidden"
PropertyChanges { target: messagebox; opacity: 0 }
},
State {
name: "shown"
PropertyChanges { target: messagebox; opacity: 1 }
}

]
transitions: [
Transition {
NumberAnimation { properties: "opacity"; duration: 500 }
}
]
}
}

laszlo.gosztola
18th August 2011, 08:56
Hello,
thanks for your efforts to solve this problem.
The background why I try this way: This MessageBox component works well in a former project. Exactly, there is a universal dialog component and a MessageBox component which is 'inherited' from the Dialog (I don't know how you say it in declarative world). Each of them is creatable from the C++ logic also. The MessageBoxes are created at initiialisation, just like in your example and if e.g. an error occurs, I call the show() method. But, in that project I know always the root object, and can set the parent.


MessageBox {
id: errorMsgBox

parent: root
type: MessageBoxType.Critical
title: "Saving Failed"
message: "Wrong input"

Component.onCompleted: {
addButton(0, "OK")
}
onButtonClicked: {
errorMsgBox.hide()
}
}

In this case root is the 'base' object, which fills the whole screen. It works well.

But in this project, there concept is that there are different tasks, which has different screens. A 'screen_controller' manages task and screen changes. And if I try to use the base object like I done in the previsous sample, it says that the variable not found. (Maybe I should take a deeper look why the debugger says it.) But this was the reason why I wanted to find the root object with this function. I also think that it's better to declare the objects like you do in your last example, but I need the fill the whole screen.

So far, I think the possibilities are the following:
- create the MessageBox on the fly, when I need it, and set the width and height to the root Object's width and height. Not elegant and maybe slows down the app, when I create the component
- create the component in the QML file, like you did - if I know the root object, everything is fine - if the engine don't find the root object, then I should find with my function and reparent it (works, but gives the warning). Maybe finding the root object, use the width and height of it, and set the coordinates with some hack of mapToGlobal functions to set the x and y properties, etc.
- or get a pointer to the root object from the c++ side. Not elegant, too.

wysota
18th August 2011, 09:41
I'm sorry, I still fail to see why you don't know what the root object is and why you want to reparent the box to the root object. In my opinion it is the responsibility of the message box object to know where to place itself. The way I see it, you are trying to employ an imperative (do this, then do this, then do this) approach in a declarative (I want it to be doing this and this) environment. If you want to know the root object, then just add an identifier for it and then refer to this identifier.