简体   繁体   English

Qt 中的信号/插槽向量?

[英]Vector of Signals/Slots in Qt?

First some background as to why I am trying to do this: I have a class, say MasterClass which is a subclass of QWidget , that creates multiple new QObject derived class object, say SlaveClass , this happens dynamically during runtime.首先是关于我为什么要这样做的一些背景:我有一个 class,比如说MasterClass ,它是QWidget的一个子类,它创建了多个新的QObject派生的 class object,比如SlaveClass在运行时动态发生。 The new SlaveClass is moved to a new QThread by using moveToThread because it has to do long-running computations and I do not want my GUI to freeze.使用moveToThread将新的 SlaveClass 移动到新的QThread ,因为它必须进行长时间运行的计算,并且我不希望我的 GUI 冻结。 Since the SlaveClass is in a different thread, the proper way for me to invoke any method in the SlaveClass is by using Qt's Signal/Slot mechanism along with Qt::QueuedConnection .由于 SlaveClass 在不同的线程中,我调用 SlaveClass 中的任何方法的正确方法是使用 Qt 的 Signal/Slot 机制以及Qt::QueuedConnection The SlaveClass has many signals and slots which I want to connect to my MasterClass. SlaveClass 有许多我想连接到我的 MasterClass 的信号插槽 What I am trying to do is to create a QVector of signals and slots in my MasterClass so that I can add and remove from it dynamically and connect and disconnect these to my SlaveClass depending on if the SlaveClass is being created or destroyed.我要做的是在我的 MasterClass 中创建一个信号插槽QVector ,以便我可以动态地添加和删除它,并根据 SlaveClass 是被创建还是销毁,将它们connectdisconnect到我的 SlaveClass。

To test out my theory I created a MasterClass and tried to create vectors of signals and slots inside it and tried connecting the signals to slots to see if it works:为了测试我的理论,我创建了一个MasterClass并尝试在其中创建信号插槽的向量,并尝试将信号连接到插槽以查看它是否有效:

First try [doesn't work]:首先尝试[不起作用]:

masterclass.h大师班.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;
};

masterclass.cpp大师班.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";
}

This gives 2 errors:这给出了2个错误:

  1. E0304: no instance of overloaded function "MasterClass::connect" matches the argument list E0304: 没有重载的实例 function "MasterClass::connect" 匹配参数列表
  2. MSB4181: The "QtRunWork" task returned false but did not log an error. MSB4181:“QtRunWork”任务返回 false,但未记录错误。

The error no.错误编号2 above is because I am declaring QVector<std::function<void(int)>> vSig; 2 上面是因为我声明QVector<std::function<void(int)>> vSig; under signals: and QVector<std::function<void(int)>> vSlt;signals:QVector<std::function<void(int)>> vSlt; under private slots: .private slots: . This error goes away as soon as I move the above two vectors under private: .一旦我将上述两个向量移动到private:下,此错误就会消失。

Second Try [works, but only kind of]:第二次尝试[有效,但只是一种]:

masterclass.h大师班.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;
};

masterclass.cpp大师班.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";
}

This works and prints: 78 69 60这工作和打印:78 69 60

There are two things to note here:这里有两点需要注意:

  1. If I remove the connect(this, &MasterClass::sig_test, this, &MasterClass::slt_test);如果我删除connect(this, &MasterClass::sig_test, this, &MasterClass::slt_test); line, it prints nothing.行,它什么也不打印。
  2. Notice the change in the arguments when creating the vSig and vSlt vectors.请注意在创建vSigvSlt向量时 arguments 的变化。 From the output, I can see that the correct vSig is being called as it adds 1 to the argument of the second vSig function and adds 2 to the argument of the third vSig function.从 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? 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?

Is there any way I can improve this?有什么办法可以改善吗?

When creating SlaveClass objects dynamically, I would have to do something like this to connect to it's slots connect(MasterClassPointer, &MasterClass::vSig[id], SlaveClassPointer, &SlaveClass::slotName);当动态创建SlaveClass对象时,我必须做这样的事情来连接它的插槽connect(MasterClassPointer, &MasterClass::vSig[id], SlaveClassPointer, &SlaveClass::slotName); . . Is it possible?可能吗?

PS I know I can use QMetaObject::invokeMethod() function but I would like to avoid it if possible. PS我知道我可以使用QMetaObject::invokeMethod() function 但如果可能的话我想避免它。

You can have a vector of slots (a lambda function can be a slot), but you can't really have a vector of signals.你可以有一个槽向量(一个 lambda function 可以是一个槽),但你不能真的有一个信号向量。 However, you can have your signal connected to something that dispatches to the correct slot based on ID:但是,您可以将信号连接到根据 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(); });

The other option is to just filter out calls with the wrong ID on the slave 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