繁体   English   中英

Qt 中的信号/插槽向量?

[英]Vector of Signals/Slots in Qt?

首先是关于我为什么要这样做的一些背景:我有一个 class,比如说MasterClass ,它是QWidget的一个子类,它创建了多个新的QObject派生的 class object,比如SlaveClass在运行时动态发生。 使用moveToThread将新的 SlaveClass 移动到新的QThread ,因为它必须进行长时间运行的计算,并且我不希望我的 GUI 冻结。 由于 SlaveClass 在不同的线程中,我调用 SlaveClass 中的任何方法的正确方法是使用 Qt 的 Signal/Slot 机制以及Qt::QueuedConnection SlaveClass 有许多我想连接到我的 MasterClass 的信号插槽 我要做的是在我的 MasterClass 中创建一个信号插槽QVector ,以便我可以动态地添加和删除它,并根据 SlaveClass 是被创建还是销毁,将它们connectdisconnect到我的 SlaveClass。

为了测试我的理论,我创建了一个MasterClass并尝试在其中创建信号插槽的向量,并尝试将信号连接到插槽以查看它是否有效:

首先尝试[不起作用]:

大师班.h

#include <QWidget>
#include <QVector>
#include <QDebug>
#include <functional>

Class MasterClass : public QWidget
{
    Q_OBJECT

public:
    MasterClass(QWidget *parent = nullptr);
    ~MasterClass();

signals:
    void sig_test(int testID);
    QVector<std::function<void(int)>> vSig;

private slots:
    void slt_test(int testID);
    QVector<std::function<void(int)>> vSlt;
};

大师班.cpp

#include "masterclass.h"

MasterClass::MasterClass(QWidget *parent)
    : QWidget(parent)
{
    vSig << [this](int id) -> void{return this->sig_test(id); };
    vSig << [this](int id) -> void{return this->sig_test(id); };
    vSig << [this](int id) -> void{return this->sig_test(id); };

    vSlt << [this](int id) -> void{return this->slt_test(id); };
    vSlt << [this](int id) -> void{return this->slt_test(id); };
    vSlt << [this](int id) -> void{return this->slt_test(id); };

    connect(this, &MasterClass::vSig[0], this, &MasterClass::vSlt[0]);
    connect(this, &MasterClass::vSig[1], this, &MasterClass::vSlt[1]);
    connect(this, &MasterClass::vSig[2], this, &MasterClass::vSlt[2]);

    emit vSig[0](78);
    emit vSig[1](68);
    emit vSig[2](58);
}

void MasterClass::slt_test(int testID)
{
    qDebug() << "\n" << testID << "\n";
}

这给出了2个错误:

  1. E0304: 没有重载的实例 function "MasterClass::connect" 匹配参数列表
  2. MSB4181:“QtRunWork”任务返回 false,但未记录错误。

错误编号 2 上面是因为我声明QVector<std::function<void(int)>> vSig; signals:QVector<std::function<void(int)>> vSlt; private slots: . 一旦我将上述两个向量移动到private:下,此错误就会消失。

第二次尝试[有效,但只是一种]:

大师班.h

.
.
.

signals:
    void sig_test(int testID);

private slots:
    void slt_test(int testID);

private:
    QVector<std::function<void(int)>> vSig;
    QVector<std::function<void(int)>> vSlt;
};

大师班.cpp

.
.
.
    vSig << [this](int id) -> void{return this->sig_test(id); };
    vSig << [this](int id) -> void{return this->sig_test(id + 1); }; // Notice change in argument
    vSig << [this](int id) -> void{return this->sig_test(id + 2); }; // Notice change in argument

    vSlt << [this](int id) -> void{return this->slt_test(id); };
    vSlt << [this](int id) -> void{return this->slt_test(id + 10); }; // Notice change in argument
    vSlt << [this](int id) -> void{return this->slt_test(id + 20); }; // Notice change in argument

    connect(this, &MasterClass::sig_test, this, &MasterClass::slt_test);

    emit vSig[0](78);
    emit vSig[1](68);
    emit vSig[2](58);
}

void MasterClass::slt_test(int testID)
{
    qDebug() << "\n" << testID << "\n";
}

这工作和打印:78 69 60

这里有两点需要注意:

  1. 如果我删除connect(this, &MasterClass::sig_test, this, &MasterClass::slt_test); 行,它什么也不打印。
  2. 请注意在创建vSigvSlt向量时 arguments 的变化。 从 output 中,我可以看到正在调用正确的vSig ,因为它将第二个vSig function 的参数加 1,并将第三个vSig的参数加 2。 However, it doesn't add 10 to the argument of the second vSlt function or 20 to the argument of the third vSlt function, this makes me wonder if it is calling the correct vSlt function or is it just calling slt_test() function?

有什么办法可以改善吗?

当动态创建SlaveClass对象时,我必须做这样的事情来连接它的插槽connect(MasterClassPointer, &MasterClass::vSig[id], SlaveClassPointer, &SlaveClass::slotName); . 可能吗?

PS我知道我可以使用QMetaObject::invokeMethod() function 但如果可能的话我想避免它。

你可以有一个槽向量(一个 lambda function 可以是一个槽),但你不能真的有一个信号向量。 但是,您可以将信号连接到根据 ID 分配到正确插槽的东西:

// MasterClass.h
class MasterClass : public QObject {
// ... class stuff ...

signals:
  void masterSignal(int id);

private:
std::unordered_map<int, SlaveClass*> m_slaveMap;

}

// MasterClass.cpp ...
connect(this, &MasterClass::masterSignal, slavePtr,
  [](int id) { m_slaveMap[id]->slot(); });

另一种选择是仅过滤掉从属插槽上具有错误 ID 的调用:

int slaveID = /*something*/
connect(masterPtr, &MasterClass::masterSignal, slavePtr,
  [myID = slaveID, slavePtr] (int id) { if (myID == id) slavePtr->slot(); });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM