Qt에서 이벤트 배포 소스 코드 분석

5886 단어
Qt에서 이벤트 배포 소스 코드 분석
Qt에서 이벤트 전달 순서:
이 프로그램에서 하나의 이벤트 순환에 들어가 시스템에서 발생하는 이벤트를 받아들이고 나누어 주는 것은 exec에서 이루어진 것이다.다음은 예를 들어 설명합니다.
1) 먼저 다음 예제 코드를 살펴보십시오.
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MouseEvent w;
    w.show();
    
    return a.exec();
}

2) a.exec는 이벤트 순환에 들어가고 QApplication::exec()를 호출한다.
int QApplication::exec()
{
    return QGuiApplication::exec();
}

3) QApplication::exec () 는 QGuiApplication:::exec () 를 호출합니다.
int QGuiApplication::exec()
{
#ifndef QT_NO_ACCESSIBILITY
    QAccessible::setRootObject(qApp);
#endif
    return QCoreApplication::exec();
}

4) QGuiApplication::exec()는 QCoreApplication::exec()를 호출합니다.
int QCoreApplication::exec()
{
    if (!QCoreApplicationPrivate::checkInstance("exec"))
        return -1;


    QThreadData *threadData = self->d_func()->threadData;
    if (threadData != QThreadData::current()) {
        qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
        return -1;
    }
    if (!threadData->eventLoops.isEmpty()) {
        qWarning("QCoreApplication::exec: The event loop is already running");
        return -1;
    }


    threadData->quitNow = false;
    QEventLoop eventLoop;
    self->d_func()->in_exec = true;
    self->d_func()->aboutToQuitEmitted = false;
    int returnCode = eventLoop.exec();
    threadData->quitNow = false;
    if (self) {
        self->d_func()->in_exec = false;
        if (!self->d_func()->aboutToQuitEmitted)
            emit self->aboutToQuit(QPrivateSignal());
        self->d_func()->aboutToQuitEmitted = true;
        sendPostedEvents(0, QEvent::DeferredDelete);
    }


    return returnCode;
}

5) QCoreApplication:::exec()에서 이벤트 Loop을 호출합니다.exec()에서 이벤트 순환하기;
int QEventLoop::exec(ProcessEventsFlags flags)
{
    Q_D(QEventLoop);
    //we need to protect from race condition with QThread::exit
    QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
    if (d->threadData->quitNow)
        return -1;


    if (d->inExec) {
        qWarning("QEventLoop::exec: instance %p has already called exec()", this);
        return -1;
    }


    struct LoopReference {
        QEventLoopPrivate *d;
        QMutexLocker &locker;


        bool exceptionCaught;
        LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
        {
            d->inExec = true;
            d->exit = false;
            ++d->threadData->loopLevel;
            d->threadData->eventLoops.push(d->q_func());
            locker.unlock();
        }


        ~LoopReference()
        {
            if (exceptionCaught) {
                qWarning("Qt has caught an exception thrown from an event handler. Throwing
" "exceptions from an event handler is not supported in Qt. You must
" "reimplement QApplication::notify() and catch all exceptions there.
"); } locker.relock(); QEventLoop *eventLoop = d->threadData->eventLoops.pop(); Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error"); Q_UNUSED(eventLoop); // --release warning d->inExec = false; --d->threadData->loopLevel; } }; LoopReference ref(d, locker); // remove posted quit events when entering a new event loop QCoreApplication *app = QCoreApplication::instance(); if (app && app->thread() == thread()) QCoreApplication::removePostedEvents(app, QEvent::Quit); while (!d->exit) processEvents(flags | WaitForMoreEvents | EventLoopExec); ref.exceptionCaught = false; return d->returnCode; }

6)eventLoop.exec()는 이벤트 배포를 위해 QCoreApplication의processEvents를 호출합니다.
7) notify를 호출하여 배포
QCore Application::send Event, QCore Application::post Event와 QCore Application::send Posted Events는 모두 notify를 호출하여 이벤트 분배를 진행한다.
bool QCoreApplication::notify(QObject *receiver, QEvent *event)
{
    Q_D(QCoreApplication);
    // no events are delivered after ~QCoreApplication() has started
    if (QCoreApplicationPrivate::is_app_closing)
        return true;


    if (receiver == 0) {                        // serious error
        qWarning("QCoreApplication::notify: Unexpected null receiver");
        return true;
    }


#ifndef QT_NO_DEBUG
    d->checkReceiverThread(receiver);
#endif


    return receiver->isWidgetType() ? false : d->notify_helper(receiver, event);
}

8) notify 호출 notifyhelper가 이벤트 배달하기;
bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
    // send to all application event filters
    if (sendThroughApplicationEventFilters(receiver, event))
        return true;
    // send to all receiver event filters
    if (sendThroughObjectEventFilters(receiver, event))
        return true;
    // deliver the event
    return receiver->event(event);
}

9) 위 8단계 코드에서 이벤트 전달 확인
전달의 순서는 먼저 전역에 전달되는 이벤트 필터, 그리고 목표 대상에게 전달되는 이벤트 필터로 최종적으로 목표 대상에게 전달된다.

좋은 웹페이지 즐겨찾기