Unable to make qmlRegisterType work

2020-05-24 19:50发布

问题:

I've found some examples of qmlRegisterType on the internet but just can't make it work. I create a new Qt Quick 2 project and add the following contents:

This is my .pro file:

#Add more folders to ship with the application, here
folder_01.source = qml/testlib
folder_01.target = qml
DEPLOYMENTFOLDERS = folder_01

#Libraries
QT += core gui widgets

#Additional import path used to resolve QML modules in Creator's code model
QML_IMPORT_PATH =

#Header files
HEADERS += main.hpp

#The .cpp file which was generated for your project. Feel free to hack it.
SOURCES += main.cpp

#Installation path
#target.path =

#Please do not modify the following two lines. Required for deployment.
include(qtquick2applicationviewer/qtquick2applicationviewer.pri)
qtcAddDeployment()

This is my code file (main.cpp):

#include <QtQml>
#include <QtWidgets/QApplication>
#include "qtquick2applicationviewer.h"

//test class
class TestClass:public QObject {
  Q_OBJECT

  public:
    TestClass(QObject* parent=0):QObject(parent){}

  public slots:
    void test() {
      qDebug("test!");
    }
};

//entry point
int main(int argc, char *argv[]) {

  //create application
  QApplication app(argc, argv);

  //register custom qml component
  qmlRegisterType<TestClass>("testlib",1,0,"TestClass");

  //create and show qml viewer
  QtQuick2ApplicationViewer viewer;
  viewer.setMainQmlFile(QStringLiteral("qml/testlib/main.qml"));
  viewer.showExpanded();

  //back to OS
  return app.exec();
}

This is my QML file (main.qml):

import QtQuick 2.0
import testlib 1.0

Rectangle {

  TestClass {
    id:testobj
  }

  Component.onCompleted: {
    testobj.test();
  }
}

But I face multiple linking errors:

  • undefined reference to `vtable for TestClass'
  • undefined reference to `TestClass::staticMetaObject'
  • undefined reference to `TestClass::metaObject() const'
  • undefined reference to `TestClass::qt_metacast(char const*)'
  • undefined reference to `TestClass::qt_metacall(QMetaObject::Call, int, void**)'

I'm using Qt 5.2.1 shipped with MinGW 4.8 stable. These errors mean the linker can not find library files which contain method implementations (stated above). What happened? May be fail to compile on Qt 5 but ok on Qt 4?

回答1:

Notes about compilation with Qt:

(1) Use 'QT +=' in .pro file for Qt headers & Qt libraries

(2) Use 'HEADERS +=' and 'SOURCES +=' in .pro file for 
project level headers and source codes

Notes about creating a custom QML component (herefrom called 'CustomCom'):

(1) Inherit publically 'CustomCom' from QQuickItem: 

class CustomCom:public QQuickItem {}

(2) Put the Q_OBJECT macro right after first line of 
class 'CustomCom' declaration.

(3) Inherit the constructor:

public: CustomCom(QQuickItem* parent=0):QQuickItem(parent){}

(4) Put the methods to be called by JS after "public slots:"

(5) Call 'qmlRegisterType' after creation of 'QApplication' and
before creating any QML view or viewer.

(6) IMPORTANT: If you fail to compile with error 
'undefined reference to vtable...", just put the code of 'CustomCom.cpp'
nested inside the 'CustomCom.hpp' file, and put the whole code 
of the class 'CustomCom.hpp' in the main header file because of
something wrong in header referencing. 

Example header code:

[main.hpp]
class CustomCom:public QQuickItem {
  Q_OBJECT

  public:
    CustomCom(QQuickItem* parent=0):QQuickItem(parent){}

  public slots:
    void test() {
      qDebug("Test!");
    }
};

Example source code:

[main.cpp]
int main(int argc,char** args) {
  QApplication* app = new QApplication(argc,args);

  //call before any qml may use the custom component
  qmlRegisterType<CustomCom>("CustomLib",1,0,"CustomCom");

  //class 'QtQuick2ApplicationViewer' is generated by Qt Creator
  //when creating new Quick 2 project. The path to 'main.qml'
  //may be different
  QtQuick2ApplicationViewer* viewer = new QtQuick2ApplicationViewer();
  viewer->setMainQmlFile("qml/project/main.qml");
  viewer->showExpanded();
}

Example QML:

[main.qml]
import QtQuick 2.0
import CustomLib 1.0

Rectangle {
  width:640; height:360;

  CustomCom {
    id:customcom;
  }

  Component.onCompleted: {
    customcom.test();
  }
}

Solution to the question (facing 'Undefined reference to vtable'):

  • Combine 'TestClass.hpp' & 'TestClass.cpp' into 'TestClass.hpp' file
  • Move the content of 'TestClass.hpp' to 'main.hpp'

The problem was caused by using master header file. Putting the #include(s) only when needed solves the problem.



回答2:

First you don't call parent contructor

TestClass::TestClass():QObject(0) {
}

or better

TestClass::TestClass(QObject* parent=0): 
  QObject (parent) {    
}

Second where are you calling the qmlRegister? If am I right you need to register type before you use it, so before QQmlEngine load source codes of qml file.



回答3:

I got the same problem and got it resolved by just add the header file (TestClass.hpp in your case) into the .pro file like this:

HEADERS += TestClass.hpp

It will guarantee moc will find it. And by the way, .h files are also OK.



标签: c++ qt mingw qml qt5