首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Qt 重绘事件残留旧内容?paintEvent 必须配合背景擦除

     編輯:程式設計綜合問答

问题现象

在 paintEvent 中绘制文本,首次正常,后续 update() 触发重绘时,旧文本未清除导致重叠:

void MyWidget::paintEvent(QPaintEvent *event) {
    QPainter painter(this);
    for (int i = 0; i < statListString.count(); ++i) {
        painter.drawText(0, 90 + 16 * i, statListString.at(i));
    }
}

首次绘制正常 → 二次重绘残留

根本原因

Qt 默认不自动擦除背景。paintEvent 仅在当前脏矩形区域绘制,未绘制区域保留像素。文本绘制不覆盖背景,导致旧像素残留。

三种修复方案

方案一:手动擦除背景(推荐,性能最优)

void MyWidget::paintEvent(QPaintEvent *event) {
    QPainter painter(this);
    // 1. 擦除整个控件区域(或仅脏矩形 event->rect())
    painter.fillRect(rect(), palette().window()); // 使用调色板背景色
    // painter.eraseRect(event->rect()); // 仅擦除脏区
    
    // 2. 绘制新内容
    for (int i = 0; i < statListString.count(); ++i) {
        painter.drawText(0, 90 + 16 * i, statListString.at(i));
    }
}

方案二:启用自动填充背景

MyWidget::MyWidget(QWidget *parent) : QWidget(parent) {
    setAttribute(Qt::WA_OpaquePaintEvent); // 标记不透明,Qt 自动填充背景
    // 或 setAutoFillBackground(true); 配合 palette 设置
}

配合 setPalette() 设置背景色可避免闪烁。

方案三:绘制到 QPixmap 再整体渲染(双缓冲)

void MyWidget::paintEvent(QPaintEvent *event) {
    static QPixmap cache; // 缓存绘制结果
    if (cache.isNull() || cache.size() != size()) {
        cache = QPixmap(size());
    }
    
    QPainter cachePainter(&cache);
    cachePainter.fillRect(rect(), Qt::white);
    for (int i = 0; i < statListString.count(); ++i) {
        cachePainter.drawText(0, 90 + 16 * i, statListString.at(i));
    }
    
    QPainter widgetPainter(this);
    widgetPainter.drawPixmap(0, 0, cache);
}

方案对比

方案性能闪烁风险适用场景
手动 fillRect高低简单绘制、高频刷新
WA_OpaquePaintEvent高低纯色背景、标准控件
QPixmap 缓存中(首次开销大)无复杂绘制、抗锯齿文本

最佳实践建议

  • 优先使用 WA_OpaquePaintEvent + setAutoFillBackground(true)
  • 复杂场景采用 QPixmap 离屏渲染
  • 避免在 paintEvent 中做耗时计算,预计算好几何数据
  • 使用 QStyleOption 适配主题样式
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved