1. 程式人生 > >Qt原始碼分析-事件如何觸發訊號

Qt原始碼分析-事件如何觸發訊號

/*訊號觸發點
在分析Qt的事件迴圈時,在Windows平臺的事件分發器處理函式
QEventDispatcherWin32::processEvents中最終只有DispatchMessage(&msg);
來分發事件,並沒有看到怎麼觸發訊號的,所以想了解事件到底怎麼轉換成訊號的

猜測,是Qt的GUi元件封裝了Windows的元件,然後接受事件訊息,呼叫事件函式時去發射訊號

分析一個按鈕的click訊號吧
一般應該是在mouseReleaseEvent裡觸發的,一層一層看怎麼處理的*/

void QWidget::mouseReleaseEvent(QMouseEvent *event)  //注意是虛擬函式
{
    event->ignore();//可以看到QWidget僅僅是忽略訊號
}

//=========================QAbstractButton::mouseReleaseEvent====================
//再看派生自QWidget的QAbstractButton,他又是QPushButton的基類

void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)//虛擬函式
{
    Q_D(QAbstractButton);
    d->pressed = false;

    if (e->button() != Qt::LeftButton) {
        e->ignore();
        return;
    }

    if (!d->down) {
        e->ignore();
        return;
    }

    if (hitButton(e->pos())) {//返回基於當前接受事件的控制元件的區域性座標的點選位置,表示是否點選到這個控制元件
        d->repeatTimer.stop();
        d->click();//這裡呼叫QAbstractButtonPrivate::click()函式
        e->accept();
    } else {
        setDown(false);
        e->ignore();
    }
}

//=========================QAbstractButtonPrivate::click()====================

void QAbstractButtonPrivate::click()//不是虛擬函式
{
    Q_Q(QAbstractButton);


    down = false;
    blockRefresh = true;
    bool changeState = true;
    if (checked && queryCheckedButton() == q) {
        // the checked button of an exclusive or autoexclusive group cannot be unchecked
#ifndef QT_NO_BUTTONGROUP
        if (group ? group->d_func()->exclusive : autoExclusive)
#else
        if (autoExclusive)
#endif
            changeState = false;
    }


    QPointer<QAbstractButton> guard(q);
    if (changeState) {
        q->nextCheckState();
        if (!guard)
            return;
    }
    blockRefresh = false;
    refresh();
    q->repaint(); //flush paint event before invoking potentially expensive operation
    QApplication::flush();
    if (guard)
        emitReleased();
    if (guard)
        emitClicked();//這裡呼叫emitClicked發射訊號
}

//=========================QAbstractButtonPrivate::emitClicked()====================

void QAbstractButtonPrivate::emitClicked()
{
    Q_Q(QAbstractButton);
    QPointer<QAbstractButton> guard(q);
    emit q->clicked(checked);//q就是QAbstractButton,就是說觸發QAbstractButton的訊號
#ifndef QT_NO_BUTTONGROUP
    if (guard && group) {
        emit group->buttonClicked(group->id(q));
        if (guard && group)
            emit group->buttonClicked(q);
    }
#endif
}

//====================重寫QPushButton的mouseReleaseEvent函式======================

//而QPushButton沒有實現mouseReleaseEvent函式,也沒有click訊號,所以必然依賴的時父類QAbstractButton的
//嘗試覆蓋這個函式試試mouseReleaseEvent,然後看有沒有click訊號發出
voidMyPushButton::mouseReleaseEvent ( QMouseEvent * e )
{
    qDebug("My PushButton mouseRelease");
    QPushButton::mouseReleaseEvent(e);
}

/*結論就是
當把QPushButton::mouseReleaseEvent(e);註釋掉時,是不會觸發Click訊號的
而,加上後,則會觸發
即事件轉換成訊號,是由QEventDispatcherWin32::processEvents函式中
呼叫DispatchMessage(&msg);分發事件,然後呼叫相應事件函式(回撥函式)
然後事件函式中會觸發相應訊號
所以切記重新相應事件函式時,記得呼叫基類的事件函式
*/