Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. [QML / C++] Exposing Pointer Type attribute to QML
Forum Updated to NodeBB v4.3 + New Features

[QML / C++] Exposing Pointer Type attribute to QML

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
12 Posts 6 Posters 3.4k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    nico88desmo
    wrote on 21 Apr 2020, 12:35 last edited by
    #1

    Dear All,

    as written in the title I have some doubts on exposing a C++ pointer object to QML.
    What I need is making a pointer object (so no instantiable) to QML ( in details, I expose an instance of an AbstractItemModel's subclass).
    From QML doc (https://doc.qt.io/qt-5/qtqml-cppintegration-overview.html#choosing-the-correct-integration-method-between-c-and-qml), I try to use qmlRegisterType() without success.

    However from the an old Qt post (https://www.qtcentre.org/threads/14835-How-to-use-Q_DECLARE_METATYPE?p=76295#post76295), it suggests to use this declaration:

    qRegisterMetaType<Type*>("Type*");
    

    And in this way it seems working.
    My question is: why do I need to use this function?
    I know that it is needed for signal/slot connections, but for QML I don't find any indication to use it

    Thanks,
    Nicola

    S D 2 Replies Last reply 22 Apr 2020, 05:58
    1
    • N nico88desmo
      21 Apr 2020, 12:35

      Dear All,

      as written in the title I have some doubts on exposing a C++ pointer object to QML.
      What I need is making a pointer object (so no instantiable) to QML ( in details, I expose an instance of an AbstractItemModel's subclass).
      From QML doc (https://doc.qt.io/qt-5/qtqml-cppintegration-overview.html#choosing-the-correct-integration-method-between-c-and-qml), I try to use qmlRegisterType() without success.

      However from the an old Qt post (https://www.qtcentre.org/threads/14835-How-to-use-Q_DECLARE_METATYPE?p=76295#post76295), it suggests to use this declaration:

      qRegisterMetaType<Type*>("Type*");
      

      And in this way it seems working.
      My question is: why do I need to use this function?
      I know that it is needed for signal/slot connections, but for QML I don't find any indication to use it

      Thanks,
      Nicola

      S Offline
      S Offline
      sierdzio
      Moderators
      wrote on 22 Apr 2020, 05:58 last edited by
      #2

      @nico88desmo said in [QML / C++] Exposing Pointer Type attribute to QML:

      I try to use qmlRegisterType() without success.

      What are the symptoms of failure? Any warnings or errors?

      From your description I'd say you rather need qRegisterUncreatableType(). But qmlRegisterType() should work fine, too.

      qRegisterMetaType<Type*>("Type*");

      There is no need to register types for subclasses of QObject, you should not need to use it.

      (Z(:^

      1 Reply Last reply
      0
      • N Offline
        N Offline
        nico88desmo
        wrote on 22 Apr 2020, 08:32 last edited by nico88desmo
        #3

        Here are more code details (I write only necessary parts of code...)

        The failure appears during runtime and is:
        QMetaProperty::read: Unable to handle unregistered datatype 'MenuModel*' for property 'dv::life::SettingsDialogCtrl::menuModel'

        MenuModel is the follow:

        class MenuModel : public QAbstractListModel {
            Q_OBJECT
            ...
        }
        

        used inside QML using the code:

        ListView {
           ...
           model: SettingsDialogCtrl.menuModel
           ...
        

        and finally SettingsDialogCtrl is a "Controller" class that handle events from UI; it is declare in this way:

        class SettingsDialogCtrl : public BaseController {
           Q_OBJECT
           Q_PROPERTY(MenuModel* menuModel READ getMenuModel)
        
        private:
           SettingsDialogCtrlP* dPtr; // PIMPL idiom
        public:
           MenuModel* getMenuModel() {
              return dPtr->menuModel.data();
           }
        
        public slots:
           void testAdd();
           ...
        };
        

        I can't use qmlRegisterUncreatableType because I don't need to access to the object using a qmlName, instead I need to use it in qml as property of SettingsDialogCtrl, which is a singleton declare using qmlRegisterSingletonType<SettingsDialogCtrl>

        For this I think using anonymous qml type declaration,
        Qt5.12 qmlRegisterType<Type>()
        Qt5.14 qmlRegisterAnonymousType<Type>(const char *uri, int versionMajor)

        But it seems not working for pointer (even if my case is similar to example https://doc.qt.io/qt-5.12/qqmlengine.html#qmlRegisterType)

        1 Reply Last reply
        1
        • N Offline
          N Offline
          nico88desmo
          wrote on 22 Apr 2020, 08:53 last edited by
          #4

          I found also this reply of an 3-years ago answer:

          https://www.qtcentre.org/threads/68270-C-pointer-to-Qml-is-this-possible-!?p=299124#post299124

          where it's indicated to register the type using qRegisterMetaType<Type*>("Type *")
          because the type (pointer type) should be understandable to QVariant (why??)

          Is there any implicit conversion?
          But I don't find any information at this link https://doc.qt.io/qt-5.12/qtqml-cppintegration-data.html

          Looks like I'm losing some information on why I should use qRegisterMetaType...

          E 1 Reply Last reply 22 Apr 2020, 09:55
          1
          • N nico88desmo
            22 Apr 2020, 08:53

            I found also this reply of an 3-years ago answer:

            https://www.qtcentre.org/threads/68270-C-pointer-to-Qml-is-this-possible-!?p=299124#post299124

            where it's indicated to register the type using qRegisterMetaType<Type*>("Type *")
            because the type (pointer type) should be understandable to QVariant (why??)

            Is there any implicit conversion?
            But I don't find any information at this link https://doc.qt.io/qt-5.12/qtqml-cppintegration-data.html

            Looks like I'm losing some information on why I should use qRegisterMetaType...

            E Offline
            E Offline
            ekkescorner
            Qt Champions 2016
            wrote on 22 Apr 2020, 09:55 last edited by
            #5

            @nico88desmo I'm exposing all my (QObject*) Entities and dtos in this way:

            qmlRegisterType<Person>("org.ekkescorner.data", 1, 0, "Person");
            

            then in QML

            import org.ekkescorner.data 1.0
            

            now QML "knows" my Objects and I can easy access the properties or use it as parameters in Q_INVOKABLE methods
            here's a snippet from my Person Class:

            ...
            #include <QObject>
            ...
            class Person: public QObject
            {
            	Q_OBJECT
            	Q_PROPERTY(QString uuid READ uuid WRITE setUuid NOTIFY uuidChanged FINAL)
            	Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
            	Q_PROPERTY(QString phone READ phone WRITE setPhone NOTIFY phoneChanged FINAL)
            ...
            public:
            	Person(QObject *parent = nullptr);
            ...
            

            never had a problem with qmlRegisterType

            ekke ... Qt Champion 2016 | 2024 ... mobile business apps
            5.15 --> 6.8 https://t1p.de/ekkeChecklist
            QMake --> CMake https://t1p.de/ekkeCMakeMobileApps

            N 1 Reply Last reply 22 Apr 2020, 12:54
            1
            • S Offline
              S Offline
              sierdzio
              Moderators
              wrote on 22 Apr 2020, 11:39 last edited by
              #6

              @nico88desmo said in [QML / C++] Exposing Pointer Type attribute to QML:

              qRegisterMetaType<Type*>("Type *")

              There is no need to provide anything in the round brackets () in most cases. Remove the string and try. Anyway, like Ekke and me said - there is no need to call it at all.

              because the type (pointer type) should be understandable to QVariant (why??)

              You return a pointer in the property, so Qt Meta Object system needs to know about it. But Q_OBJECT macro handles this automatically.

              Is there any implicit conversion?

              Yes, all communication between C++ and QML is based on QVariants.

              But it seems not working for pointer (even if my case is similar to example

              You are calling the qmlRegister* methods before instantiating the QML engine, right? You should.

              (Z(:^

              1 Reply Last reply
              1
              • E ekkescorner
                22 Apr 2020, 09:55

                @nico88desmo I'm exposing all my (QObject*) Entities and dtos in this way:

                qmlRegisterType<Person>("org.ekkescorner.data", 1, 0, "Person");
                

                then in QML

                import org.ekkescorner.data 1.0
                

                now QML "knows" my Objects and I can easy access the properties or use it as parameters in Q_INVOKABLE methods
                here's a snippet from my Person Class:

                ...
                #include <QObject>
                ...
                class Person: public QObject
                {
                	Q_OBJECT
                	Q_PROPERTY(QString uuid READ uuid WRITE setUuid NOTIFY uuidChanged FINAL)
                	Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
                	Q_PROPERTY(QString phone READ phone WRITE setPhone NOTIFY phoneChanged FINAL)
                ...
                public:
                	Person(QObject *parent = nullptr);
                ...
                

                never had a problem with qmlRegisterType

                N Offline
                N Offline
                nico88desmo
                wrote on 22 Apr 2020, 12:54 last edited by
                #7

                Thanks both for the support, I'm going to answer to each one:

                @ekkescorner said in [QML / C++] Exposing Pointer Type attribute to QML:

                @nico88desmo I'm exposing all my (QObject*) Entities and dtos in this way:
                ...
                cut
                ...
                never had a problem with qmlRegisterType

                This solution works me too for other objects, but if you declare:

                qmlRegisterType<Person>("org.ekkescorner.data", 1, 0, "Person");
                

                your're telling to QML Engine that this type is instantable from QML; in my case, I don't want QML is able to create any instance of it.
                For this I declare:

                qmlRegisterType<MenuModel>();
                

                as documented here: This template function registers the C++ type in the QML system. Instances of this type cannot be created from the QML system

                @sierdzio said in [QML / C++] Exposing Pointer Type attribute to QML:

                @nico88desmo said in [QML / C++] Exposing Pointer Type attribute to QML:

                qRegisterMetaType<Type*>("Type *")

                There is no need to provide anything in the round brackets () in most cases. Remove the string and try. Anyway, like Ekke and me said - there is no need to call it at all.

                because the type (pointer type) should be understandable to QVariant (why??)

                I try removing it, but without the string "MenuModel*", QML ListView isn't working.
                It works only in this case int qmlTypeId = qRegisterMetaType<namespace::MenuModel*>("MenuModel*");

                You return a pointer in the property, so Qt Meta Object system needs to know about it. But Q_OBJECT macro handles this automatically.

                Is there any implicit conversion?

                Yes, all communication between C++ and QML is based on QVariants.

                Good to know this.

                But it seems not working for pointer (even if my case is similar to example

                You are calling the qmlRegister* methods before instantiating the QML engine, right? You should.

                Yes, before starting program, I call the necessary functions to allow QML to see C++ objects.
                The others one work correctly, the only small problem is with MenuModel * class.

                E 1 Reply Last reply 22 Apr 2020, 15:34
                1
                • N nico88desmo
                  22 Apr 2020, 12:54

                  Thanks both for the support, I'm going to answer to each one:

                  @ekkescorner said in [QML / C++] Exposing Pointer Type attribute to QML:

                  @nico88desmo I'm exposing all my (QObject*) Entities and dtos in this way:
                  ...
                  cut
                  ...
                  never had a problem with qmlRegisterType

                  This solution works me too for other objects, but if you declare:

                  qmlRegisterType<Person>("org.ekkescorner.data", 1, 0, "Person");
                  

                  your're telling to QML Engine that this type is instantable from QML; in my case, I don't want QML is able to create any instance of it.
                  For this I declare:

                  qmlRegisterType<MenuModel>();
                  

                  as documented here: This template function registers the C++ type in the QML system. Instances of this type cannot be created from the QML system

                  @sierdzio said in [QML / C++] Exposing Pointer Type attribute to QML:

                  @nico88desmo said in [QML / C++] Exposing Pointer Type attribute to QML:

                  qRegisterMetaType<Type*>("Type *")

                  There is no need to provide anything in the round brackets () in most cases. Remove the string and try. Anyway, like Ekke and me said - there is no need to call it at all.

                  because the type (pointer type) should be understandable to QVariant (why??)

                  I try removing it, but without the string "MenuModel*", QML ListView isn't working.
                  It works only in this case int qmlTypeId = qRegisterMetaType<namespace::MenuModel*>("MenuModel*");

                  You return a pointer in the property, so Qt Meta Object system needs to know about it. But Q_OBJECT macro handles this automatically.

                  Is there any implicit conversion?

                  Yes, all communication between C++ and QML is based on QVariants.

                  Good to know this.

                  But it seems not working for pointer (even if my case is similar to example

                  You are calling the qmlRegister* methods before instantiating the QML engine, right? You should.

                  Yes, before starting program, I call the necessary functions to allow QML to see C++ objects.
                  The others one work correctly, the only small problem is with MenuModel * class.

                  E Offline
                  E Offline
                  ekkescorner
                  Qt Champions 2016
                  wrote on 22 Apr 2020, 15:34 last edited by
                  #8

                  @nico88desmo said in [QML / C++] Exposing Pointer Type attribute to QML:

                  your're telling to QML Engine that this type is instantable from QML; in my case, I don't want QML is able to create any instance of it.

                  ah - understand
                  BTW: in my projects I never create QObject* from QML, always a C++ class is parent and manages lifecycle - but this is only a project-rule and not something I'm telling the QML engine as you want to do

                  ekke ... Qt Champion 2016 | 2024 ... mobile business apps
                  5.15 --> 6.8 https://t1p.de/ekkeChecklist
                  QMake --> CMake https://t1p.de/ekkeCMakeMobileApps

                  N 1 Reply Last reply 22 Apr 2020, 20:13
                  0
                  • E ekkescorner
                    22 Apr 2020, 15:34

                    @nico88desmo said in [QML / C++] Exposing Pointer Type attribute to QML:

                    your're telling to QML Engine that this type is instantable from QML; in my case, I don't want QML is able to create any instance of it.

                    ah - understand
                    BTW: in my projects I never create QObject* from QML, always a C++ class is parent and manages lifecycle - but this is only a project-rule and not something I'm telling the QML engine as you want to do

                    N Offline
                    N Offline
                    nico88desmo
                    wrote on 22 Apr 2020, 20:13 last edited by
                    #9

                    @ekkescorner said in [QML / C++] Exposing Pointer Type attribute to QML:

                    ah - understand
                    BTW: in my projects I never create QObject* from QML, always a C++ class is parent and manages lifecycle - but this is only a project-rule and not something I'm telling the QML engine as you want to do

                    This is the same policy I have with my current project; in any case, since QML Engine give the possibility to prevent instantiation of some object, I was investigating on why in this case everything works iff I register my type using qRegisterMetatype<Type*>("Type*")

                    I'm quite new on QML architecture, that's why I'm trying to go deeper to understand better how it works ;)

                    1 Reply Last reply
                    0
                    • D Offline
                      D Offline
                      DeltaSim
                      wrote on 23 Apr 2020, 15:13 last edited by DeltaSim
                      #10

                      Hi,

                      You can try to use setContextProperty("QML_POINTER_NAME",pointer);

                      For example:

                      C++:
                      MyClass * myPointer;
                      QQuickView view;
                      view.engine()->rootContext()->setContextProperty("myPointerInQML",myPointer);
                      
                      QML:
                      myPointerInQML.myMethodOrProperty();
                      
                      P 1 Reply Last reply 16 May 2021, 04:54
                      0
                      • D DeltaSim
                        23 Apr 2020, 15:13

                        Hi,

                        You can try to use setContextProperty("QML_POINTER_NAME",pointer);

                        For example:

                        C++:
                        MyClass * myPointer;
                        QQuickView view;
                        view.engine()->rootContext()->setContextProperty("myPointerInQML",myPointer);
                        
                        QML:
                        myPointerInQML.myMethodOrProperty();
                        
                        P Offline
                        P Offline
                        Puya
                        wrote on 16 May 2021, 04:54 last edited by
                        #11

                        there is no need to call it at all.

                        @sierdzio @ekkescorner I can confirm @nico88desmo 's observation that it is indeed needed to register the pointer type with qRegisterMetaType or you would receive the error they mentioned:

                        QMetaProperty::read: Unable to handle unregistered datatype ... for property ...

                        And trying to register the pointer type results in a compiler error:

                        error: type ... cannot be used prior to '::' because it has no members

                        To reproduce register a type as a singleton. Then have a property that is a pointer type or an invokable that returns a pointer. (therefore the pointer is passed to QML not the object type itself) Then try registering with either of the methods you propose. Only option that seems to work is using qRegisterMetaType.

                        1 Reply Last reply
                        0
                        • N nico88desmo
                          21 Apr 2020, 12:35

                          Dear All,

                          as written in the title I have some doubts on exposing a C++ pointer object to QML.
                          What I need is making a pointer object (so no instantiable) to QML ( in details, I expose an instance of an AbstractItemModel's subclass).
                          From QML doc (https://doc.qt.io/qt-5/qtqml-cppintegration-overview.html#choosing-the-correct-integration-method-between-c-and-qml), I try to use qmlRegisterType() without success.

                          However from the an old Qt post (https://www.qtcentre.org/threads/14835-How-to-use-Q_DECLARE_METATYPE?p=76295#post76295), it suggests to use this declaration:

                          qRegisterMetaType<Type*>("Type*");
                          

                          And in this way it seems working.
                          My question is: why do I need to use this function?
                          I know that it is needed for signal/slot connections, but for QML I don't find any indication to use it

                          Thanks,
                          Nicola

                          D Offline
                          D Offline
                          Diracsbracket
                          wrote on 18 May 2021, 16:03 last edited by
                          #12

                          Hi @nico88desmo
                          I am using exactly the same pattern as you:

                          I have a Qml Singleton type registered as:

                          qmlRegisterSingletonType<QmlInterface>(UM_URI_DOMAIN, 1, 0, "UMP", &QmlInterface::singletonProvider);
                          

                          and in there, a property declared as follows:

                          Q_PROPERTY(UmFolderListModel* file_model READ file_model CONSTANT)
                          

                          The only other registration that is required is:

                          qmlRegisterUncreatableType<UmFolderListModel>(UM_URI_DOMAIN, 1, 0, "UmFolderListModel", UM_UNCREATABLE_REASON);
                          

                          And I use it as follows in QML:

                          property UmFolderListModel fileModel: UMP.file_model
                          

                          As stated above, the qmlRegisterUncreatableType registration is needed in my case.

                          1 Reply Last reply
                          1

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved