大家好,我是IT文藝男,來自一線大廠的一線程序員
經過前面幾次的Qt源碼講解,我相信大家對Qt update刷新機制從底層原理上有了一個深刻的理解;這次做一個收尾總結,來復盤前面幾次所講解的內容;
分析的切入點、思考點::
在做GUI開發時,要讓控件刷新,會調用update函數;那么在調用了update函數后,Qt究竟基於什么原理、執行了什么代碼使得屏幕上有變化?
分析的過程分解::
一、刷新事件異步投遞過程
二、刷新事件的處理流程
三、繪制到內存Image
四、刷新結果輸出到屏幕
一、刷新事件異步投遞過程
分析void QWidget::update()
函數的源碼,即調用update沒有傳遞參數,則默認刷新控件的整個區域,調用重載的update函數
- 如果控件是隱藏或者刷新被禁用,則直接返回
- 參數傳遞的矩形與控件矩形的交集,如果為空,則直接返回
- 如果支持BackingStore(默認支持),則標臟該控件所屬的頂層窗口(TLW:: topLevelWidget縮寫)區域,即調用
tlwExtra->backingStoreTracker->markDirty(r, this);
函數
a、把控件加入到dirtyWidgets容器中(addDirtyWidget函數)
b、通知tlw進行刷新(sendUpdateRequest
函數)
sendUpdateRequest
函數Post一個QEvent::UpdateRequest事件,即放入事件隊列中,立即返回;QEvent::UpdateRequest事件的接受者為tlw;
二、刷新事件的處理流程
追蹤QEvent::UpdateRequest事件處理,進入消息通知流程,即QApplication::notify(QObject *receiver, QEvent *e)
函數(沒有對QEvent::UpdateRequest事件進行處理),進一步由QApplicationPrivate::notify_helper(QObject *receiver, QEvent * e)
函數處理;
receiver的event函數不做處理,其調用父類的event函數,即bool QWidget::event(QEvent *event)
函數,該函數中針對事件類型進行處理(switch case);
對於QEvent::UpdateRequest事件處理,QWidgetBackingStore::doSync
函數中調用tlw->d_func()->drawWidget(store->paintDevice(), dirtyCopy, QPoint(), flags, 0, this)
;函數進行繪制,函數的第一個參數是獲取繪制設備,對於Windows平台,繪制目的設備為內存Image
三、繪制到內存Image
回到QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags,QPainter *sharedPainter, QWidgetBackingStore *backingStore)
函數
函數主體內容如下::
1、繪制背景
2、繪制前景(send the paint event)
3、繪制子控件(paintSiblingsRecursive函數調用)
QWidgetPrivate::paintSiblingsRecursive函數里又會調用QWidgetPrivate::drawWidget函數從而形成樹形繪制。
四、刷新結果輸出到屏幕
qtbase\src\plugins\platforms\windows目錄中的QWindowsBackingStore::flush
函數中會調用BitBlt函數(Windows API函數)