首页 > 解决方案 > 在 Qt 中注册自定义 MetaType 的别名类型

问题描述

我的头文件中有一个简单的自定义类型XyztReal及其别名:datamodel.h

#ifndef IMUCONTROLLERDATAMODEL_H
#define IMUCONTROLLERDATAMODEL_H

#include <QMetaType>

namespace imu_controller {
namespace data {

// some code

struct __attribute__((__packed__)) XyztReal {
    qreal x ;
    qreal y ;
    qreal z ;
    qreal ts;
};

typedef XyztReal GyrReal;
typedef XyztReal AccReal;
typedef XyztReal MagReal;

void registerTypes();

}
}

Q_DECLARE_METATYPE(imu_controller::data::XyztReal)

#endif // IMUCONTROLLERDATAMODEL_H

并在源代码中注册功能datamodel.cpp

void registerTypes()
{
    qRegisterMetaType<XyztReal>("XyztReal");   // or qRegisterMetaType<XyztReal>();
    qRegisterMetaType<GyrReal >("GyrReal" );
    qRegisterMetaType<AccReal >("AccReal" );
    qRegisterMetaType<MagReal >("MagReal" );
}

所以我在程序中的适当位置调用此函数并尝试连接不同线程中某些对象的信号/插槽,如下所示:

Qt::ConnectionType ct = static_cast<Qt::ConnectionType>(Qt::BlockingQueuedConnection | Qt::UniqueConnection);
connect(data_ctrl, &imu_controller::DataController::gyrRealReady, this, &MainWindow::someSlot, ct);

其中信号/插槽分别具有imu_controller::data::GyrRealimu_controller::data::XyztReal参数类型,或者:

Qt::ConnectionType ct = static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection);
connect(data_ctrl, &imu_controller::DataController::gyrRealReady, this, &MainWindow::onImuGyrRealReceived, ct);

其中信号/插槽都有imu_controller::data::GyrReal参数类型,但程序不起作用并且调试器打印:

QObject::connect: 不能对“imu_controller::data::GyrReal”类型的参数进行排队(确保使用 qRegisterMetaType() 注册了“imu_controller::data::GyrReal”。)

对于所有XyztReal别名类型。

重要提示: 如果imu_controller::DataController类信号类型更改为XyztReal类型,则程序可以工作!

PS: 我认为类型注册的问题。我阅读了 qt 文档和几个主题,但没有找到解决方案或任何示例。

标签: c++qttypedefqt-signalsqmetatype

解决方案


据我了解,这里的const char * typeName论点qRegisterMetaType是非常必要的。此外,它在命名空间方面也需要一致性。

假设您在DataController课堂上有这个信号:

signals:
    void some_signal(data::AccReal);

由于该类位于imu_controller命名空间中,因此您只需data在参数类名称之前添加命名空间。

现在,在您的registerTypes函数中,它应该像这样注册:

qRegisterMetaType<AccReal >("data::AccReal");

换句话说,typeName字符串必须与写入的信号参数的类型完全匹配。

看起来一个人可以多次注册一个类型,指定不同的类型名,即

qRegisterMetaType<AccReal >("AccReal");
qRegisterMetaType<AccReal >("data::AccReal");
qRegisterMetaType<AccReal >("imu_controller::data::AccReal");

奇怪的是,如果你有一个

using WhatEver = imu_controller::data::AccReal;

某处,然后你可以拥有

signals:
    void some_signal(WhatEver);

只要你有

 qRegisterMetaType<AccReal >("WhatEver");

总结一下,您的注册功能可能如下:

QString aliases[] = {"XyztReal", "GyrReal", "AccReal", "MagReal" };
for(auto a : aliases)
{
    qRegisterMetaType<XyztReal>(a.toLatin1());

    a.prepend("data::");
    qRegisterMetaType<XyztReal>(a.toLatin1());

    a.prepend("imu_controller::");
    qRegisterMetaType<XyztReal>(a.toLatin1());
}

即,您可以注册XyztReal多次,为每个可能的别名和命名空间的每种可能组合注册一次。


推荐阅读