Qt中update()和repaint()的源码分析
2016-06-08 14:44
549 查看
我们在使用Qt的时候,在刷新界面到底是使用update()还是repaint()?这两者有什么区别?
update()会在多次调用以后,系统会在合适的时机重绘一次,而repaint()系统会立即响应,调用多少次repaint就会重绘多少次。
以下源码来自Qt5.1.1版本
update()源码:
repaint()源码:
主要关注
可以看到update()和()函数都会修改顶层父窗口的绘制区域,那么让我们来看看markDirty都干了什么
(1)保存dirty区域:
(2)发送UpdateRquest事件:
其中有一个非常重要的参数updateImmediately:在update()中调用markDirty()给的是默认参数false,而在repaint()中调用markDirty()时传递的是true,这就导致最终发送事件的不同。
在sendUpdateRequest()中究竟发生了什么?
我们看到updateImmediately参数最终影响到了事件发送的机制:
update:postEvent(),而且优先级为Qt::LowEventPriority
repiant:sendEvent()
这样看来,repaint系统会立即响应并重绘控件,但是update系统不会立即响应,而是要找合适的时机再刷新
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系统不会立即响应,而是要找合适的时机再刷新
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 从源码安装Mysql/Percona 5.5
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- 浅析Ruby的源代码布局及其编程风格
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例