Qt信号和槽的机制(逻辑清晰的来说清楚信号和槽)
Qt 信号和槽的机制
⾸先说声对不起,上次在PyQt5中写信号与槽,由于时间原因没有写完。有⼩伙伴留⾔说,希望把这章补全。所以,这是⼀篇迟来的⽂章,再次向⼤家说声抱歉。
⼀、桌⾯程序的结构
Qt的使⽤场景,主要是应⽤于桌⾯程序来使⽤,不管你使⽤的操作系统平台是什么。对于桌⾯程序来说,最重要的就是交互了。既然有交互,就需要⼀个窗⼝系统了。
窗⼝系统实现了桌⾯程序的主要逻辑,并提供了⼀套基于事件驱动的编程框架。Qt同样也提供了这样的⼀套逻辑。
oceanus
我们常见的桌⾯程序的结构,如下图所⽰:
所以,我们可以看到,在桌⾯程序中我们需要对窗⼝系统的⼀些操作作出相应,也就是事件。网名大全2013最新版的
⼆、事件
实现事件的机制通常有两种。
⼀种是事件处理类,是⽤回调函数来实现。
另⼀种叫委托,就是事件的处理不是收到事件的⼈⾃⼰来做,⽽是把它委托给了别⼈来做。Qt就提供了这样的⼀种机制:信号和槽。
三、信号和槽
信号与槽是Qt特有的的消息传输机制,在Qt中信号与槽⽤得⼗分⼴泛。在编程的过程中,我们都会遇到消息传递的事情,本质上就是发出命令(信号、消息),执⾏命令(相应的执⾏)。
⽐如单击窗⼝上⼀个按钮然后弹出⼀个对话框,那么就可以将这个按钮的单击信号和⾃定义的槽关联起来,信号是按钮的单击信号,槽实现了创建⼀个对话框并显⽰的功能。
信号与槽就是实现对象之间通信的⼀种机制,在其他编程语⾔中也有通过回调机制来实现对象之间的通信。
信号:当对象改变其状态时,信号就由该对象发射 (emit) 出去,⽽且对象只负责发送信号,它不知道另⼀端是谁在接收这个信号。
槽:⽤于接收信号,⽽且槽只是普通的对象成员函数。⼀个槽并不知道是否有任何信号与⾃⼰相连接。
信号槽是设计模式观察者模式的⼀种实现:
A、⼀个信号就是⼀个能够被观察的事件,或者⾄少是事件已经发⽣的⼀种通知;
B、⼀个槽就是⼀个观察者,通常就是在被观察的对象发⽣改变的时候——也可以说是信号发出的时候——被调⽤的函数;
C、信号与槽的连接,形成⼀种观察者-被观察者的关系;
D、当事件或者状态发⽣改变的时候,信号就会被发出;同时,信号发出者有义务调⽤所有注册的对这个事件(信号)感兴趣的函数(槽)。
country music信号和槽是多对多的关系。⼀个信号可以连接多个槽,⽽⼀个槽也可以监听多个信号。
bridesmaid
然后,实现信号和槽,就要说⼀下Qt的元对象系统。
四、Qt元对象系统
Qt 的元对象系统叫 Mate-Object-System,提供了对象之间通信的信号与槽机制、运⾏时类型信息和动态属性系统。
但是,元对象是基于三个条件的:
1、该类必须继承⾃Qobject类
2、必须在类的私有声明区声明Q_OBJECT宏(在类定义的时候,如果没有指定public,
则默认为private,⽤来启⽤元对象功能,⽐如动态属性、信号和槽)。
3、 元对象编译器Meta-Object Compiler(moc)为 QObject的⼦类实现元对象
特性提供必要的代码。
schedule是什么意思有了元对象系统后,我们就可以使⽤Qt的信号和槽了。
五、信号和槽的格式
信号与槽关联是⽤ QObject::connect() 函数实现的,其基本格式是:
QObject::connect(nder, SIGNAL(signal()), receiver, SLOT(slot()));
在Qt 5中提供了⼀种新的格式:
connect(nder, &Sender::valueChanged,receiver, &Receiver::updateValue);
具体的使⽤哪种格式,就看个⼈的喜好了。
注:在⽇常的项⽬编程中,如果第⼀种的connect⽅式出现报错,你可以尝试使⽤第⼆种connect⽅式。
六、connect的第五个参数
在connect函数中除了上⾯介绍的四个参数外,还有第五个参数,是缺省的参数。我们打开qobject.h⽂件可以看到它的定义,如下所⽰:
static QMetaObject::Connection connect(const QObject *nder, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
static QMetaObject::Connection connect(const QObject *nder, const QMetaMethod &signal,
const QObject *receiver, const QMetaMethod &method,
Qt::ConnectionType type = Qt::AutoConnection);
inline QMetaObject::Connection connect(const QObject *nder, const char *signal,
const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;
最后⼀个参数所表⽰的意思:
Qt::AutoConnection:信号的发送者与信号的接收者在同⼀线程,则默认使⽤Qt::DirectConnection:如果不在同⼀线程,则默认 使⽤Qt::QueuedConnection。
Qt::DirectConnection:信号的发送者与信号的接收者在同⼀线程中执⾏,当发出信号后,会马上进⼊槽函数,看上去就像在信号 发送位置调⽤了槽函数,在多线程下会⽐较危险,容易造成崩溃。
Qt::QueuedConnection:信号的发送者与信号的接收者不在同⼀线程中执⾏,槽函数运⾏于信号的接收者线程,当发送信号后, 槽函数不会马上被调⽤,等待信号的接收者把当前函数执⾏完,进⼊事件循环之后,槽函数才会被调⽤。多线程环境下⼀般⽤这个。英语翻译在线
Qt::BlockingQueuedConnection:槽函数的调⽤时机与Qt::QueuedConnection⼀致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运⾏完。接收者和发送者绝对不能在⼀个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
Qt::UniqueConnection:可以通过按位或(|)与以上四个结合在⼀起使⽤。当设置此参数时,当某个信号和槽已经连接时,再进⾏重复的连接就会失败。也就是避免了重复连接。
介绍到这⾥,信号和槽的基本内容就写完了。但是,还是得说下Qt事件(你可以结合着上⾯第2节⼀起看)。
judge是什么意思七、Qt事件
⽆论是什么桌⾯操作系统,每个进程都有⼀个全局的事件队列(Event Queue)。当我们在键盘上按了⼀个键、移动或者点击⿏标、触摸屏幕等等,都会产⽣⼀个事件(Event),并由操作系统负责将它扔到进程的事件队列。
spotted
dogdays扔到事件队列后,它会等待以后的某⼀个时刻发送。分配器(dispatcher )会遍历事件队列,并且将⼊栈的事件发送到它们的⽬标对象当中,因此它们被称为事件循环(Event loop)。
Qt中是通过运⾏QCoreApplication::exec()来进⼊Qt的主体事件循环的;这会引发阻塞,直⾄QCoreAp
plication::exit() 或者QCoreApplication::quit() 被调⽤,进⽽结束循环。
写到这⾥就先结束吧,再次向⼤家说声抱歉,这篇迟来的⽂章-关于信号和槽的,欢迎⼤家⼀起交流⼀起进步。
本⽂原创作者:冯⼀川(),未经作者授权同意,请勿转载。
lightbox