Qt信号槽之槽函数中获取发送信号对象——sender()

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 &parameter) {
    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信号槽之槽函数中获取发送信号对象——sender()_第1张图片


Qt训练营内容(一期) 开始啦 ,更多详细的文章有兴趣的小伙伴可以点击看一看哈,里面有更多优质的内容等着你!也可以加群 861353824 一起交流哈!

你可能感兴趣的:(Qt,Qt基础常识详解,Qt,信号槽,sender,connect,signal)