我需要整合我的 c++ 代码和 qml。但是我在使用 qmlRegisterType 时遇到了许多错误“未定义对‘Middlemen::staticMetaObject’的引用”

Posted

技术标签:

【中文标题】我需要整合我的 c++ 代码和 qml。但是我在使用 qmlRegisterType 时遇到了许多错误“未定义对‘Middlemen::staticMetaObject’的引用”【英文标题】:I need to Intergate my c++ code and qml. But I get errors "undefined reference to `Middlemen::staticMetaObject'" among many on using qmlRegisterType 【发布时间】:2020-05-18 18:35:03 【问题描述】:

我需要能够从 qml(javascript) 调用我的 c++ 函数。但是在尝试使用qmlRegisterType 将类注册为 qml 类型时,我似乎遇到了错误

我使用 cmake CMakeLists.txt 来构建我的项目。我没有使用 qt-creator。

ma​​in.cpp

#include <iostream>
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "../include/middlemen.hpp"

int main(int argc, char *argv[])

    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qmlRegisterType<Middlemen>("com.ImSteg.Middlemen", 1, 0, "Middlemen");

    QQmlApplicationEngine engine;

    app.setOrganizationName("European University of Lefke");
    app.setOrganizationDomain("http://www.eul.edu.tr/en/");
    app.setApplicationName("ImSteg");

    const QUrl url(QStringLiteral("qrc:/pages/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &obj_url)
        if(!obj && url == obj_url)
            QCoreApplication::exit(-1);
    , Qt::QueuedConnection);

    engine.load(url);

    return app.exec();

middlemen.hpp

#ifndef MIDDLEMEN_HPP
#define MIDDLEMEN_HPP

#include <QObject>
#include <QString>

class Middlemen : public QObject

    Q_OBJECT

    public:
        explicit Middlemen(QObject *parent = 0);
        Q_INVOKABLE QString Embed(QString message, QString password, QString img_path, QString stego_path);
        Q_INVOKABLE QString Extract(QString password, QString img_path);
        ~Middlemen();
;

#endif

middlemen.cpp

#include "../include/middlemen.hpp"
#include "../include/steganography.hpp"

Middlemen::Middlemen(QObject *parent) : QObject(parent)  

QString Middlemen::Embed(QString message, QString password, QString img_path, QString stego_path)
    Steganography steg(message.toStdString(), password.toStdString(), img_path.toStdString(), stego_path.toStdString());
    return QString::fromStdString(steg.Embedding());


QString Middlemen::Extract(QString password, QString img_path)
    Steganography steg(password.toStdString(), img_path.toStdString());
    return QString::fromStdString(steg.Extraction());


Middlemen::~Middlemen() 

CMakeLists.txt

cmake_minimum_required(VERSION 3.16.4)

project(image-steganography)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

find_package(OpenCV REQUIRED)
find_package(Qt5 COMPONENTS Qml Quick REQUIRED)

qt5_add_resources(qml_QRC gui/qml.qrc)

include_directories($OpenCV_INCLUDE_DIRS)
include_directories(include)
include_directories(third_party/sha256/include)

file(GLOB SOURCES "src/*.cpp" "third-party/sha256/src/*.cpp")

add_executable(ImSteg $SOURCES $qml_QRC)

target_link_libraries(ImSteg $OpenCV_LIBS)
target_link_libraries(ImSteg Qt5::Qml Qt5::Quick)

我得到的错误

[ 10%] Automatic MOC and UIC for target ImSteg
[ 10%] Built target ImSteg_autogen
[ 20%] Generating qrc_qml.cpp
Scanning dependencies of target ImSteg
[ 30%] Building CXX object CMakeFiles/ImSteg.dir/ImSteg_autogen/mocs_compilation.cpp.o
[ 40%] Building CXX object CMakeFiles/ImSteg.dir/src/convert.cpp.o
[ 50%] Building CXX object CMakeFiles/ImSteg.dir/src/main.cpp.o
[ 60%] Building CXX object CMakeFiles/ImSteg.dir/src/middlemen.cpp.o
[ 70%] Building CXX object CMakeFiles/ImSteg.dir/src/steganography.cpp.o
[ 80%] Building CXX object CMakeFiles/ImSteg.dir/third-party/sha256/src/sha256.cpp.o
[ 90%] Building CXX object CMakeFiles/ImSteg.dir/qrc_qml.cpp.o
[100%] Linking CXX executable ImSteg
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/main.cpp.o: in function `int qmlRegisterType<Middlemen>(char const*, int, int, char const*)':
main.cpp:(.text._Z15qmlRegisterTypeI9MiddlemenEiPKciiS2_[_Z15qmlRegisterTypeI9MiddlemenEiPKciiS2_]+0x38): undefined reference to `Middlemen::staticMetaObject'
/usr/bin/ld: main.cpp:(.text._Z15qmlRegisterTypeI9MiddlemenEiPKciiS2_[_Z15qmlRegisterTypeI9MiddlemenEiPKciiS2_]+0x1b6): undefined reference to `Middlemen::staticMetaObject'
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/main.cpp.o: in function `QtPrivate::MetaObjectForType<Middlemen*, void>::value()':
main.cpp:(.text._ZN9QtPrivate17MetaObjectForTypeIP9MiddlemenvE5valueEv[_ZN9QtPrivate17MetaObjectForTypeIP9MiddlemenvE5valueEv]+0x7): undefined reference to `Middlemen::staticMetaObject'
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/main.cpp.o: in function `QMetaTypeIdQObject<Middlemen*, 8>::qt_metatype_id()':
main.cpp:(.text._ZN18QMetaTypeIdQObjectIP9MiddlemenLi8EE14qt_metatype_idEv[_ZN18QMetaTypeIdQObjectIP9MiddlemenLi8EE14qt_metatype_idEv]+0x3b): undefined reference to `Middlemen::staticMetaObject'
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/main.cpp.o:(.data.rel.ro._ZTVN11QQmlPrivate11QQmlElementI9MiddlemenEE[_ZTVN11QQmlPrivate11QQmlElementI9MiddlemenEE]+0x10): undefined reference to `Middlemen::metaObject() const'
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/main.cpp.o:(.data.rel.ro._ZTVN11QQmlPrivate11QQmlElementI9MiddlemenEE[_ZTVN11QQmlPrivate11QQmlElementI9MiddlemenEE]+0x18): undefined reference to `Middlemen::qt_metacast(char const*)'
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/main.cpp.o:(.data.rel.ro._ZTVN11QQmlPrivate11QQmlElementI9MiddlemenEE[_ZTVN11QQmlPrivate11QQmlElementI9MiddlemenEE]+0x20): undefined reference to `Middlemen::qt_metacall(QMetaObject::Call, int, void**)'
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/main.cpp.o:(.data.rel.ro._ZTIN11QQmlPrivate11QQmlElementI9MiddlemenEE[_ZTIN11QQmlPrivate11QQmlElementI9MiddlemenEE]+0x10): undefined reference to `typeinfo for Middlemen'
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/middlemen.cpp.o: in function `Middlemen::Middlemen(QObject*)':
middlemen.cpp:(.text+0x26): undefined reference to `vtable for Middlemen'
/usr/bin/ld: CMakeFiles/ImSteg.dir/src/middlemen.cpp.o: in function `Middlemen::~Middlemen()':
middlemen.cpp:(.text+0x3e7): undefined reference to `vtable for Middlemen'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/ImSteg.dir/build.make:264: ImSteg] Error 1
make[1]: *** [CMakeFiles/Makefile2:97: CMakeFiles/ImSteg.dir/all] Error 2
make: *** [Makefile:104: all] Error 2

如何解决此错误。

【问题讨论】:

您是否在构建文件夹中的任何位置找到定义的函数? (很可能在 mocs_compilation.cpp 中)moc'ing 似乎有问题 我最终从 cmake 切换到 qmake,它解决了这个问题。顺便谢谢@Amfasis 您的问题可能是由于通配问题。 CMake 开发人员建议不要这样做。 【参考方案1】:

我最终从 cmake 切换到 qmake。 CMake 可能是最佳选择,但对于 Qt 应用程序,qmake 是最佳选择。

ImSteg.pro

QT += quick qml
CONFIG += c++17
CONFIG += warn_off

TARGET = ImSteg

SOURCES +=  src/main.cpp \
            src/convert.cpp \
            src/steganography.cpp \
            src/middlemen.cpp \
            third-party/sha256/src/sha256.cpp

RESOURCES += gui/qml.qrc

HEADERS +=  include/convert.hpp \
            include/steganography.hpp \
            include/middlemen.hpp \
            third-party/sha256/include/sha256.hpp

unix: CONFIG += link_pkgconfig
unix: PKGCONFIG += opencv4

【讨论】:

【参考方案2】:

从 qml 中读取 C++ 的数据有很多方法,最简单的方法是创建一个信号槽并绑定它。

这是 main.cpp 中的一个示例

//Qmt -> C++ connection
// connect rectangle change coordinate signal coming from qml to memcontrol fun slot
QObject *rootObject = engine.rootObjects().first();
QObject *pageOne = rootObject->findChild<QObject*>("page1box");
QObject::connect(pageOne, SIGNAL(changecoordinate(double,double)),&memctrl,SLOT(fun(double,double)));

在 main.qml 中使用这个

Page1Form 
    //id: page1box
    objectName: "page1box"
    signal changecoordinate(msgx:

阅读此link 了解更多详细信息,其中包含示例和一些讨论

【讨论】:

以上是关于我需要整合我的 c++ 代码和 qml。但是我在使用 qmlRegisterType 时遇到了许多错误“未定义对‘Middlemen::staticMetaObject’的引用”的主要内容,如果未能解决你的问题,请参考以下文章

从 C++ 代码创建单独的 QML 窗口

Qt Quick - 如何仅通过 c++ 代码与 qml 属性交互

如何在 C++ 中获取 QML 方法的源代码?

如何将表模型数据传递给 qml?

在 Qml 代码中编辑 C++ QList<Object*> 模型的问题和一些 Qml 警告

如何将C ++类设置为qml中的Item?