代码之家  ›  专栏  ›  技术社区  ›  Daniel Santos

如何注册类以在Qt中的QWebChannel信号中使用

  •  3
  • Daniel Santos  · 技术社区  · 10 年前

    我使用QT5和WebChannel与HTML页面通信。 我成功地能够交流文字和字符串。不过,我想交流一些积分数据。

    官方文件说

    不需要手动消息传递和数据序列化 http://doc.qt.io/qt-5/qwebchannel.html

    当我尝试发送对象或数组而不是字符串时,应用程序会抛出以下消息:

    不知道如何处理“数据”,请使用qRegisterMetaType注册它。

    如何使用Point类而不是字符串对象发出信号?或者将类序列化为字符串。

    这是我要发送到HTML的对象

    Point类

    class MyData{
    public :
        int x,y,z;
    };
    Q_DECLARE_METATYPE(MyData)
    

    地图类

    class MyMap : public QObject{
    Q_OBJECT
    
    public:
        explicit MyMap ();
    
    signals:
        updateText(const QString &text); // registered
        updateData(MyData &data); //   Don't know how to handle 'data', use qRegisterMetaType to register it.
    
    public slots:
        receiveText(const QString &text);
    };
    

    和主代码

    qRegisterMetaType<MyData>();
    
    // setup the channel
    QWebChannel channel;
    QObject::connect(&clientWrapper, &WebSocketClientWrapper::clientConnected, &channel, &QWebChannel::connectTo);
    
    // setup the dialog and publish it to the QWebChannel
    channel.registerObject(QStringLiteral("map"), &map);
    
    map.updateText("text");
    
    MyData data;
    data.x=10;
    data.y=12;
    data.z=13;
    map.updateData(data);
    
    3 回复  |  直到 10 年前
        1
  •  1
  •   jpo38    10 年前

    Qt documentation :

    要在QVariant中使用类型T,请使用Q_DECLARE_METATYPE() 足够的为了在排队信号和时隙连接中使用类型T, 必须在第一个连接之前调用qRegisterMetaType() 建立。

    在我自己的代码中,我使用 Q_DECLARE_METATYPE 对于要存储在 QVariant (此宏必须放在全局范围内)。而我 qRegisterMetaType<T>() 对于我希望传递给signals/slot的类(必须在建立signal.slot连接之前调用此函数)。如果只使用一个功能,我就不必同时调用这两个功能。

    因此,对于您的示例,这应该起作用:

    qRegisterMetaType<MyData>( "MyData" );
    // then, form here, you can connect `updateData(MyData)` signal to any slot taking a MyData parameter
    

    对于信号/时隙声明:

    • 如果 qRegisterMetaType 未调用,您只能使用信号/插槽传递 MyData 通过引用或指针(声明 signal void updateData(MyData& data); void updateData(MyData* data); ). 然后,如果进行异步连接(如 Qt::QueuedConnection )因为,作为 slot 将在“稍后”执行,您必须确保对象引用在 狭槽 在发出 信号 .
    • 如果 q寄存器元类型 被调用,您可以使用信号/时隙传递 我的数据 通过副本(声明 信号 void updateData(MyData data); ). 当Qt能够序列化对象时,与通过复制传递的对象进行异步连接是安全的(这意味着如果 狭槽 “稍后”执行,它最终将被调用为一个全新的 我的数据 从发出信号的原始对象复制的对象 q寄存器元类型 Qt无法执行此“复制”)。

    确保 我的数据 当您这样做时,声明是已知的(无转发声明)。

    还要注意,并非所有类/结构都可以通过这种方式注册,它们必须具有:

    公共默认构造函数、公共副本构造函数和公共析构函数

    这是你的情况 我的数据 类(默认的是可以的),所以它应该可以顺利地工作。

        2
  •  0
  •   GPPK    10 年前

    您只需在插槽前的某个位置添加一行,如下所示:

    qRegisterMetaType<Block>();
    

    你所做的是告诉元对象编译器(MOC)关于你的类以及如何传递它。可以找到进一步的阅读 here 它更详细地讨论了这个问题,并给出了示例。

        3
  •  0
  •   Serguei Fedorov    10 年前

    您还需要将类型名称的字符串表示形式作为参数传递给函数

    qRegisterMetaType<MyData>("MyData");