qt repaint 用法_qt的update与repaint

一直搞不明白,qt的update与repaint的区别。虽然文档上说得貌似很明了了。但是,不看看源码,用着用着就迷糊了。今天看了下下相关的源码,记下自己的一点心得的。

1、update到paintEvent的调用

唉,貌似道路很曲折呀~

void QWidget::update(const QRect &rect)

{

if (!isVisible() || !updatesEnabled() || rect.isEmpty())

return;

if (testAttribute(Qt::WA_WState_InPaintEvent)) {

QApplication::postEvent(this, new QUpdateLaterEvent(rect));

return;

}

if (hasBackingStoreSupport()) {//这个函数在windows下总是返回true

QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();

if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore)

tlwExtra->backingStore->markDirty(rect, this); // 这里只是标志了一下无效区。

} else {

d_func()->repaint_sys(rect);

}

}

如上,qt 的update函数只是通过markDirty()把无效区放到了一个叫做QWidgetBackingStore对象里面去了。其实呢,markDirty这个函数里面是大有文章的,看一下就知道

void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget, bool updateImmediately,

bool invalidateBuffer)

{

// 略去与代码分析无关的东东了

#ifndef QT_NO_GRAPHICSEFFECT

widget->d_func()->invalidateGraphicsEffectsRecursively();// 这个东西有什么用呢?还没去细看。

#endif //QT_NO_GRAPHICSEFFECT

// 某些特殊情况下,直接UpdateRequest新事件。注意下QWidget的这个属性WA_PaintOnScreen

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;

}

// 如果总是要整体更新的话,就没有必要缓存无效区了吧。直接发UpdateRequest事件的

if (fullUpdatePending) {

if (updateImmediately)

sendUpdateRequest(tlw, updateImmediately);

return;

}

if (!windowSurface->hasPartialUpdateSupport()) {

fullUpdatePending = true;

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,已经是无效的了,即刻发UpdateRequest事件的

}

// 隐藏窗口时,此值为true

if (invalidateBuffer) {

const bool eventAlreadyPosted = !dirty.isEmpty();

dirty += translatedRect;

if (!eventAlreadyPosted || updateImmediately)

sendUpdateRequest(tlw, updateImmediately);

return;

}

// 如果之前没有无效窗口,把窗口加上去,并发一个UpdateRequest事件

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);// 加上一个无效窗口

}

// 如果需要立即更新的话,就发UpdateRequest事件的。这里就是update与repaint的区别所在了。再看下面repaint函数, 其传进来的参数是为true的。

if (updateImmediately)

sendUpdateRequest(tlw, updateImmediately);

}

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()) {

QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();

if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) {

tlwExtra->inRepaint = true;

tlwExtra->backingStore->markDirty(rect, this, true);// 第三个参数为真,于是可以立即通过markDirty函数发送一个

//UpdateRequest事件出去的

tlwExtra->inRepaint = false;

}

} else {

d->repaint_sys(rect);

}

}

好吧,看到这里才知道,所谓的更新,也只不过是发个更新事件而已,如下:

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

}

} 至于事件是怎么调到paintEvent的,这个就是事件响应机制的问题了。好吧,先打住的,貌似已经贴了不少代码的。 后面更新,是依次调用 了QWidgetPrivate::syncBackingStore(const QRegion &region) >> QWidgetBackingStore::sync()。于是,把缓存的无效区给绘制出来了。sync()函数里面的东西也不少,累了,以后再细看的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值