C++ Qt中的信号/插槽向量?

C++ Qt中的信号/插槽向量?,c++,multithreading,qt,signals-slots,C++,Multithreading,Qt,Signals Slots,首先是关于我为什么要这样做的背景:我有一个类,比如说MasterClass,它是QWidget的一个子类,它创建了多个新的QObject派生类对象,比如SlaveClass,这在运行时动态发生。通过使用moveToThread将新的SlaveClass移动到新的QThread,因为它必须执行长时间运行的计算,并且我不希望我的GUI冻结。由于SlaveClass位于不同的线程中,因此我调用SlaveClass中任何方法的正确方法是使用Qt的Signal/Slot机制以及Qt::QueuedConn

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

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

第一次尝试[无效]:

大师班

#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;
};
.
.
.

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;
};
masterclass.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";
}
.
.
.
    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";
}
。
.
.
vSig void{返回此->sig_测试(id);};
vSig void{返回此->sig_测试(id+1);};//注意论点的变化
vSig void{返回此->sig_测试(id+2);};//注意论点的变化
vSlt void{返回此->slt_测试(id);};
vSlt void{返回此->slt_测试(id+10);};//注意论点的变化
vSlt void{返回此->slt_测试(id+20);};//注意论点的变化
连接(此,&MasterClass::sig_测试,此,&MasterClass::slt_测试);
发射vSig[0](78);
发射vSig[1](68);
发射vSig[2](58);
}
void MasterClass::slt_测试(int testID)
{

qDebug()您可以有一个插槽向量(lambda函数可以是插槽),但您不能真正有一个信号向量。但是,您可以将您的信号连接到根据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(); });


我想它显然没有调用你的
vSlt
插槽。为什么会这样?你从来没有将任何东西连接到这些插槽。谢谢,我理解,我也这么认为,但是为什么它要将
vSig
信号连接到
slt\u测试
插槽?我也从来没有这样连接过。只有
sig\u test
连接到
slt\u测试
vSig
只是一个函数向量。这些函数只需调用
sig_test
。由于
sig_test
连接到
slt_test
,调用
vSig
就可以到达
slt_test
@JarMan谢谢,这很有意义:)谢谢!过滤不是一个好主意,因为它会创建数据的副本由于插槽位于不同的线程中,所以将g发送到插槽。我将尝试使用slavemap的第一种方法。
int slaveID = /*something*/
connect(masterPtr, &MasterClass::masterSignal, slavePtr,
  [myID = slaveID, slavePtr] (int id) { if (myID == id) slavePtr->slot(); });