关于backingStore的同步
从QWidgetBackingStore::sync
说起, 调用关系如下:
QWidgetPrivate::syncBackingStore
=> QWidgetBackingStore::sync
=> QWidgetBackingStore::markDirtyOnScreen
=> QWidgetBackingStore::doSync
=> QWidgetBackingStore::resetWidget
=> QWidgetPrivate::drawWidget
=> QWidgetPrivate::paintBackground
=> QWidgetPrivate::sendPaintEvent
=> QWidget::paintEvent
=> QWidgetPrivate::paintSiblingsRecursive
=> QWidgetBackingStore::flush
QWidgtBackingStore只对QWidget可见, 所以QWidgetPrivate::syncBackingStore
对QWidgetBackingStore::sync
做了进一步封装, 其他地方可以通过widget的D指针调到QWidgetPrivate::syncBackingStore
.
QWidgetPrivate::syncBackingStore
主要是QWdiget在处理UpdateRequest
事件的时候调到:
QWidget::event(QEvent::UpdateRequest)
=> QWidgetPrivate::syncBackingStore
关于updateRequest事件
至于UpdateRequest事件的来源, 搜代码, 找到的就QWidgetBackingStore
和QWidgetWindow
(QWindow)这两个地方.
- 先说说
QWidgetBackingStore
.
会向widget发UpdateRequest事件的就QWidgetBackingStore::sendUpdateRequest
一个地方, 这个sendUpdateRequest又是给WidgetBackingStore::markDirty
用的:
QWidgetBackingStore::markDirty (updateNow)
=> QWidgetBackingStore::addDirtyWidget
=> QWidgetBackingStore::sendUpdateRequest
=> QApplication::sendEvent(widget, QEvent::UpdateRequest) (or postEvent)
再上一层就到了QWidget::repaint
和QWidget::update
:
QWidget::repaint(const QRegion &rgn)
=> QWidgetPrivate::repaint
=> QWidgetBackingStore::markDirty (updateNow)
QWidget::update(const QRect &rect)
=> QWidgetPrivate::update
=> QWidgetBackingStore::markDirty (updateLatter)
这两个算是QWidget最终暴露给上层应用的api了. 看实现都是调的QWidgetBackingStore::markDirty
, 不同之处仅是传的参数, 前者是立即触发UpdateRequest事件, 后者也会触发UpdateReques事件但是走的是事件循环.
repaint
最终会立即触发paintEvent, 多用于动画的绘制.
连续多次调update
最终只会触发一次paintEvent. 因为QApplication::compressEvent
中对UpdateRequest事件做了压缩. 算是Qt做的一点优化. Qt也是比较建议用update.
按钮hover效果的刷新就是在处理鼠标事件的时候调了QWidget::update
.
- 再看看
QWidgetWindow
这边的情况.
QWidgetWindow::event(QEvent::Resize)
=> QWidgetWindow::handleResizeEvent
=> QWidgetPrivate::syncBackingStore
QWidgetWindow::event(QEvent::Expose)
=> QWidgetWindow::handleExposeEvent
=> QWidgetPrivate::syncBackingStore
QWidgetWindow::repaintWindow()
=> QWidgetBackingStore::markDirty(updateNow, BufferInvalid)
QWindow::requestUpdate
=> QPlatformWindow::requestUpdate
=> QPlatformWindow::deliverUpdateRequest
=> QCoreApplication::sendEvent(window, QEvent::UpdateRequest);
=> QWidgetWindow::event(QEvent::UpdateRequest)
=> QWidget::repaint
看了下, QWidgetWindow
这边会触发到backingStore更新的有上面四个地方. 前面两个两个很好理解, 窗口大小改变(Resize)和窗口显示(Expose)的时候会触发. 第三个和屏幕相关的, 从QWindow::setScreen
触发过来的, 场景未知, 先略过.
至于最后一个, QWidgetWindow
在处理UpdateRequest事件的时候会触发widget的重绘. 这个UpdateRequest事件最终来自QWindow::requestUpdate
, 是暴露给上层应用的api. 只能说Qt的设计就是如此,QWindow::requestUpdate
向本窗口发一个UpdateRequest事件,
然后派生类QWidgetWindow
在处理UpdateRequest事件的时候转调widget的重绘.