Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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]



  • 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


  • Qt Champions 2017

    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.



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


Log in to reply