1. QObject::connect 经典方式是 字符串 链接
声明:
static QMetaObject::Connection connect(
const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection );
connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
信号(Signal) 槽(Slot) 链接 使用 主要 有两种:
template<typename PointerToMemberFunction, typename Functor>
static QMetaObject::Connection connect
( const QObject *sender, PointerToMemberFunction signal,
Functor functor);
template<typename PointerToMemberFunction, typename Functor>
static QMetaObject::Connection connect
(const QObject *sender, PointerToMemberFunction signal,
const QObject *context, Functor functor,
Qt::ConnectionType type = Qt::AutoConnection);
1. 提供 const QObject *receiver 参数
2. 没有 const QObject *receiver 参数
注意: 上面的形式 是方便C++用户理解使用的语法形式。 也是QT文档使用的形式(Q_DOC)
内部实现的代码是下面的形式。
参看实现 可知: 如果没有 提供 const QObject *receiver 参数, 则使用 sender.
//connect to a functor
template <typename Func1, typename Func2>
static inline typename std::enable_if<
QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1,
QMetaObject::Connection>::type
connect( const typename QtPrivate::FunctionPointer<Func1>::Object *sender,
Func1 signal,
Func2 slot)
{
return connect(sender, signal, sender, slot, Qt::DirectConnection);
}
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)
对于类的成员函数, 使用的是 模板进行解析,利用的是模板的参数匹配功能,使用的语法解析:
template<class Obj, typename Ret, typename... Args>
struct FunctionPointer<Ret (Obj::*) (Args...)>
{
typedef Obj Object;
typedef List<Args...> Arguments;
typedef Ret ReturnType;
typedef Ret (Obj::*Function) (Args...);
enum {ArgumentCount = sizeof...(Args), IsPointerToMemberFunction = true};
template <typename SignalArgs, typename R>
static void call(Function f, Obj *o, void **arg)
{
FunctorCall<
typename Indexes<ArgumentCount>::Value,
SignalArgs, R,
Function>
::call(f, o, arg);
}
};
利用这个模板 将 ClassName::MemberFunction 的函数 分离出:
Object: ClassName
ReturnType Ret
Arguments 参数列表
函数调用 和参数传递
void TestSigObj::sglClass(ClassParam _t1, const QString _t2)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
int signal_index = signalOffset + local_signal_index;
void *empty_argv[] = { 0 };
if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index,
argv ? argv : empty_argv);
}
{
QMutexLocker locker(signalSlotLock(sender));
ConnectionListsRef connectionLists = sender->d_func()->connectionLists;
if (!connectionLists.connectionLists) {
locker.unlock();
if (qt_signal_spy_callback_set.signal_end_callback != 0)
qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
return;
}
const QObjectPrivate::ConnectionList *list;
if (signal_index < connectionLists->count())
list = &connectionLists->at(signal_index);
else
list = &connectionLists->allsignals;
Qt::HANDLE currentThreadId = QThread::currentThreadId();
do {
QObjectPrivate::Connection *c = list->first;
if (!c) continue;
// We need to check against last here to ensure that signals added
// during the signal emission are not emitted in this emission.
QObjectPrivate::Connection *last = list->last;
do {
if (!c->receiver)
continue;
QObject * const receiver = c->receiver;
const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId.load();
// determine if this connection should be sent immediately or
// put into the event queue
if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
|| (c->connectionType == Qt::QueuedConnection)) {
queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker);
continue;
#ifndef QT_NO_THREAD
} else if (c->connectionType == Qt::BlockingQueuedConnection) {
if (receiverInSameThread) {
qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: "
"Sender is %s(%p), receiver is %s(%p)",
sender->metaObject()->className(), sender,
receiver->metaObject()->className(), receiver);
}
QSemaphore semaphore;
QMetaCallEvent *ev = c->isSlotObject ?
new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) :
new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore);
QCoreApplication::postEvent(receiver, ev);
locker.unlock();
semaphore.acquire();
locker.relock();
continue;
#endif
}
QConnectionSenderSwitcher sw;
if (receiverInSameThread) {
sw.switchSender(receiver, sender, signal_index);
}
if (c->isSlotObject) {
c->slotObj->ref();
QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj);
locker.unlock();
obj->call(receiver, argv ? argv : empty_argv);
// Make sure the slot object gets destroyed before the mutex is locked again, as the
// destructor of the slot object might also lock a mutex from the signalSlotLock() mutex pool,
// and that would deadlock if the pool happens to return the same mutex.
obj.reset();
locker.relock();
} else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
//we compare the vtable to make sure we are not in the destructor of the object.
const int methodIndex = c->method();
const int method_relative = c->method_relative;
const auto callFunction = c->callFunction;
locker.unlock();
if (qt_signal_spy_callback_set.slot_begin_callback != 0)
qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv);
callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);
if (qt_signal_spy_callback_set.slot_end_callback != 0)
qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex);
locker.relock();
} else {
const int method = c->method_relative + c->method_offset;
locker.unlock();
if (qt_signal_spy_callback_set.slot_begin_callback != 0) {
qt_signal_spy_callback_set.slot_begin_callback(receiver,
method,
argv ? argv : empty_argv);
}
metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
if (qt_signal_spy_callback_set.slot_end_callback != 0)
qt_signal_spy_callback_set.slot_end_callback(receiver, method);
locker.relock();
}
if (connectionLists->orphaned)
break;
} while (c != last && (c = c->nextConnectionList) != 0);
if (connectionLists->orphaned)
break;
} while (list != &connectionLists->allsignals &&
//start over for all signals;
((list = &connectionLists->allsignals), true));
}
if (qt_signal_spy_callback_set.signal_end_callback != 0)
qt_signal_spy_callback_set.signal_end_callback(sender, signal_index);
}
same thread
QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj);
locker.unlock();
obj->call(receiver, argv ? argv : empty_argv);
inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, Q_NULLPTR); }
template<typename Func, int N, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase
{
typedef QtPrivate::Functor<Func, N> FuncType;
Func function;
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
{
switch (which) {
case Destroy:
delete static_cast<QFunctorSlotObject*>(this_);
break;
case Call:
FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a);
break;
case Compare: // not implemented
case NumOperations:
Q_UNUSED(ret);
}
}
public:
explicit QFunctorSlotObject(const Func &f) : QSlotObjectBase(&impl), function(f) {}
};
template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> {
static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg) {
(o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
}
};
2. QTimer::singleShot
支持 lamda functor. 也有两种形式
没有 const QObject *receiver 参数 的 实现:
// singleShot to a functor or function pointer (without context)
template <typename Duration, typename Func1>
static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
!std::is_same<const char*, Func1>::value, void>::type
singleShot(Duration interval, Func1 slot)
{
singleShot(interval, defaultTypeFor(interval), nullptr, slot);
}
可知: 如果没有 提供 const QObject *receiver 参数, 和 QObject::connect 不同的是 使用 nullptr.
receiver == nullptr 处理函数 是在那个 执行线程 中呢 ?
实现:
void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
const QObject *receiver,
QtPrivate::QSlotObjectBase *slotObj)
{
new QSingleShotTimer(msec, timerType, receiver, slotObj);
}
QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj)
: QObject(QAbstractEventDispatcher::instance()), hasValidReceiver(r), receiver(r), slotObj(slotObj)
{
timerId = startTimer(msec, timerType);
if (r && thread() != r->thread()) {
// Avoid leaking the QSingleShotTimer instance in case the application exits before the timer fires
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater);
setParent(0);
moveToThread(r->thread());
}
}
可知: 如果 receiver == nullptr, 父对象是: QAbstractEventDispatcher::instance()
static QAbstractEventDispatcher *instance(QThread *thread = Q_NULLPTR);
QAbstractEventDispatcher *QAbstractEventDispatcher::instance(QThread *thread)
{
QThreadData *data = thread ? QThreadData::get2(thread) : QThreadData::current();
return data->eventDispatcher.load();
}
执行 startTimer 语句, 则会在创建Timer的线程事件队列处理。
void QSingleShotTimer::timerEvent(QTimerEvent *)
{
// need to kill the timer _before_ we emit timeout() in case the
// slot connected to timeout calls processEvents()
if (timerId > 0)
killTimer(timerId);
timerId = -1;
if (slotObj) {
// If the receiver was destroyed, skip this part
if (Q_LIKELY(!receiver.isNull() || !hasValidReceiver)) {
// We allocate only the return type - we previously checked the function had
// no arguments.
void *args[1] = { 0 };
slotObj->call(const_cast<QObject*>(receiver.data()), args);
}
} else {
emit timeout();
}
}
3. QTimer
若没有指定 对象 持有者, 则在 当前的执行线程(即 创建这个QTimer 的线程 )中, 启动 timer.
slot 调用流程 (slot 是 Lamda)
template <int... II, typename... SignalArgs, typename R, typename Function>
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> {
static void call(Function &f, void **arg) {
f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
}
};
arg: 是原始 堆栈列表
slot 是函数, 调用的形式:
template <int... II, typename... SignalArgs,
typename R, typename... SlotArgs, typename SlotRet,
class Obj>
struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R,
SlotRet (Obj::*)(SlotArgs...)>
{
static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg)
{
(o->*f)(
(*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...),
ApplyReturnValue<R>(arg[0]);
}
};
类型的校验 是模板参数编译时执行:
Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<
typename SignalType::Arguments,
typename SlotType::Arguments>::value),
"Signal and slot arguments are not compatible.");
struct CheckCompatibleArguments<List<Arg1, Tail1...>, List<Arg2, Tail2...>>
{
enum {
value = AreArgumentsCompatible<
typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value
&& CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value };
};
struct CheckCompatibleArguments<List<Arg1, Tail1...>, List<Arg2, Tail2...>>
{
enum { value = AreArgumentsCompatible<typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value
&& CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value };
};
class IHHUserActionManager {
public:
~IHHUserActionManager(){}
virtual QObject *getObject() = 0;
virtual bool initUserActionAppInfo(QString appKey,QString appName,QString appVersion)=0;
virtual void setUid(QString uid)=0;
virtual void setUploadSize(int uploadSize)=0;
virtual void AddActionByQueue(QString eventid,QJsonObject customJsonContent)= 0;
virtual void AddActionByQueue(QJsonObject ActionObject)= 0;
virtual void AddActionByQueue(QString eventid,QString customJsonContent)= 0;
};