//main.cpp
#include "Counter.h"
int main(void){
Counter counter;
QObject::connect(&counter,&Counter::Is_Signal,&counter,&Counter::Is_Slots);
while(1) {
int num;
std::cout<<"enter 1 to emit the sign"<<std::endl;
std::cin>>num;
if (num==1){
emit counter.Is_Signal(1);
std::cout<<std::endl;
}}
}
//Counter.h
#include "QObject"
#include <iostream>
class Counter : public QObject
{
Q_OBJECT
public Q_SLOTS:
void Is_Slots(int value){
std::cout<<"Slot function is done!";
};
signals:
void Is_Signal(int value);
};
借鉴并且化用了官网的例子。官网
但是不够直观,我改了一下,只需要这两个文件。
这样就实现了一个基本的Qt信号机制。
最基本需要注意的点。
1.实现信号机制的类必须继承自 QObject ,而且下面要添加这个 Q_OBJECT 。里面定义了 QMetaObject 等一些基本的属性和方法。
2.
定义Slot 的类的方法前要加 public slots:
,声明一下。
定义signals 的类的方法前 加 signals:
。注意这里不是 public signals:
我们顺着 signals 的宏定义一直找到源头:
# define Q_SLOTS QT_ANNOTATE_ACCESS_SPECIFIER(qt_slot)
# define Q_SIGNALS public QT_ANNOTATE_ACCESS_SPECIFIER(qt_signal)
...
define slots Q_SLOTS
...
define signals Q_SIGNALS
原来这里已经有了一个public!
slots 函数需要实现(就是写函数里都有啥),但是signal函数不需要,只用声明一下就好了。
实际上我们声明一个signal函数只是为了调用一下它,它根本不需要实现。
4.
template <typename Func1, typename Func2>
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection)
connect函数中的参数 signal和 slot 应该输入 &类名::函数名字 。而不是
&对象名::函数名字。 (看作类的静态函数)
看下GDB的调试:
//main函数
(gdb) p counter
$1 = (Counter) {<QObject> = {<No data fields>}, static staticMetaObject = {d = {superdata = {direct = 0x7ffff709a140 <QObject::staticMetaObject>}, stringdata = 0x555555559060 <qt_meta_stringdata_Counter>, data = 0x5555555590c0 <qt_meta_data_Counter>, static_metacall = 0x55555555733a <Counter::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)>, relatedMetaObjects = 0x0, metaTypes = 0x55555555ba60 <qt_incomplete_metaTypeArray<qt_meta_stringdata_Counter_t, QtPrivate::TypeAndForceComplete<Counter, std::integral_constant<bool, true> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<int, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<void, std::integral_constant<bool, false> >, QtPrivate::TypeAndForceComplete<int, std::integral_constant<bool, false> > >>, extradata = 0x0}}}
(gdb) p &counter
$2 = (Counter *) 0x7fffffffe380
(gdb) p counter.Is_Signal
$3 = {void (Counter * const, int)} 0x555555557576 <Counter::Is_Signal(int)>
(gdb) p counter.Is_Slots
$4 = {void (Counter * const, int)} 0x55555555776e <Counter::Is_Slots(int)>
//connect函数内部
(gdb) p sender
$5 = (const QtPrivate::FunctionPointer<void (Counter::*)(int)>::Object *) 0x7fffffffe380
(gdb) p signal
$6 = (void (Counter::*)(Counter * const, int)) 0x555555557576 <Counter::Is_Signal(int)>
(gdb) p receiver
$7 = (const QtPrivate::FunctionPointer<void (Counter::*)(int)>::Object *) 0x7fffffffe380
(gdb) p slot
$9 = (void (Counter::*)(Counter * const, int)) 0x55555555776e <Counter::Is_Slots(int)>
除了sender和receiver有变化外,其他没有变化。最后调用了这个函数。
static QMetaObject::Connection connectImpl(const QObject *sender, void **signal,
const QObject *receiver, void **slotPtr,
QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject);
看出counter对象里多了一大堆东西来自最开始前面那个宏 Q_OBJECT ,可以看出来很重要。
里面
- 调用Signal 函数 的时候,我们这里写了个 emit 表示“发出了一个信号”,实际上emit这个宏什么也没有,可以不写。但是习惯上带上。
- 调用Is_Signal 函数的时候,会来到Qt引擎生成的一个文件里。在debug文件里 有个autogen结尾的文件夹,那个就是自动生成的。里面还有个文件夹里有这个文件,里面出现了Qt 自动帮我们补全的Counter::Is_Signal真面目了!看到里面调用了
QMetaObject::activate
,Qt在背后帮我们做了整个过程。
//moc_Counter.cpp
Created by: The Qt Meta Object Compiler version 68 (Qt 6.2.2)
...
// SIGNAL 0
void Counter::Is_Signal(int _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(std::addressof(_t1))) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
7.那么这个activate函数是啥呢?是这个
//qobjectdefs.h
static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
没功夫再往下面看了…