Short version:
I need to have an object whose properties are to supply data to preexisting QML files.
I update all 20k properties at once at 60Hz, and would like QT to recalculate QML properties and layout only once at 60Hz, not when each property changes because of potential performance issues. That seems to be possible by sharing a single signal between multiple Q_PROPERTies that are known to only change together
However I would also like to supply a list of properties dynamically - using QQmlPropertyMap or similar approach. But QQmlPropertyMap does not allow sharing signals.
I can create my own QQmlPropertyMap-like class but that requires QMetaObjectBuilder which needs QT += core-private, or (dangerous?) creation of QMetaObject structure out of ints manually.
What should I do? Any hints are greatly appreciated!
Long version:
I'm writing an application that draws something like a car dashboard/navigator on screen using QT under Windows OS (non-UWP).
I need to create an module that supplies data to a set of existing QML files and shows result onscreen.
The QML-files all seem to bind to various properties of a single global contextProperty like this:
Rectangle { x: mydata.someval; y: mydata.someval + Math.sqrt(mydata.otherval)}
Rectangle { x: mydata.someval; y: mydata.someval + Math.sqrt(mydata.otherval)}
To copy to clipboard, switch view to plain text mode
QML makes no assumptions on what `mydata` is, as long as `mydata.someval` translates to a number.
The QML-files may be updated later so I should not modify them if possible.
I have a list of the properties in a JSON file, some with default values.
I also have a preexisting large C++ Visual Studio project that will supply the data.
The data values change frequently (about 60 times per second) and dataset contains about 20 000 items.
The app should run on a lower-end Windows PC if possible.
I would like to keep Visual Studio project separate from QT one as otherwise niether QT Creator nor Visual Studio would be able to understand combined project completely (it has MS-specific code such as COM).
I would also like to not recompile QT-part of the application whenever non-root QML-file or dataset changes.
It would therefore be best to create a DLL that could provide a C-style API to pass data between the projects like this:
int GetPropertyId(const char* propertyName);
void SetMyPropertyInt(int myPropertyId, int value);
void SetMyPropertyString(int myPropertyId, const char* value);
....
int GetPropertyId(const char* propertyName);
void SetMyPropertyInt(int myPropertyId, int value);
void SetMyPropertyString(int myPropertyId, const char* value);
....
To copy to clipboard, switch view to plain text mode
...and then use it:
static int someval_id = GetPropertyId("someval");
static int otherval_id = GetPropertyId("otherval");
while (true)
{
SetMyPropertyInt(someval_id, mylogic.calculate_someval());
SetMyPropertyInt(otherval_id, mylogic.calculate_otherval());
....
}
static int someval_id = GetPropertyId("someval");
static int otherval_id = GetPropertyId("otherval");
while (true)
{
SetMyPropertyInt(someval_id, mylogic.calculate_someval());
SetMyPropertyInt(otherval_id, mylogic.calculate_otherval());
....
}
To copy to clipboard, switch view to plain text mode
Because the properties need to be created dynamically, I'm using QQmlPropertyMap as root context property (`mydata`) - this seems to work so far.
However, when one property changes, all dependencies are recalculated, and QML properties often depend on a formula involving multiple data properties and other QML properties at once, so each change causes property recalculation, layout changes, recalculation of QML-object children that depend on the layout.
The core issue it that, although I can't see it now, this may be getting quite slow as more data is supplied.
The project that used to supply data to the QML files before was careful enough about what to update and when - so the issue wasn't readily visible. Unfortunately mine was written with simple screen rendering in mind, updates every value on each frame, and this cannot be fixed without a complete rewrite.
This is because EVERY one of sequential SetMyPropertyInt() calls causes a signal to fire.
That would make sense in general, but I know every property gets assigned at once, so there is no need to recalculate before all of them are updated. Now, how do I tell QT about it?
I found out that with MOC-generated QObject I can assign a single signal to multiple Q_PROPERTies.
I'm not sure if this is allowed, but it seems to work exactly as I want - I set all the properties' real data manually and then fire the signal once - QT is smart enough to update everything in one go. Actually, even if I setProperty() sequentially, QML properties only seem to be recalculated once - I have no idea why but that also works.
But that requires a `static` MOC-generated QObject, and I would prefer a dynamic one.
QQmlPropertyMap apparently generates signals itself and does not allow supplying custom ones:
QQmlOpenMetaObjectType
::createProperty(....
) { ....
d->mob.
addSignal("__" + QByteArray::number(id
) + "()"); ....
}
QQmlOpenMetaObjectType::createProperty(....) { .... d->mob.addSignal("__" + QByteArray::number(id) + "()"); .... }
To copy to clipboard, switch view to plain text mode
I can code a custom QQmlPropertyMap-like class, but it requires inclusion of `private/qmetaobjectbuilder_p.h` which is marked private and thus supposedly a bad idea.
(see DynamicObject from this article: https://machinekoder.com/creating-qm...lly-runtime-c/ )
...or I can feed a bunch of integers to QMetaObject like MOC compiler does - which doesn't seem to be a forward-compatible way either.
Is this problem a common one? Was it already solved by someone else? How would I approach it? Maybe it's not really supposed to be a problem at all? Am i going in a completely wrong direction?
Any hints, links, thoughts or other replies are greatly appreciated. Thanks in advance.
P.S.
I know that QML is for buttons and lists, not for quickly-updated dashboards - but that is not for me to decide.
Bookmarks