[Development] Design review: Adapter layer, C++ to QML

Peter Kümmel syntheticpp at gmx.net
Thu Jan 31 08:22:44 CET 2013


On 30.01.2013 19:23, Charley Bay wrote:
> I've implemented a C++ "adapter-layer" (mostly template-based) to expose
> C++ objects to QML.
>
> We are in the "early-stages" for its use, and (of course) the "final-API"
> will significantly impact how we expose our (domain-specific) C++ classes
> to QML.
>
> My manager suggested I ask others what they are doing to solve similar
> problems (C++/QML adapter layer).  IMHO, this could reasonably be a
> "standardized" adapter-API for generalized use in applications with rich
> C++ classes that must be exposed to QML (that's us).
>
> ----------
> Design goals:
>
>   (a)- Expose individual C++ objects with minimal code
>
>   (b)- Individual "QML-instances" can "contain" a "C++ back-end-instance"
> that is not shared with other QML instances.
>
>   (c)- Multiple "QML-instances" can "share" access to the same C++ back-end
> instance, with coordinated updates (e.g., as one QML-instance triggers a
> C++ object "property-value-change", all QML instances are "notified" of
> that change)
>
>   (d)- Enable nested QML-wrapped-object-access to nested C++ instances that
> are natively stored (e.g., no refactoring of C++ code to incrementally
> expose nested C++ objects to QML)
>
>   (e)- Expose "sets" of C++ instances to QML (e.g., through
> "QAbstractListModel") with add/remove notifications to QML
>
> ----------
> Conceptual design:
>
> Each "C++ instance" is "wrapped" by a "singleton-QmlBoxBack" instance with
> application-specific properties exposed.  Many "QmlBox" instances will
> "reference" that single "QmlBoxBack" instance for "ultimate-state", and the
> "QmlBoxBack" will maintain the "registered-set" of "QmlBox" instances, so
> that when one "QmlBox" changes a property-value, all "QmlBox" instances are
> "notified" of the change.  Similarly, the "QmlBoxBack" instance is
> charged-with explicit notification of all "QmlBox" instances when the
> back-end C++ model changes asynchronously.  (We are using this for
> monitoring back-end instrumentation.)
>
> For logistical reasons, a "QmlBoxBacksManager<>" is needed to manage the
> (registered) "QmlBoxBack" instances, to preserve the "singleton" nature of
> the "QmlBoxBack" for a give C++ instance.
>
> ----------
> High level design is:
>
>   (1) The following C++ key abstractions are implemented:
>
>      - QmlBox (derives from QObject)
>      - QmlBoxBack (derives from nothing)
>      - QmlBoxBacksManager<> (template base class)
>
>   (2) Application-specific type definition:
>
>      - Implement your C++ class (e.g., "MyDog")
>      - Derive "MyQmlDogBox" from "QmlBox" to expose type-specific properties
>      - Derive "MyQmlDogBoxBack" from "QmlBoxBack" to propagate type-specific
> properties
>      - Use macro to define "MyQmlBoxBacksManagerDog" (which parameterizes
> "QmlBoxBacksManager<>")
>
>   (3) Application-specific use:
>
>      - QML can instantiate instances, or reference instances on the C++ side
>      - QML is "notified" when items are added/removed from the C++ side,
> which triggers instantiation of QML instances (e.g., through
> "QAbstractListModel" semantics)
>
>   (4) Internal details:
>
>      - Each C++ instance is "wrapped-by" a SINGLE "QmlBoxBack" instance,
> which "owns" or "references" that C++ instance (e.g., like a
> "smart-pointer")
>      - Many "QmlBox" instances are "registered" within a given "QmlBoxBack";
> when property values "change", all "QmlBox" instances are "notified" of
> that property-change
>      - All "QmlBoxBack" instances for a given "type" are "registered" with
> the "QmlBoxBacksManager<>" for that type, which deletes the "QmlBoxBack"
> instances when the C++ object is "destroyed", and un-registeres "QmlBox"
> instances as-needed.
>
>    SUMMARY:
>      - One "QmlBoxBack" for each C++ instance
>      - Many "QmlBox" instances "reference" a given "QmlBoxBack"
>

I would try to avoid the necessity of a new class only to bind the C++ code.
JS uses prototypes, so all you need on the JS side are callbacks to C++ to
build your prototypes. Once I used this approach for QScriptEngine

cmakescript.git.sourceforge.net/git/gitweb.cgi?p=cmakescript/cmakescript;a=blob;f=Source/cmJsUtilities.h

But I haven't tried it with QML.

>   (5) Practical use:
>
>      - ...where "myInstrument", "laser", and "wavelength" are implemented
> through application-specific C++ types:
>
>          Item {
>             color:  myInstrument.laser.wavelength.color
>          }
>
>      - ...where a "list-model" exists to expose many instances of the
> application-specific type "detector", which has properties "channel" and
> "filter":
>
>          ListView {
>            model:  myInstrument.detectors
>            delegate: Text { text: "(" + channel + ")" + filter.text }
>          }
>
> ----------
>
> QUESTIONS:
>
>   (1) Are you doing "heavy-duty-wrapping" of rich C++ models, without
> refactoring the C++ code?  What was the design, and did it work for you?
>
>   (2) Have you a critique for the design listed above (how to improve it, if
> it seems a reasonable approach)?
>
>   (3) Have I missed similar approaches that already exist, which we could
> otherwise use directly?
>
>   (4) Is there interest in "formalizing" this for wider conventional use by
> the Qt community?  (We are currently intending on using this for our code
> base, but the adapter-layer itself is not specific to our domain.)
>
> Thanks!
>
> --charley
>
>
>
> _______________________________________________
> Development mailing list
> Development at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/development
>




More information about the Development mailing list