您的位置:首页 > 编程语言 > Qt开发

Qt中update()和repaint()的源码分析

2016-06-08 14:44 549 查看
我们在使用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);


repaint()源码:

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);
}
}

我们看到updateImmediately参数最终影响到了事件发送的机制:

update:postEvent(),而且优先级为Qt::LowEventPriority

repiant:sendEvent()

这样看来,repaint系统会立即响应并重绘控件,但是update系统不会立即响应,而是要找合适的时机再刷新
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  qt5 c++ 源码