PDA

View Full Version : QDeclarativeView question



cmessineo
30th June 2015, 22:19
Hi all, I'm using a QDeclarativeView object to open a qml file. I use it as such:

MainView w;
w.setSource(QUrl::fromLocalFile(settings.value("main_view").toString()));

Where MainView inherits from QDeclarativeView

In my mainview.qml file I use a Loader to load various QML files depending on what the user selects from menus. How can I tell in C++ when the underlying QML structure changes? Is there a signal I can hook into?

Thanks

wysota
1st July 2015, 01:06
What do you need that functionality for?

cmessineo
1st July 2015, 18:17
wysota, I want to cache some QDeclarativeItem * in a Hash.

I find this look up tends to be slow:
QDeclarativeItem *obj = this->rootObject()->findChild<QDeclarativeItem*>(item);


I thought I'd empty the cache each time a new qml file was loaded by my loader.

I found a work around, I delete from the cache items that have not been looked up after 10 minutes.

wysota
1st July 2015, 22:11
wysota, I want to cache some QDeclarativeItem * in a Hash.
That's a solution, I'm asking about the problem.


I find this look up tends to be slow:
QDeclarativeItem *obj = this->rootObject()->findChild<QDeclarativeItem*>(item);
You should (almost) never need that in real world app.

cmessineo
1st July 2015, 23:04
I'm sure the guys at Digia would not have created methods like findChild or setProperty if they didn't expect people to use them in real world.

Right now I use this code, so I can update qml properties on a touch screen display module. Data comes in over a serial port and depending upon the data I update a property in qml.

QDeclarativeItem *obj = this->rootObject()->findChild<QDeclarativeItem*>(item);

if(!obj) {
qDebug() << "[QML] no item with objectName: " << item;
bool found = obj->setProperty(property.toLatin1(),value);
}

wysota
1st July 2015, 23:10
I'm sure the guys at Digia would not have created methods like findChild or setProperty if they didn't expect people to use them in real world.
findChild was created long before Digia took over Qt :) Anyway, the fact that a method exists doesn't automatically mean it should be used for things you are trying to use it for. My point is that in a general case you shouldn't "extract" items from a Qt Quick scene into C++.


Right now I use this code, so I can update qml properties on a touch screen display module. Data comes in over a serial port and depending upon the data I update a property in qml.
You should rather expose your data model to Qt Quick and connect your items to the data model there.

cmessineo
1st July 2015, 23:41
Well that is the problem and it is my fault for not communicating properly, there is no data model. The QML is not known by me, I don't know what other people will create, so I have to find the child item and update a property if I can. I just didn't want to use findChild("root") if I had made that call 100ms ago and it was successful. I can cache things the way I want, I just can't tell if the qml has changed, so I can kill the cache. Most people use a Loader for navigation of their QML applications. I was hoping to find a way to figure out when the Loader loaded up some new qml file. The only thing I have control over is the C++ qmlviewer app that I created. I don't know what the qml will be.

wysota
1st July 2015, 23:51
Well that is the problem and it is my fault for not communicating properly, there is no data model.
There is always some data model. At first glance I can see you have some objects that have some properties that have some values. Now it's just a matter of wrapping them in a nice API.


The QML is not known by me, I don't know what other people will create, so I have to find the child item and update a property if I can.
In my opinion you should rather do the opposite -- inform QML that some value has changed and let the author of the document handle that.


I just didn't want to use findChild("root") if I had made that call 100ms ago and it was successful.
How do you know that object still exists 100ms later?


I can cache things the way I want, I just can't tell if the qml has changed, so I can kill the cache.
"QML" doesn't have to "change" for objects to stop existing. Consider the following code:


... {
id: root
property Item someItem: null

Component {
id: c
Item { objectName: "someObject" }
}

Component.onCompleted: root.someItem = c.createObject(root)

Timer {
interval: 10000
running: true
onTriggered: if(root.someItem) { root.someItem.destroy(); root.someItem = null }
}
}

How do you know whether "someObject" exists or not, even if it existed just a moment ago?


I was hoping to find a way to figure out when the Loader loaded up some new qml file.
That's pretty easy as the loader will emit an itemChanged signal when it does that however it will not make your code work. Especially that you don't know if there is any Loader at all.

cmessineo
2nd July 2015, 00:14
I thought there would be a mechanism for me to hook into when something like this happened:

Timer {
interval: 10000
running: true
onTriggered: if(root.someItem) { root.someItem.destroy(); root.someItem = null }
}

Or even if a QML Item was created through javascript. Some signal that an object was created or destroyed.

wysota
2nd July 2015, 08:13
I thought there would be a mechanism for me to hook into when something like this happened:

Timer {
interval: 10000
running: true
onTriggered: if(root.someItem) { root.someItem.destroy(); root.someItem = null }
}
There are too many situations like that that can cause you trouble. You will not patch and stitch each and every one.


Or even if a QML Item was created through javascript. Some signal that an object was created or destroyed.
You can do that using QGraphcisItem API but that will be hell slow since you'd be monitoring every item in the scene. I assure you this is a wrong way to approach your problem. The proper way is to expose some API to QML scripts and ask authors of the scritps to use that API.

E.g. something along the lines of:

Item {
id: myObject
ChangeListener {
name: "myObject"
properties: [ "width", "height", "x", "y" ] // listen to changes on these properties
onChanged: myObject[propName] = value // propName and value are parameters of onChanged signal
}
}

or even:
Item {
id: myObject
objectName: "myObject"
ChangeListener {
target: myObject
properties: [ "width", "height", "x", "y" ]
// updating the property is done in C++
}
}

anda_skoa
2nd July 2015, 09:55
The QML is not known by me, I don't know what other people will create, so I have to find the child item and update a property if I can
So how do you know that the item exists?

I agree with wysota, this sounds like a very broken setup.

The cleanest and incidentally at the same time easiest way is to export an object with the data property as a context property and let the QML side use it wherever it wants to.

Cheers,
_