Linking error with qmlRegisterType



  • Hi all,

    I am learning exchanging data between qml and C++ class. So I write this simple test program.

    I wrote a simple QML file

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    import QtQuick.Layouts 1.0
    
    //import testing 1.0
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        property string count: "hello"
    
        Rectangle
        {
            width: parent.width
            height: parent.height
            Text {
                id: text
                text: qsTr("text")
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.verticalCenter: parent.verticalCenter
            }
        }
        MouseArea
        {
            anchors.fill: parent
            onClicked:
            {
                console.log("count " + count)
            }
        }
    }
    

    and simple main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "updatecounter.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
    //    qmlRegisterType<UpdateCounter>("testing", 1, 0, "UpdateCounter");
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    
        return app.exec();
    }
    

    Everything is fine up to here. Then I added my C++ class

    #ifndef UPDATECOUNTER_H
    #define UPDATECOUNTER_H
    
    #include <QObject>
    
    class UpdateCounter : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(QString counter READ counter WRITE setCounter NOTIFY counterChanged)
    public:
        explicit UpdateCounter(QObject *parent = 0);
    
        QString counter() const {return mcounter;}
        void setCounter(const QString &counter);
        Q_INVOKABLE void sendCounterUpdate(const QString &counter);
    
    signals:
        void counterChanged();
    
    private:
        QString mcounter;
    };
    
    #endif // UPDATECOUNTER_H
    
    #include "updatecounter.h"
    
    UpdateCounter::UpdateCounter(QObject *parent) : QObject(parent)
    {
    
    }
    
    void UpdateCounter::setCounter(const QString &counter)
    {
        if(counter == mcounter)
            return;
        mcounter = counter;
    }
    
    void UpdateCounter::sendCounterUpdate(const QString &counter)
    {
        if(counter == mcounter)
            return;
        mcounter = counter;
        emit counterChanged();
    }
    

    The program behaves as expected. Then I register my class using qmlRegisterType. I get linking errors.

    main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __cdecl UpdateCounter::metaObject(void)const " (?metaObject@UpdateCounter@@UEBAPEBUQMetaObject@@XZ)
    main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual void * __cdecl UpdateCounter::qt_metacast(char const *)" (?qt_metacast@UpdateCounter@@UEAAPEAXPEBD@Z)
    main.obj:-1: error: LNK2001: unresolved external symbol "public: virtual int __cdecl UpdateCounter::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@UpdateCounter@@UEAAHW4Call@QMetaObject@@HPEAPEAX@Z)
    main.obj:-1: error: LNK2019: unresolved external symbol "public: __cdecl UpdateCounter::UpdateCounter(class QObject *)" (??0UpdateCounter@@QEAA@PEAVQObject@@@Z) referenced in function "public: __cdecl QQmlPrivate::QQmlElement<class UpdateCounter>::QQmlElement<class UpdateCounter>(void)" (??0?$QQmlElement@VUpdateCounter@@@QQmlPrivate@@QEAA@XZ)
    main.obj:-1: error: LNK2001: unresolved external symbol "public: static struct QMetaObject const UpdateCounter::staticMetaObject" (?staticMetaObject@UpdateCounter@@2UQMetaObject@@B)
    

    Please let me know what I did wrong.

    Thank you,
    Anthony

    [Added code tags ~kshegunov]


  • Moderators

    Hi! Try "clean project", "run qmake" and then rebuild the project.



  • Thank you. I have to remember to do that all the time.

    Now I have a different error. I have
    declared setCounter in the .h file
    Q_PROPERTY(QString counter READ counter WRITE setCounter NOTIFY counterChanged)
    void setCounter(const QString &counter);

    implemented the code in the cpp file
    void UpdateCounter::setCounter(const QString &counter)
    {
    if(counter == mcounter)
    return;
    mcounter = counter;
    }
    registered the class in main.cpp
    qmlRegisterType<UpdateCounter>("testing", 1, 0, "UpdateCounter");

    imported the class and assigned an object in qml
    import testing 1.0
    UpdateCounter{id: updateCounter}

    But when I call the function I get this error at run time.
    updateCounter.setCounter(count)
    qrc:/main.qml:33: TypeError: Property 'setCounter' of object [object Object] is not a function

    How can I make setCounter visible?

    Thanks,
    Anthony



  • setCounter cannot be called directly. Either make the setCounter(..) function as Q_INVOKABLE or move the function under slot. It will be called. Looking at your code you idea is to set the value of counter. Since counter is exposed via Q_PROPERTY directly set it like updateCounter.counter = 10. Now setCounter function will be called automatically.



  • Thank you for your advices. It works now. I achieved what I want to do. Here is the code for anyone interested.

    H file
    class UpdateCounter : public QObject
    {
    Q_OBJECT
    Q_PROPERTY(double counter READ counter WRITE setCounter NOTIFY counterChanged)
    public:
    double counter() const {return mcounter;}
    void setCounter(const double);

    Q_INVOKABLE void resetCounter(const double);
    

    signals:
    void counterChanged();

    private:
    double mcounter;
    };

    CPP file
    void UpdateCounter::setCounter(const double counter)
    {
    if(counter == mcounter)
    return;
    qDebug() << "UpdateCounter.setCounter" << counter;
    mcounter = counter + 2;
    emit counterChanged();
    }

    void UpdateCounter::resetCounter(const double counter)
    {
    if(counter == mcounter)
    return;
    qDebug() << "UpdateCounter.resetCounter" << counter;
    mcounter = counter;
    emit counterChanged();
    }

    int main(int argc, char *argv[])
    {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    qmlRegisterType<UpdateCounter>("testing", 1, 0, "UpdateCounter");
    
    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    
    return app.exec();
    

    }

    and qml file
    import testing 1.0

    ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    property double count: 0
    UpdateCounter
    {
        id: updateCounter
        onCounterChanged:
        {
            count = counter;
            console.log("QML UpdateCounter " + count)
            text.text = qsTr("Counter %1").arg(count)
        }
    }
    
    Rectangle
    {
        width: parent.width
        height: parent.height/2
        color: "red"
        Text
        {
            text: qsTr("Reset")
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.verticalCenter: parent.verticalCenter
        }
        MouseArea
        {
            anchors.fill: parent
            onClicked:
            {
                console.log("QML reset to 10 " + count)
                updateCounter.resetCounter(10)
            }
        }
    }
    Rectangle
    {
        y: parent.height/2
        width: parent.width
        height: parent.height/2
        color: "yellow"
        Text
        {
            id: text
            text: qsTr("text")
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.verticalCenter: parent.verticalCenter
        }
        MouseArea
        {
            anchors.fill: parent
            onClicked:
            {
                console.log("QML count " + count)
                count = count + 1
                updateCounter.counter = count
            }
        }
    }
    

    }

    now how do I mark this topic as solved?


  • Lifetime Qt Champion

    HI,

    Use the "Topic Tools" button.


  • Moderators

    @att_ The Hitchhiker's Visual Guide to the Qt Forum explains how to mark threads as solved.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.