如何解决Qt 中的信号/槽向量?
首先介绍一下我为什么要这样做的背景:我有一个类,比如说 MasterClass,它是 QWidget
的子类,它创建多个新的 QObject
派生类对象,比如 SlaveClass,这会在运行时动态发生。使用 QThread
将新的 SlaveClass 移动到新的 movetoThread
,因为它必须进行长时间运行的计算,而且我不希望我的 GUI 冻结。由于 SlaveClass 在不同的线程中,我调用 SlaveClass 中的任何方法的正确方法是使用 Qt 的信号/插槽机制和 Qt::QueuedConnection
。 SlaveClass 有许多信号和插槽,我想将它们连接到我的 MasterClass。我想要做的是在我的 MasterClass 中创建一个 signals 和 slots 的 QVector
,以便我可以动态地添加和删除它,{{1 }} 和 connect
这些到我的 SlaveClass 取决于 SlaveClass 是被创建还是销毁。
为了测试我的理论,我创建了一个 MasterClass 并尝试在其中创建 signals 和 slots 的向量并尝试连接 signals 到 slots 看看它是否有效:
第一次尝试[不起作用]:
大师班.h
disconnect
masterclass.cpp
#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;
};
这给出了 2 个错误:
错误编号。上面 2 是因为我在 #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],&MasterClass::vSlt[1]);
connect(this,&MasterClass::vSig[2],&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";
}
下声明了 QVector<std::function<void(int)>> vSig;
,在 signals:
下声明了 QVector<std::function<void(int)>> vSlt;
。一旦我将上述两个向量移到 private slots:
下,这个错误就会消失。
第二次尝试 [有效,但只是一种]:
大师班.h
private:
masterclass.cpp
.
.
.
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;
};
这有效并打印: 78 69 60
这里有两点需要注意:
- 如果我删除
. . . 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,&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"; }
行,它不会打印任何内容。 - 注意创建
connect(this,&MasterClass::slt_test);
和vSig
向量时参数的变化。从输出中,我可以看到正确的vSlt
被调用,因为它将第二个vSig
函数的参数加 1,并将第三个vSig
函数的参数加 2。但是,它不会将第二个vSig
函数的参数加 10 或第三个vSlt
函数的参数加 20,这让我怀疑它是否调用了正确的vSlt
函数还是只是调用vSlt
函数?
有什么办法可以改进吗?
动态创建 slt_test()
对象时,我必须执行类似的操作才能连接到它的插槽 SlaveClass
。可能吗?
附言我知道我可以使用 connect(MasterClasspointer,&MasterClass::vSig[id],SlaveClasspointer,&SlaveClass::slotName);
函数,但我想尽可能避免使用它。
解决方法
你可以有一个槽向量(一个 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(); });
另一种选择是过滤掉从插槽上带有错误 ID 的呼叫:
int slaveID = /*something*/
connect(masterPtr,[myID = slaveID,slavePtr] (int id) { if (myID == id) slavePtr->slot(); });
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。