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

Issue: Qt Creator can't find custom C++ QtQuick Components, but compilation still works



  • I'm following the Integrating QML and C++ example in Qt Creator 4.13.3, using Qt version 5.15.2. I followed all the instructions exactly. The app builds and runs correctly.

    However, QT Creator itself somehow isn't aware of the component I added:
    2ef0540d-6556-4258-b82c-ef5dfc606805-image.png
    This is an issue for me.

    Things I Have Tried

    1. Using QML Emulation Layer from selected qt

      53d3dd3e-c03e-49c4-af67-3af5b26d199b-image.png

      Nothing happened except for having to fix this unrelated bug (via user Jaehak Lee's suggestion in the responses).

    2. Cleaning and rebuilding everything.

      No change.

    3. Following this solution from StackOverflow.

      It does not seem to be applicable - it assumes that I have a modules directory under my source directory but I'm not sure why I would have that, nor why I would need to use qmlplugindump directly with Qt 5.15.2.

      However, I did try it regardless, to no avail:

      e45161f6-0000-44b9-a832-823bd996b819-image.png

    Information that might help

    This is how I have tried to set up qmltypes:

    QT += quick bluetooth
    
    CONFIG += c++14
    CONFIG += qmltypes
    QML_IMPORT_NAME = me.tague.myproject
    QML_IMPORT_MAJOR_VERSION = 1
    

    This is the header file for the component I am trying to add:

    #ifndef HOMECONTROLLER_H
    #define HOMECONTROLLER_H
    
    #include <QObject>
    #include <qqml.h>
    #include <QtBluetooth>
    #include "locateddevice.h"
    
    class HomeController : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(LocatedDevice* deviceList READ deviceList NOTIFY deviceListChanged)
        QML_ELEMENT
    
    public:
        explicit HomeController(QObject *parent = nullptr);
        LocatedDevice* deviceList();
    
    private:
        LocatedDevice *m_deviceList;
        QBluetoothDeviceDiscoveryAgent *m_agent;
    
    signals:
        void deviceListChanged();
    };
    
    #endif // HOMECONTROLLER_H
    


  • I've developed a hackish workaround - if you're frustrated by this issue too, this "fix" is ugly but might help in the short-term:

    I noticed that Qt Creator still recognizes the old qmlRegisterType function calls if they're invoked from main in a project. So naturally, I made a custom compiler step for qmake that generates a header file with all QML_ELEMENT-tagged classes registered in a function.

    First, make sure you've set up qmltypes in your project as usual - your QML_IMPORT_NAME and all that is set.

    Add to the bottom of MyProject.pro:

    
    type_registrar_unfucker.name = type_registrar_unfucker
    type_registrar_unfucker.input = TYPE_REGISTRAR_SOURCES
    type_registrar_unfucker.commands = python3 $$PWD/type_unfuck.py ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} $$QML_IMPORT_NAME $$QML_IMPORT_MAJOR_VERSION
    type_registrar_unfucker.output = ${QMAKE_FILE_IN_BASE}.h
    type_registrar_unfucker.clean = ${QMAKE_FILE_IN_BASE}.h
    type_registrar_unfucker.variable_out = HEADERS
    QMAKE_EXTRA_COMPILERS += type_registrar_unfucker
    
    TYPE_REGISTRAR_SOURCES += $$OUT_PWD/myproject_metatypes.json
    

    Add as type_unfuck.py in your source directory:

    # type unfuck
    # -----------
    # This python script deals with the issue of Qt Creator not being able to recognize element types
    # registered using 'QML_ELEMENT'.
    #
    # It does so by generating a header, 'myprojectname_metatypes.h'.
    # Include this header ONLY in main.cpp, and then call `registerTypes()` first thing in `main`.
    # Then, Qt Creator will stop whining.
    
    import sys
    import json
    
    source_path = sys.argv[1]
    dest_path = sys.argv[2]
    import_name = sys.argv[3]
    import_major = sys.argv[4]
    
    with open(source_path) as f:
        data = json.load(f)
    
    
    includes = ["QtQml"]
    types = []
    
    for file in data:
        includes.append(file["inputFile"])
    
        for type in file["classes"]:
            if "classInfos" in type and {"name":"QML.Element","value":"auto"} in type["classInfos"]:
                types.append(type["className"])
    
    with open(dest_path, 'w') as f:
        for i in includes:
            f.write(f'#include <{i}>\n')
    
        f.write('void registerTypes() {\n')
        for t in types:
            f.write(f'\tqmlRegisterType<{t}>("{import_name}", {import_major}, 0, "{t}");\n')
        f.write('}\n')
    

    Then, just add #include <myproject_metatypes.h> to your project's main.cpp and invoke registerTypes(); immediately in your main function. Build your project, then click on Tools -> QML/JS -> Reset Code Model, and Qt Creator should now recognize your custom components correctly.