#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
class QSlider;
class QLabel;
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = 0);
private slots:
void onValueChanged(int val);
private:
QSlider *m_slider;
QLabel *m_label;
};
#endif // DIALOG_H
//////////////////////////////////////////////////////////////
#include "dialog.h"
#include <QtWidgets>
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
{
m_label = new QLabel("0", this);
m_slider = new QSlider(Qt::Horizontal, this);
m_slider->setRange(0, 100);
m_slider->setValue(0);
QHBoxLayout *mainLayout = new QHBoxLayout();
mainLayout->addWidget(m_label);
mainLayout->addWidget(m_slider);
this->setLayout(mainLayout);
//connect(m_slider, SIGNAL(valueChanged(int val)), this, SLOT(onValueChanged(int val))); // error
//connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged(int)));
//connect(m_slider, &QSlider::valueChanged, this, &Dialog::onValueChanged);
connect(m_slider, &QSlider::valueChanged, [this] (int val) {
m_label->setText(QString::number(val));
});
}
void Dialog::onValueChanged(int val)
{
m_label->setText(QString::number(val));
}
///////////////////////////////////////////////////////////////////////
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
Qt的信号和槽机制是用来在对象间通信的方法,当一个特定的事件发生的时候,signal会被emit发射出来,slot函数用来
响应相应的signal。它使得对象间保持一种松耦合的关系。
Qt信号槽是由Q_OBJECT支持的,程序在编译之前moc预处理器会对有Q_OBJECT的类进行预处理,生成moc_xxxx.cpp来扩展当前类。
内部由meta object来维护我们需要的信息和接口。
1.一个信号可以连接到多个槽和信号;
2.多个信号可以连接到同一个槽;
如果一个信号连接到多个槽,当信号被发射后所有的槽函数按照连接建立的顺序都会被激活。
static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
const QObject *receiver, const QMetaMethod &method,
Qt::ConnectionType type = Qt::AutoConnection);
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal,
const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection);
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal,
const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection);
// 需要编译器支持C++11 lambda表达式
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);
最后一个参数描述了连接建立的类型,实际上它决定了信号是被立即投递还是进队。如果信号进队,那么它的参数类型必须是能被Qt's meta-object系统认识的,因为Qt在事件
背后需要拷贝其参数进行存储,否则的话会得到一个错误信息:
QObject::connect: Cannot queue arguments of type 'MyType'
(Make sure 'MyType' is registered using qRegisterMetaType().)
对于自定义的类型在connect之前需要注册一下:
qRegisterMetaType<MyType>("MyType");
主要有下面几种连接方式:
AutoConnection:
默认参数,如果接收者所在的线程和信号发射的线程是同一个线程使用DirectConnect,否则使用QueuedConnection;
DirectConnection:
信号发射后槽函数会被立刻调用,槽函数的执行在信号发射的线程;
QueuedConnection:
将信号转换为事件,事件被派发到接收者所在的线程队列中,事件循环会在之后的某个时间取出事件调用槽函数,此槽函数的执行在接收者的线程;
BlockingQueuedConnection:
与QueuedConnection类似,区别在于发送者的线程会被阻塞,直至接收者所在线程的事件循环处理发送者发送(入栈)的事件,当连接信号的槽被触发后,阻塞被解除。
要注意的是使用这个参数要求接收者所在的线程不是信号发射的线程,否则应用程序会死锁。
从上面的连接方式可以看出,发送对象(sender)在哪个线程并不重要,AutoConnection是根据信号是在哪个线程发射的来决定用哪一种连接类型。
class Thread : public QThread
{
Q_OBJECT
signals:
void mySignal();
protected:
void run()
{
emit mySignal();
}
};
Thread thread;
Object object;
QObject::connect(thread, SIGNAL(mySignal()), &object, SLOT(mySlot()));
thread.start();
如上代码,虽然发送者thread和接收者object在同一线程,但是mySignal是在不同的线程发射的所以使用的应该是QueuedConnection。