QObject::sender()
我们如何在槽函数中获取到信号的发送对象呢,使用sender()方法即可获取。但是使用此方法我们需要注意几点:
QObject *QObject::sender() const
1、使用sender()方法获取信号的发送对象,前提是槽函数是被信号触发的,而非自己调用,否则返回空(nullptr),所以我们在使用的时候最好加个非空判断;
2、通过此方法获取的对象指针仅在槽函数执行的期间有效;
3、如果在此期间,信号发送对象被销毁,或者信号与槽函数已经断开,此对象指针将无效;
4、此方法虽然违背了面向对象的模块化原则,但是当多个信号连接同一个槽函数的时候,可以通过此方法获取到发送信号的对象,根据这个对象来判断当前是哪个信号触发的槽函数,当我们多个信号绑定一个槽函数的时候,一般是需要根据信号的不同来做不同的操作,所以这里可以获取到实际发生信号的对象,那我们就知道是哪个信号,然后就可以去处理了。
如下方代码,如果有多个信号连接到onDealWork槽函数,我们可以根据objectName()属性/对象的类型进行区分来处理不同的工作,其他区分的方式也都可以,具体看实际情况。
通过对象的objectName
void onDealWork()
{
QObject* obj = sender();
if(obj->objectName() == "Btn")
{
// todo;
}
else if(obj->objectName() == "Label")
{
// todo;
}
else if(obj->objectName() == "Edit")
{
// todo;
}
}
通过对象的类型
void onDealWork()
{
QObject* obj = sender();
QObject* obj = sender();
QPushButton* pBtn = dynamic_cast<QPushButton*>(obj);
if (pBtn != nullptr)
{
// todo;
}
QLabel* pLabel = dynamic_cast<QLabel*>(obj);
if (pLabel != nullptr)
{
// todo;
}
}
5、当我们使用 Qt::DirectConnection 类型作为信号槽的连接方式,且槽函数调用的线程不同于信号发送对象的线程,这个时候sender()方法返回的QObject对象指针是无效的,这种场景是不可以使用此方法来获取信号发送对象的。
大家可以使用下方代码进行测试,在槽函数中使用sender()获取的对象指针实际为nullptr,所以大家最好是获取到指针之后加上非空判断。
实际上使用Qt::DirectConnection连接方式,信号的触发和槽函数执行都是在同一个线程中,大家可以使用下方代码查看线程id,Qt::HANDLE mainId 和 Qt::HANDLE childId,使用 Qt::DirectConnection两者id一致,也就是处在同一个线程,使用 Qt::QueuedConnection或者默认不填,两者id是不一样的,表示不在同一个线程。
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
Qt::HANDLE childId = QThread::currentThreadId();
QString result;
QObject* obj = sender();
if (obj != nullptr)
{
result = sender()->objectName();
qDebug() << "current connect type is Qt::QueuedConnection";
}
else
{
// 如果多线程情况下,信号槽使用Qt::DirectConnection这种连接方式;
// 这里sender()返回空指针nullptr;
qDebug() << "current connect type is Qt::DirectConnection";
}
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
this->setObjectName("123");
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
// 如果使用此方式,在多线程的时候,默认是Qt::QueuedConnection;
//connect(this, &Controller::operate, worker, &Worker::doWork);
connect(this, &Controller::operate, worker, &Worker::doWork, Qt::DirectConnection);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString & result){
qDebug() << result;
}
signals:
void operate(const QString &);
};
// 测试代码;
void test()
{
Qt::HANDLE mainId = QThread::currentThreadId();
Controller* control = new Controller();
emit control->operate("test");
}
下图中是使用VS调试过程中sender()返回的值为空(nullptr)。
尾
Qt训练营内容(一期) 开始啦 ,更多详细的文章有兴趣的小伙伴可以点击看一看哈,里面有更多优质的内容等着你!也可以加群 861353824 一起交流哈!
更多推荐
Qt信号槽之槽函数中获取发送信号对象——sender()
发布评论