[Interest] Force property's binding to be executed from C++

Xavier Bigand flamaros.xavier at gmail.com
Wed Aug 24 01:24:28 CEST 2016


Thank you Jerome, I just found QQmlProperty::connectNotifySignal
method. QQmlProperty seems much simpler to use instead of meta info (it is
why it was added according to the documentation)

I made a simple try and it's called just after the qml binding was updated,
so it seems to do just what I want.
And I will be able to connect all my properties on the same slot or on a
dedicated one if it is too slow (I doubt about that because our changes are
lazy).

For the rest it is already the case, our skin properties are in a singleton
component (to optimize memory usage), and we do hot reloading of our qml
files with a file watcher during the development ;-)


Thank you too Jason, before we were using a separated xml file (one per
skin/product for our 3D elements), and it is much more easier for us to use
bindings instead of separating values by skins.

Have a good day both.


2016-08-24 0:19 GMT+02:00 Jérôme Godbout <jerome at bodycad.com>:

> For the second part, you should expose those value into properties where
> the skin object refer too (most likely a map of properties where it can
> fetch those skin values). and emit Changed on that map when you data
> changed.
>
> I think you allow dynamic skinning that can be set from the outside and
> those value are filled at run time (like a debugger or user can give live
> property setting to an object). If this is the case, you need to connect
> yourself to any changed on that input.
>
> I strongly recommend making a Component that set the colors based on the
> current skin and perform a Singleton with a Loader that load the Component
> and bind yourself to that loaded part (make sure you have a default
> Component to provide when none are available by the loader). This way you
> could make a simple Component file that can inherite from each other but
> can override any skin value and you can create as many as you want, make a
> folder file observer and can even detected them and add them to the GUI
> theme selection (this is what I do for my apps and it work like a charm).
>
> On Tue, Aug 23, 2016 at 6:11 PM, Jérôme Godbout <jerome at bodycad.com>
> wrote:
>
>> Hi,
>> You can retreive the properties changed from meta information of those
>> properties on you object.
>>
>> I'm not sure I understand your use case but here's some info that may
>> help.
>>
>> auto meta_obj = target_object_->metaObject();
>> for(int i = 0; i < meta_obj.propertyCount(); ++i)
>> {
>>   auto meta_property = meta_obj.property();
>>   auto method_signal = meta_property.notifySignal();
>>   connect(target_object_, method_signal, myHandler, handle_slot_name);
>> }
>>
>> You may want to keep a list of object connections if they don't get
>> deleted when swaping to disconnected them.
>>
>> So you can now handle those property changed from C++ without writting
>> Qml binding directly. This also work with signal and slots.
>>
>> Most likely, you want to bind on any changed properties of the skin and
>> revaluate the whole skin manager update sequence I guess.
>>
>> Jerome
>>
>>
>> On Tue, Aug 23, 2016 at 5:36 PM, Xavier Bigand <flamaros.xavier at gmail.com
>> > wrote:
>>
>>> That the problem, I can easily call my SkinManager::updateSkin when the skin changed, because it's a cpp attribut too (the selected skin). But I have to call it when the QmlEngine have reevaluated the properties values not before.
>>>
>>> Getting property values directly from cpp code doesn't execute bindings (as much as I know), so I am trying to call this slot (SkinManager::updateSkin) from Qml where it should be easier to fix this calling order issue.
>>>
>>>
>>> If I create a property that depends of all others it be reevaluated after the others, then I will be able to invoke my cpp slot from his onChanged signal.
>>>
>>> The difficulty is to create this property.
>>>
>>>
>>>
>>>
>>> My QML component looks like to this :
>>>
>>>
>>> HomeDesignSkins.qml :
>>>
>>>
>>> Item {
>>>
>>>     id: homeDesignSkins
>>>
>>>        readonly property color accentucationColor: {                                                                       // In cpp SkinManager::updateSkin() method can be invoked before the execution of this binding,
>>>
>>>         if (application.product === Product.ProductOutdoor)                                                            // the better way to solve this issue is to create a binding dependency
>>>
>>>             return "#45a785"
>>>
>>>         else if (application.product === Product.ProductMyDreamHome)
>>>
>>>         {
>>>
>>>             if (settings.skin === "MyDreamHomeThemeCanson")
>>>
>>>                 return Qt.rgba(235 / 255, 130 / 255, 122 / 255, 255 / 255)
>>>
>>>             else if (settings.skin === "MyDreamHomeThemeMilli")
>>>
>>>                 return Qt.rgba(242 / 255, 118 / 255, 82 / 255, 255 / 255)
>>>
>>>             else
>>>
>>>                 return Qt.rgba(145 / 255, 135 / 255, 148 / 255, 255 / 255)
>>>
>>>         }
>>>
>>>         else
>>>
>>>             return "#8da7c0"
>>>
>>>     }
>>>
>>>
>>>     ...
>>>
>>>
>>>     // Here we have numerous properties used to describe our GUI skin (some are shared with the cpp code for our 3D rendering)
>>>
>>>
>>>     Object {
>>>
>>>         property string homeDesignSkinsProperties: {
>>>
>>>                    var propertyValues
>>>
>>>                    for (var propertyName in homeDesignSkins)
>>>
>>>                           propertyValues += propertyName + " "                                 // How retrieving the property values by their names
>>>
>>>                    return propertyValues
>>>
>>>              }
>>>
>>>
>>>             onHomeDesignSkinsPropertiesChanged: {                                     // This signal should be called once after that all properties of homeDesignSkins where reevaluted when the skin changed
>>>
>>>                    skinManager.updateSkin()                                                     // skinManager is the instance of the cpp SkinManager singleton, updateSkin is an Q_INVOKABLE method
>>>
>>>             }
>>>
>>>     }
>>>
>>> }
>>>
>>>
>>>
>>>
>>>
>>>
>>> 2016-08-23 21:29 GMT+02:00 Jason H <jhihn at gmx.com>:
>>>
>>>> If I understand you correctly, and I probably don't, the skin component
>>>>
>>>> Skin {
>>>> signal skinPropertyChanged();
>>>> property color accentucationColor: "red"
>>>> onAccentucationColorChanged: skinPropertyChanged()
>>>> }
>>>>
>>>> SkinManager {// exposed C++ class
>>>>     id:skinManager
>>>>     property var currentSkin: null;
>>>>     onCurrrentSkinChanged: updateSkin(); // handle when the skin
>>>> switches
>>>> }
>>>>    Connections {
>>>>       target: currentSkin
>>>>       onSkinPropertyChanged: id:skinManager.updateSkin() // handle when
>>>> propterties of the skin change.
>>>>    }
>>>>
>>>> Will that work?
>>>>
>>>>
>>>> *Sent:* Tuesday, August 23, 2016 at 1:12 PM
>>>> *From:* "Xavier Bigand" <flamaros.xavier at gmail.com>
>>>> *To:* interest at qt-project.org
>>>> *Subject:* [Interest] Force property's binding to be executed from C++
>>>> Hi,
>>>>
>>>> To skin our GUI we have a dedicated qml component instanced once that
>>>> contains all necessary values under properties.
>>>> I am able to access to those properties from C++ code but they aren't
>>>> correctly synchronized with the selected skin.
>>>>
>>>> Here is my cpp code :
>>>>
>>>>
>>>>     void SkinManagerWrapper::updateSkin() const
>>>>
>>>>     {
>>>>
>>>>         QObject*    skinItem = mRootObject->findChild<QObject*>("hdGUI", Qt::FindDirectChildrenOnly);
>>>>
>>>>
>>>>
>>>>         core::SkinManager*  skinManager = core::SkinManager::singleton();
>>>>
>>>>
>>>>
>>>>         // General
>>>>
>>>>         skinManager->accentuationColor = convert(skinItem->property("accentuationColor").value<QColor>());           // skinManager->accentuationColor is actually a cpp property ;-)
>>>>
>>>>     }
>>>>
>>>>
>>>> The property method return the previous value before the execution of
>>>> the binding, because in the qml binding the value is depending of the
>>>> selected skin.
>>>>
>>>> As workaround I am trying to create a qml property that depend of all
>>>> properties of our skin component ("HomeDesignSkins"), but If it is possible
>>>> to retrieve dynamically properties names of the component, I can't figure
>>>> out retrieving values of properties by string names.
>>>> The Idea is to be able to use the onChanged signal of this property to
>>>> invoke my cpp updateSkin method, this should resolve dependency order issue.
>>>>
>>>> Maybe their is an other way to do it, else I am searching to way to
>>>> retrieve property values in qml from their names.
>>>>
>>>>
>>>> --
>>>> Xavier
>>>> _______________________________________________ Interest mailing list
>>>> Interest at qt-project.org http://lists.qt-project.org/ma
>>>> ilman/listinfo/interest
>>>>
>>>
>>>
>>>
>>> --
>>> Xavier
>>>
>>> _______________________________________________
>>> Interest mailing list
>>> Interest at qt-project.org
>>> http://lists.qt-project.org/mailman/listinfo/interest
>>>
>>>
>>
>


-- 
Xavier
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20160824/6ef366c9/attachment.html>


More information about the Interest mailing list