Wrapping C++ Objects for Property Exposure in QML

Wrapping C++ Objects for Property Exposure in QML

Wrapping C++ Objects For Property Exposure In QML Charley Bay Beckman Coulter, Inc. Review: C++ From Within QML Integrating QML and C++: (1) Call (Invoke) C++ from QML – Invoke (existing / internal) C++ API for Qt QML or Qt Quick – Apply Q_INVOKABLE to funcs in QObject-derived (2) Implement C++ Types for QML – Derive from QObject – Define “properties” (Q_PROPERTY()) – Register with QML qmlRegisterType() qmlRegisterUncreatableType() qmlRegisterInterface() qmlRegisterSingletonType() What's The Problem? The Issue: "Deep / Rich" Types Are typically: ● Domain-specific ● Have business logic ● Often found in legacy systems ● Expected to be "reusable" within that domain ● Are often "key abstractions" (but not always) ● May be "lightweight" or "heavyweight" Deep / Rich Types: Ligthweight Lightweight: "Popcorn Types" ● Frequently come-and-go (are created-and-destroyed) ● Have non-trivial business logic ● Often imply rules needed throughout the system (e.g., point-of- entry data validation, back-end system adaptation across components/revisions of hardware, etc.) ● Often used to bridge sub-systems ● Often "serialized" to span sessions, setups, configurations ● Often comprise significant portions of the domain-specific APIs for "interface-state" (e.g., are "ubiquitous") These are typically your desired QML "properties"! Deep / Rich Types: Lightweight Examples Example "Lightweight-Deep/Rich" types – class Wavelength – class Voltage – class Parameter – class Detector – class SpectraFilter Deep / Rich Types: Heavyweight Heavyweight: Typically "Key Abstractions" ● Often created at "system-start" with known configuration (e.g., "devices") ● Typically expressed through class hierarchies (e.g., across device revisions, devices specific to a product line evolution) ● Typically consistent across products / product-lines (e.g., "one software to control all devices in a family-of-product-lines) ● May be "plug-&-play" (e.g., subsystems may come-and-go as units during system-run) ● Is often what needs to be monitored / controlled ● Is part of higher-level system (coordination with other key abstractions is typical for data validation, denial of access/operations [e.g., "baton-passing"], etc.) You typically want to "hand-wrap" these for QML! Deep / Rich Types: Heavyweight Examples Example "Heavyweight-Deep/Rich" types – class FluidicsSubsystem – class OpticsSubsystem – class CytometerInstrument – class ExperimentArchive QObject Implies Alternative Control Flow QObject and QMetaObject: ● signals/slots introduce coupling to imply "alternative- control-flow" (only relevant to designs intended for that control flow) ● QObject-derived types should typically be used as "identity" instances (not with value semantics, copy CTOR and operator=() not available) Signals/slots are “side-effect” triggers used to assemble, communicate among, and “stitch-together” across sub-systems. While they can be used within a sub- system, they are often not needed where deterministic behavior is required within (even large) key-abstractions that represent functional business-logic state. Wrapping Deep / Rich Types: QObject C++ types sometimes cannot derive from QObject: ● If cross-platform embedded (to "very-small-footprint-deployment") ● If application-specific performance requirements ● If application-specific design may establish class hierarchies (which disallow QObject) ● If used where Qt is not used ● If "existing/legacy" code rd ● If 3 Party code that cannot be modified ● If developed / tested at unit / functional level with as little coupling as possible An Example: class Wavelength class Wavelength ● Lightweight class { (only data member is double value_nm_; //IS ONLY DATA MEMBER! “double”) public: Wavelength(double value_nm); Wavelength& operator=(double value_nm); ● Has domain-rules Wavelength& operator=(Wavelength& other); – Range-bounds QString getAsLabel(void) const; – Label formatting bool isBlue(void) const; bool isGreen(void) const; – Interpreted as “color” bool isOrange(void) const; bool isRed(void) const; ● Is ubiquitous bool isViolet(void) const; bool isYellow(void) const; throughout domain- specific APIs bool isVisible(void) const; }; const bool switch ( band ) { const bool Wavelength case 0: Wavelength const SdString ::setFromStringParseable( // wavelength_in_nm <= 380 (Invisible, but we need *some* color) ::operator<(const Wavelength& other) const Wavelength const SdString& string, r_0_to_1 = 0.35; { ::getAsString(void) const long& start_index) g_0_to_1 = 0; return isLessThan(other); { const bool { b_0_to_1 = 1; } //FILE: SdString string; Wavelength //------------------------------------------------------------------------ intensity_0_to_1 = 0.3; // appendToString(string); ::hasStateWithWholeNm(void) const // ------------------------------------------------------------------------ break; const bool const bool return string; { //------------------------------------------------------------------------ Wavelength Wavelength #include <limits> // For std::numeric_limits<double> } return hasState() && (!hasStateWithFractionalNm static const SdString()); STRING_NM_ (STR_NM_); case 1: ::IsWavelengthVisible(double wavelength_nanometers) ::operator<=(const Wavelength& other) const #include <algorithm> // For max() } //------------------------------------------------------------------------ // 380 < wavelength_in_nm <={ 420, violet { const bool //------------------------------------------------------------------------ r_0_to_1 = std::max(0.35, - (wavelength_in_nm return (wavelength_nanometers-440)/(440-380)); >= WAVELENGTH_NM_VISIBLE_MIN) return isLessThanOrEqual(other); #include "Wavelength.hpp" Wavelength const bool //------------------------------------------------------------------------ g_0_to_1 = 0; && } ::getAsStringParseable(SdString& string) const Wavelength b_0_to_1 = 1; (wavelength_nanometers <= WAVELENGTH_NM_VISIBLE_MAX); #include "SdString.hpp" { ::hasWavelength(double wavelength_value clear();) const intensity_0_to_1 = 0.3 + 0.7*(wavelength_in_nm} -380)/(420-380); const bool #include "TypeUtil.hpp" string.clear(); { break; Wavelength return appendToStringParseable(string); return TypeUtil::IsValuesEqual long(wavelength_value start_index_temp, wavelength_nanometers = string.findIndexFirstCharNonWhitespace_); (start_index); const bool ::operator!=(const Wavelength& other) const } } if(start_index_temp >= 0) case 2: Wavelength { { // We have something in this string at-or-after the index // 420specified. < wavelength_in_nm <=:: IsWavelengthVisibleBlue440, blue (double wavelength_nanometers) return isNotEqual(other); //------------------------------------------------------------------------ const SdString const bool // r_0_to_1 = -(wavelength_in_nm{ -440)/(440-380); } //------------------------------------------------------------------------ Wavelength Wavelength if(string.isCharDigit(start_index_temp)) g_0_to_1 = 0; return (wavelength_nanometers >= WAVELENGTH_NM_BLUE_MIN) //------------------------------------------------------------------------ ::getAsStringParseable(void) const ::isEqual(const Wavelength& other) { const b_0_to_1 = 1; && const double { { double value; break; (wavelength_nanometers <= WAVELENGTH_NM_BLUE_MAX); Wavelength static const char* STR_NM_ = "nm"; SdString string; // if(this != &other) if(string.parseFloatingStartingAt(value, start_index_temp )) } ::operator+(const Wavelength& other) const appendToStringParseable(string); // { { case 3: { //------------------------------------------------------------------------class return string; returnWavelength wavelength_nanometers _ == other.wavelength_nanometersif(IsOkWavelengthInNanometers_; ((double)value) || (value // 440 == <WAVELENGTH_NM_NONE)) wavelength_in_nm <=const 490, bool blue green As It Really Exists: return operator+(other.wavelength_nanometers _); //------------------------------------------------------------------------ } // } { // We read an acceptable value, or successfully parsedr_0_to_1 a zero.= 0; Wavelength } //------------------------------------------------------------------------ const bool // return true; // RECALL: We MAY have an optional "nm", so if we g_0_to_1 see it, = (wavelength_in_nm::-IsWavelengthVisibleGreen440)/(490-440); (double wavelength_nanometers) Wavelength } // we should skip it. b_0_to_1 = 1; { const double ::getAsStringUserInterface(SdString& string) const if(start_index_temp >= 0) break; return (wavelength_nanometers >= WAVELENGTH_NM_GREEN_MIN) Wavelength { const bool { && ::operator+(double nm_value) const Wavelength::Wavelength(void) string.clear(); Wavelength if((start_index_temp = string.findIndexFirstCharNonWhitespace case 4: (start_index_temp )) >= (0)wavelength_nanometers <= WAVELENGTH_NM_GREEN_MAX); { :wavelength_nanometers_(WAVELENGTH_NM_NONE) return appendToStringUserInterface(string); ::isGreaterThan(const Wavelength& other) const{ // 490 < wavelength_in_nm <=} 510, deep blue green return ((INT32)wavelength_nanometers_ + (INT32)nm_value); { } { if(string.isMatchSubThis(start_index_temp , STRING_NM_, r_0_to_1 = false/*0; case_sensitive */)) } // clear(); // if(this != &other) { g_0_to_1 = 1; const bool } const SdString // { start_index_temp += STRING_NM_.getLength (); b_0_to_1 = -(wavelength_in_nmWavelength-510)/(510 -490); const double Wavelength return wavelength_nanometers _ > other.wavelength_nanometers } _; break; ::IsWavelengthVisibleOrange(double wavelength_nanometers) Wavelength ::getAsStringUserInterface(void) const //FILE: Wavelength.hpp Wavelength::Wavelength(double wavelength_nanometers) // } } { ::operator-(const

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    45 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us