You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Qt自定义ProgressBar调用setValue后paintEvent不触发无法刷新问题

问题分析与解决

首先,你的自定义QProgressBar在调用setValue()时没触发重绘,大概率是因为Qt默认的更新机制在自定义子类场景下没有正确触发paintEvent,另外你的绘制代码还有一处小bug会导致视觉异常。下面是具体的解决步骤:

1. 强制触发重绘:重写setValue方法

虽然QProgressBar::setValue()理论上会自动调用update()触发重绘,但在自定义子类中,有时会因为样式继承或内部逻辑的原因导致触发失效。我们可以手动重写setValue,确保每次值变化时强制刷新:

在头文件grafica_progressbar.h中添加声明:

public:
    void setValue(int val) Q_DECL_OVERRIDE;

在实现文件grafica_progressbar.cpp中添加实现:

void grafica_ProgressBar::setValue(int val) {
    // 先调用父类方法更新内部值
    QProgressBar::setValue(val);
    // 强制触发paintEvent
    update();
}

2. 修复绘制代码的bug

你的灰色区域绘制逻辑有误:p.drawRect(TopPos, 0, width(), height())中,矩形宽度应该是width() - TopPos,否则灰色部分会超出控件范围,导致视觉异常。修改这一行:

p.drawRect(TopPos, 0, width() - TopPos, height()); // 正确的灰色区域范围

另外,建议优化文本绘制方式,使用控件的rect()方法获取范围,比手动写坐标更可靠:

p.drawText(rect(), Qt::AlignCenter, QString::number(tmpValue) + " bar");

还可以添加抗锯齿渲染,让绘制效果更平滑:

QPainter p(this);
p.setRenderHint(QPainter::Antialiasing); // 添加这一行

3. 可选:构造函数初始化默认属性

为了让进度条初始状态更合理,可以在构造函数中设置默认的最小/最大值:

grafica_ProgressBar::grafica_ProgressBar() {
    setMinimum(0);
    setMaximum(100);
}

完整优化后的代码示例

头文件

#ifndef GRAFICA_PROGRESSBAR_H
#define GRAFICA_PROGRESSBAR_H
#include <QProgressBar>
#include <QPaintEvent>
#include <QPainter>

class grafica_ProgressBar : public QProgressBar {
    Q_OBJECT
public:
    grafica_ProgressBar();
    void setValue(int val) Q_DECL_OVERRIDE; // 重写setValue
protected:
    void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE;
};
#endif // GRAFICA_PROGRESSBAR_H

实现文件

#include "grafica_progressbar.h"

grafica_ProgressBar::grafica_ProgressBar() {
    setMinimum(0);
    setMaximum(100);
}

void grafica_ProgressBar::setValue(int val) {
    QProgressBar::setValue(val);
    update();
}

void grafica_ProgressBar::paintEvent(QPaintEvent *) {
    int tmpValue = value();
    int TopPos = QStyle::sliderPositionFromValue(minimum(), maximum(), tmpValue, width());
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);

    // 设置进度颜色
    if (tmpValue < maximum() * 0.85) {
        p.setPen(Qt::green);
        p.setBrush(Qt::green);
    } else {
        p.setPen(QColor(255,51,51));
        p.setBrush(QColor(255,51,51));
    }
    // 绘制进度条
    p.drawRect(0, 0, TopPos, height());

    // 绘制剩余灰色区域
    p.setPen(Qt::gray);
    p.setBrush(Qt::lightGray);
    p.drawRect(TopPos, 0, width() - TopPos, height());

    // 绘制文本
    p.setPen(Qt::black);
    p.drawText(rect(), Qt::AlignCenter, QString::number(tmpValue) + " bar");
}

这样修改后,每次调用setValue()都会强制触发paintEvent,进度条就能正确刷新,同时绘制的视觉效果也更准确。

内容的提问来源于stack exchange,提问作者Pierluigi Rovere

火山引擎 最新活动