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 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

                      DiracsbracketD Offline
                      DiracsbracketD 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