在我的工作项目中,我遇到了一种特别奇怪的行为。在运行时,当调用 QMetaObject::invokeMethod 时,我得到一个打印,表明程序正在尝试从 QObject 中找到指定的方法,而不是我给它的指针指向的实际类。更奇怪的是,我制作了一个模型,在我看来,它的功能与代码本身的功能大致相同,不同之处在于模型实际上做了预期的事情。我找不到两者之间有意义的差异,也无法弄清楚为什么我的代码无法正常运行。
请原谅所示代码中的一些不良做法。由于与此问题无关的原因,我被迫编辑部分代码,主要是类和库的名称,并且在维护实际代码中的质量方面做得不是很好。这对实际功能没有影响,只有可读性。
我会根据要求提供模型的代码,但这个代码实际上是我遇到问题的代码,所以我觉得添加 g 只会导致不必要的膨胀。
编辑
我是个笨蛋,忘记包含错误消息。请注意,这也与代码库类似地编辑(即类名和一些函数名已更改)
QMetaObject::invokeMethod: No such method QObject::simpleRx(QString,int,client*)
编辑#2 好的,所以问题的根源是主机中缺少 Q_OBJECT 宏。现在我收到一个“QMetaMethod::invoke: Unable to handle unregistered datatype 'int&'”错误,我将在接下来进行研究。
主文件
#include "maincontroller.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MainController mc(argc, argv);
return a.exec();
}
主控制器.h
class MainController : public QObject
{
Q_OBJECT
private:
//attributes
client* comm;
host* host;
bool allOk;
QStringList argList;
int parseArguments(QStringList &arguments, int argc, char *argv[]);
public:
//methods
explicit MainController(int argc, char *argv[], QObject *parent = nullptr);
};
#endif // MAINCONTROLLER_H
主控制器.cpp
#include "client.h"
#include "host.h"
#include <QCoreApplication>
MainController::MainController(int argc, char *argv[], QObject *parent) : QObject(parent)
{
if(true)
{
host=new host();
comm=new client(host, "main", this,0);
//connect(comm, &client::killSignal, this, &MainController::quit);
}
else
{
exit(EXIT_FAILURE);
}
}
客户端.h
#define client_H
#include <QObject>
class QUuid;
class host;
class client : public QObject
{
Q_OBJECT
public:
explicit client(host* givenHost, QString givenId, QObject* givenOwner, int givenPriority, QObject *parent=nullptr);
signals:
void killSignal();
public slots:
private:
//attributes
//pointer to the instance that is using this instance of client
QObject* owner;
QString simpleId; //placeholder attribute until id mess is sorted
host* host;
QHash<QString, const char*>* handlers;
//methods
public:
//attributes
//methods
explicit client(host* givenHost, QString givenId, QObject* givenOwner, int givenPriority, QObject *parent=nullptr);
int simpleTx(QString msg, QString msgName, QString simpleTarget, client* clientPtr=nullptr);
int registerMe(QString threadName);
};
#endif // client_H
客户端.cpp
#include "host.h"
#include "globals.h"
#include<QUuid>
#include <QHash>
#include<QJsonObject>
#include<QJsonDocument>
#include <QMetaObject>
#include<QDebug>
client::client(host* givenHost, QString givenId, QObject* givenOwner, int givenPriority, QObject *parent) : QObject(parent),
host(givenHost),
handlers(new QHash<QString, const char*>),
owner(givenOwner),
simpleId(givenId),
priority(givenPriority)
{
id = new QUuid();
id->createUuid();
registerMe(givenId);
}
//registers this instance of client to host and sets simpleId to threadName
int client::registerMe(QString threadName)
{
QJsonObject payload;
payload.insert(SIMPLEID, threadName);
payload.insert(PRIORITY, priority);
payload.insert(ID, id->toString(QUuid::StringFormat::WithoutBraces));
simpleId = threadName;
simpleTx(JSONtoStr(payload),IPCREGISTRATIONHEADER, HOST, this);
return ALLCLEAR;
}
int client::simpleTx(QString msg, QString msgName, QString SimpleTarget, client* clientPtr)
{
int transmitReturnValue = 420;
QJsonObject payload = StrToJSON(msg);
QString fullMsg = JSONtoStr(JSONify(simpleId, SimpleTarget, msgName, payload));
if(QMetaObject::invokeMethod(host, "simpleRx", Qt::QueuedConnection, Q_ARG(QString, fullMsg), Q_ARG(int, transmitReturnValue), Q_ARG(client*, nullptr)))
{
return ALLCLEAR;
}
else
{
return INVOKEERROR;
}
}
int client::registerHandler(QString msgName, const char* method)
{
handlers->insert(msgName, method);
return ALLCLEAR;
}
int client::getPriority()
{
return priority;
}
QJsonObject client::JSONify(QString src, QString dst, QString msgName, QJsonObject payload)
{
QJsonObject header;
QJsonObject msg;
header.insert(SRC, src);
header.insert(DST, dst);
header.insert(MSGNAME, msgName);
msg.insert(HEADER, header);
msg.insert(PAYLOAD, payload);
return msg;
}
QString client::JSONtoStr(QJsonObject json)
{
QJsonDocument doc(json);
QString msgString(doc.toJson(QJsonDocument::Compact));
return msgString;
}
QJsonObject client::StrToJSON(QString jsonString)
{
QJsonObject obj;
QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8());
// check validity of the document
if(!doc.isNull())
{
if(doc.isObject())
{
obj = doc.object();
}
else
{
qDebug() << "Document is not an object";
}
}
else
{
qDebug() << "Invalid JSON...\n" << jsonString;
}
return obj;
}
主机.h
#define host_H
#include <QObject>
class client;
class host : public QObject
{
signals:
public slots:
private:
//attributes
QHash<QUuid*, client*>* registeredClients;
QHash<QString, client*>* simpleRegisteredClients;
QList<int> priorities;
//methods
int rx(QString jsonString, client* clientPtr);
Q_INVOKABLE void simpleRx(QString jsonString, int &transmitreturnvalue, client* clientPtr=nullptr);
QJsonObject StrToJSON(QString jsonString);
public:
//attributes
//methods
explicit host(QObject *parent = nullptr);
};
#endif // host_H
主机.cpp
#include "clent.h"
#include "globals.h"
#include<QJsonDocument>
#include<QJsonObject>
#include<QDebug>
host::host(QObject *parent) : QObject(parent)
{
}
void host::simpleRx(QString jsonString, int &transmitReturnValue, clent* clientPtr)
{
QString msgName = StrToJSON(jsonString).value(HEADER).toObject().value(MSGNAME).toString();
int rxret = 1;
if(msgName==REGISTRATIONHEADER)
{
QString clientName = StrToJSON(jsonString).value(PAYLOAD).toObject().value(SIMPLEID).toString();
simpleRegisteredClients->insert(clientName, clientPtr);
if(clientPtr->getPriority()!=0)
{
priorities.push_back(clientPtr->getPriority());
}
transmitReturnValue = ALLCLEAR;
}
else if(msgName==ACCEPTDEATH)
{
QString simpleName = StrToJSON(jsonString).value(PAYLOAD).toObject().value(SIMPLEID).toString();
simpleRegisteredClients->remove(simpleName);
}
else if(msgName==KILLMESSAGE && StrToJSON(jsonString).value(HEADER).toObject().value(DST).toString()==ALL)
{
std::sort(priorities.begin(), priorities.end());
QHash<QString, clent*>::iterator i;
while(!priorities.empty())
{
int currentPriority = priorities.takeLast();
for (i = simpleRegisteredClients->begin(); i != simpleRegisteredClients->end(); ++i)
{
if(i.value()->getPriority()==currentPriority)
{
QMetaObject::invokeMethod(i.value(), "rx", Qt::ConnectionType::QueuedConnection,
Q_RETURN_ARG(int, rxret), Q_ARG(QString, jsonString));
}
}
}
QJsonObject finalMsg;
QJsonObject payload;
QJsonObject header;
QString finalJsonString;
header.insert(SRC, HOST);
header.insert(MSGNAME, FINALMESSAGE);
finalMsg.insert(HEADER, header);
finalMsg.insert(PAYLOAD, payload);
for (i = simpleRegisteredClients->begin(); i != simpleRegisteredClients->end(); ++i)
{
if(i.value()->getPriority()==0)
{
QMetaObject::invokeMethod(i.value(), "rx", Qt::ConnectionType::QueuedConnection,
Q_RETURN_ARG(int, rxret), Q_ARG(QString, finalJsonString));
}
}
}
else
{
QString clientName = StrToJSON(jsonString).value(HEADER).toObject().value(DST).toString();
bool invokeSuccesful=false;
invokeSuccesful = QMetaObject::invokeMethod(simpleRegisteredClients->value(clientName), "rx",
Qt::ConnectionType::QueuedConnection, Q_RETURN_ARG(int, rxret), Q_ARG(QString, jsonString));
if(!invokeSuccesful)
{
qDebug() << "Invoke was not succesful";
transmitReturnValue = INVOKEERROR;
}
}
transmitReturnValue = ALLCLEAR;
}
QJsonObject host::StrToJSON(QString jsonString)
{
QJsonObject obj;
QJsonDocument doc = QJsonDocument::fromJson(jsonString.toUtf8());
// check validity of the document
if(!doc.isNull())
{
if(doc.isObject())
{
obj = doc.object();
}
else
{
qDebug() << "Document is not an object";
}
}
else
{
qDebug() << "Invalid JSON...\n" << jsonString;
}
return obj;
}
CMakeLists.txt
project(myProject LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Network REQUIRED)
set(srcPath ${CMAKE_CURRENT_LIST_DIR}/sources)
set(hdrPath ${CMAKE_CURRENT_LIST_DIR}/headers)
set(extLib ${CMAKE_CURRENT_SOURCE_DIR}/../../externals/path_to/so_file)
set(libIncludes ${CMAKE_CURRENT_SOURCE_DIR}/../../externals/path_to/library/source/)
set(fileList
${srcPath}/main.cpp
${srcPath}/client.cpp
${srcPath}/host.cpp
${srcPath}/maincontroller.cpp
${hdrPath}/maincontroller.h
${hdrPath}/globals.h
${hdrPath}/client.h
${hdrPath}/host.h
)
add_executable(myProject
${fileList}
)
set_target_properties(myProject PROPERTIES
AUTOMOC ON
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
VERSION 0.9.0
EXPORT_NAME "myProject"
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/build/archive"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/build/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/build/run"
)
target_include_directories(myProject PRIVATE headers/)
target_include_directories(myProject PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/headers ${libIncludes})
target_link_libraries(myProject PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network ${extLib})
我在 Ubuntu 20.04 上运行 Qt 6.1.0
请询问您需要的任何更多详细信息,如果可以,我会提供。
非常感谢您的帮助。