我们在使用Qt的时候,在刷新界面到底是使用update()还是repaint()?这两者有什么区别?
update()会在多次调用以后,系统会在合适的时机重绘一次,而repaint()系统会立即响应,调用多少次repaint就会重绘多少次。
以下源码来自Qt5.1.1版本
update()源码:
void QWidget::update()
{
update(rect());
}
/*! \fn void QWidget::update(int x, int y, int w, int h)
\overload
This version updates a rectangle (\a x, \a y, \a w, \a h) inside
the widget.
*/
/*!
\overload
This version updates a rectangle \a rect inside the widget.
*/
void QWidget::update(const QRect &rect)
{
if (!isVisible() || !updatesEnabled())
return;
QRect r = rect & QWidget::rect();
if (r.isEmpty())
return;
if (testAttribute(Qt::WA_WState_InPaintEvent)) {
QApplication::postEvent(this, new QUpdateLaterEvent(r));
return;
}
if (hasBackingStoreSupport()) {
#ifdef Q_WS_MAC
if (qt_widget_private(this)->isInUnifiedToolbar) {
qt_widget_private(this)->unifiedSurface->renderToolbar(this, true);
return;
}
#endif // Q_WS_MAC
QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore)
tlwExtra->backingStoreTracker->markDirty(r, this);
} else {
d_func()->repaint_sys(r);
}
}
主要关注
tlwExtra->backingStoreTracker->markDirty(r, this);
void QWidget::repaint(const QRect &rect)
{
Q_D(QWidget);
if (testAttribute(Qt::WA_WState_ConfigPending)) {
update(rect);
return;
}
if (!isVisible() || !updatesEnabled() || rect.isEmpty())
return;
if (hasBackingStoreSupport()) {
#ifdef Q_WS_MAC
if (qt_widget_private(this)->isInUnifiedToolbar) {
qt_widget_private(this)->unifiedSurface->renderToolbar(this, true);
return;
}
#endif // Q_WS_MAC
QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) {
tlwExtra->inRepaint = true;
tlwExtra->backingStoreTracker->markDirty(rect, this, true);
tlwExtra->inRepaint = false;
}
} else {
d->repaint_sys(rect);
}
}
主要关注
tlwExtra->backingStoreTracker->markDirty(rect, this, true);
可以看到update()和()函数都会修改顶层父窗口的绘制区域,那么让我们来看看markDirty都干了什么
void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately,
bool invalidateBuffer)
{
Q_ASSERT(tlw->d_func()->extra);
Q_ASSERT(tlw->d_func()->extra->topextra);
Q_ASSERT(!tlw->d_func()->extra->topextra->inTopLevelResize);
Q_ASSERT(widget->isVisible() && widget->updatesEnabled());
Q_ASSERT(widget->window() == tlw);
Q_ASSERT(!rect.isEmpty());
#ifndef QT_NO_GRAPHICSEFFECT
widget->d_func()->invalidateGraphicsEffectsRecursively();
#endif //QT_NO_GRAPHICSEFFECT
if (widget->d_func()->paintOnScreen()) {
if (widget->d_func()->dirty.isEmpty()) {
widget->d_func()->dirty = QRegion(rect);
sendUpdateRequest(widget, updateImmediately);
return;
} else if (qt_region_strictContains(widget->d_func()->dirty, rect)) {
if (updateImmediately)
sendUpdateRequest(widget, updateImmediately);
return; // Already dirty.
}
const bool eventAlreadyPosted = !widget->d_func()->dirty.isEmpty();
widget->d_func()->dirty += rect;
if (!eventAlreadyPosted || updateImmediately)
sendUpdateRequest(widget, updateImmediately);
return;
}
if (fullUpdatePending) {
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return;
}
const QRect widgetRect = widget->d_func()->effectiveRectFor(rect);
const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
if (qt_region_strictContains(dirty, translatedRect)) {
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return; // Already dirty
}
if (invalidateBuffer) {
const bool eventAlreadyPosted = !dirty.isEmpty();
dirty += translatedRect;
if (!eventAlreadyPosted || updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
return;
}
if (dirtyWidgets.isEmpty()) {
addDirtyWidget(widget, rect);
sendUpdateRequest(tlw, updateImmediately);
return;
}
if (widget->d_func()->inDirtyList) {
if (!qt_region_strictContains(widget->d_func()->dirty, widgetRect))
widget->d_func()->dirty += widgetRect;
} else {
addDirtyWidget(widget, rect);
}
if (updateImmediately)
sendUpdateRequest(tlw, updateImmediately);
}
在markDirty() 主要是干两件事:
(1)保存dirty区域:
addDirtyWidget(widget, rect);
widget->d_func()->dirty += widgetRect;
(2)发送UpdateRquest事件:
sendUpdateRequest(tlw, updateImmediately);
其中有一个非常重要的参数updateImmediately:在update()中调用markDirty()给的是默认参数false,而在repaint()中调用markDirty()时传递的是true,这就导致最终发送事件的不同。
在sendUpdateRequest()中究竟发生了什么?
static inline void sendUpdateRequest(QWidget *widget, bool updateImmediately)
{
if (!widget)
return;
if (updateImmediately) {
QEvent event(QEvent::UpdateRequest);
QApplication::sendEvent(widget, &event);
} else {
QApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
}
}
update:postEvent(),而且优先级为Qt::LowEventPriority
repiant:sendEvent()
这样看来,repaint系统会立即响应并重绘控件,但是update系统不会立即响应,而是要找合适的时机再刷新