【问题标题】:QVector<custom class> connection thread cannot queue arguments of typeQVector<custom class> 连接线程不能对类型的参数进行排队
【发布时间】:2016-03-08 12:21:42
【问题描述】:

我有问题。 我有一个自定义类BasicSpace。这个类不是qobject(没有宏)并且不被qobject继承。这是一个简单的类,包含一些数据、qtime 等。 我有:

connect(connector,SIGNAL(finishedReadData(QVector<BasicSpace>&)),&window,SLOT(updateData(QVector<BasicSpace>&)));

我试试

qRegisterMetaType< QVector<BasicSpace> >("QVector<BasicSpace>");

main.cpp.

但是当调用 slot 时 Qt 仍然带我消息:

QObject::connect: 不能对类型为“QVector&”的参数进行排队 (确保使用 qRegisterMetaType() 注册 'QVector&'。)

我的注意力在线程之间。

我的项目是高级的,所以我尽量避免使用不同名称的typedef 解决方案,所以我不测试它。 有人可以帮助我吗?

编辑 THX 弗兰克。我替换了对 QVector 等值的引用,没有 &。这项工作,但我有疑问。它可以工作,但线程连接总是复制数据,所以没有参考数据是双倍复制,第一次在函数中,第二次在线程之间?

我说这已经解决了 50%。我有工作代码,但主要问题 - 队列连接中模板类型的参考值未解决。

【问题讨论】:

  • 不要通过非常量引用,而是通过 const 引用或值。 IE。 finishedReadData(QVector&lt;BasicSpace&gt;).
  • 弗兰克是对的。尽管如此,它对我来说没有问题,就像你尝试它一样。无需注册任何东西。您能否发布您的插槽和信号声明。通常不需要过多考虑信号和槽参数,并且在大多数情况下不需要注册该类型。

标签: c++ multithreading qt metadata slots


【解决方案1】:

当您连接位于同一线程中的信号和对象槽时,将使用Qt::DirectConnection 类型。在这种情况下,插槽作为普通函数调用执行。您不必通过qRegisterMetaType 注册您的数据类型,并且当您将数据作为参考发送时,它不会被复制。

当发送者和接收者对象不在同一个线程中时,使用Qt::QueuedConnection 类型。现在,当您发送一些数据时,它会被复制到事件队列中,无论您是按值发送还是通过引用发送。此外,您的数据类型必须使用qRegisterMetaType 注册。

这是一个说明这种行为的简单示例:

class MyObject
{
public:
    MyObject()
    {
        qDebug() << Q_FUNC_INFO;
    }

    MyObject(const MyObject &other)
    {
        qDebug() << Q_FUNC_INFO;
    }

    ~MyObject()
    {
        qDebug() << Q_FUNC_INFO;
    }

};

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();

signals:
    void myObjectSignal1(const MyObject &obj);
    void myObjectSignal2(const MyObject &obj);

public slots:
    void testDirectConnection();
    void testQueuedConnection();

    void myObjectSlot(const MyObject &obj);

};

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    QHBoxLayout *layout = new QHBoxLayout(this);

    QPushButton *b1 = new QPushButton;
    b1->setText("direct");
    layout->addWidget(b1);
    connect(b1, SIGNAL(clicked()), this, SLOT(testDirectConnection()));

    QPushButton *b2 = new QPushButton;
    b2->setText("queued");
    layout->addWidget(b2);
    connect(b2, SIGNAL(clicked()), this, SLOT(testQueuedConnection()));

    qRegisterMetaType<MyObject>("MyObject");

    connect(this, SIGNAL(myObjectSignal1(MyObject)),
            this, SLOT(myObjectSlot(MyObject)));
    connect(this, SIGNAL(myObjectSignal2(MyObject)),
            this, SLOT(myObjectSlot(MyObject)), Qt::QueuedConnection);
}

Widget::~Widget()
{

}

void Widget::testDirectConnection()
{
    MyObject obj;
    emit myObjectSignal1(obj);
}

void Widget::testQueuedConnection()
{
    MyObject obj;
    emit myObjectSignal2(obj);
}

void Widget::myObjectSlot(const MyObject &obj)
{
}

Qt::DirectConnection 场景:

  1. myObjectSignal1 信号连接到myObjectSlot 使用 Qt::DirectConnection

  2. MyObjectWidget::testDirectConnection 内部创建。

  3. myObjectSignal1 信号触发 myObjectSlot 作为正常的函数调用。

  4. MyObject 通过引用传递到 myObjectSlot
  5. myObjectSlot 执行完成。
  6. MyObject 在控制离开 Widget::testDirectConnection 时被销毁。

输出将是:

MyObject::MyObject() 
MyObject::~MyObject() 

Qt::QueuedConnection 场景:

  1. myObjectSignal2 信号连接到 myObjectSlot 使用 Qt::QueuedConnection
  2. MyObjectWidget::testQueuedConnection 内部创建。

  3. myObjectSignal2 信号触发,MyObject 被复制到事件队列中。

  4. MyObject 在控制离开 Widget::testQueuedConnection 时被销毁。
  5. 控制返回到事件循环并执行myObjectSlot,得到MyObject的副本。
  6. MyObject 的副本在控制权离开 myObjectSlot 时被销毁。

输出将是:

MyObject::MyObject() // object is created inside testQueuedConnection
MyObject::MyObject(const MyObject&) // object is copied
MyObject::~MyObject() // object is destroyed
MyObject::~MyObject() // copy is destroyed

如果您想避免额外的对象复制,您可以使用new 运算符在堆上为您的数据分配内存,然后传递一个指针。但在这种情况下,您必须确保您的对象在处理结束时被销毁。

一篇关于 Qt 信号槽连接中参数复制的好文章:http://www.embeddeduse.com/2013/06/29/copied-or-not-copied-arguments-signals-slots/

【讨论】:

    猜你喜欢
    • 2013-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    相关资源
    最近更新 更多