【问题标题】:How do I change the state of a QProgressBar?如何更改 QProgressBar 的状态?
【发布时间】:2018-09-26 18:39:24
【问题描述】:

我有一个自定义对话框,它模仿和修饰QProgressDialog 并使用一些额外的特定于应用程序的信息,并允许暂停/恢复在后台运行的工作线程。最终我正在寻找的是能够改变QProgressBar 的外观以反映this question 中描述的暂停状态。

奇怪的是,QWinTaskbarProgress 从 Qt 5.2 开始似乎支持这个确切的功能,但在 Qt4 或 Qt5 中,普通的 QProgressBar 不支持。我可以在 Qt 源代码中摆弄,但我已经在 Qt 源代码中进行了研究,我无法弄清楚表单控件的实际状态是在哪里查询/提供的,所以我想不通出我需要改变的东西。也许它不存在,因为这严格来说是 Windows 的东西,但也许不是?

使用 CSS 覆盖 StyleSheet as recommended in the docs(和 here)会导致进度条非常难看,与 Windows 7 的进度条外观完全不同。

正常:

样式表:

我不想使用这个选项。

【问题讨论】:

  • 是的,您在 Windows 7+ 上找不到绘制任务栏进度条的代码的原因是因为它是 Windows 的功能,而不是 Qt - 它是 ITaskBarList3 界面的一部分.
  • 我确实看到了。我想我认为在 Qt src 深处使用的 Windows/vc++ 控件对象上发生了类似的事情。

标签: c++ windows qt qt4 qt5


【解决方案1】:

简单的方法是将QGraphicsColorizeEffect设置为进度条。

像这样:

QProgressBar* progress = new QProgressBar;
progress->setGraphicsEffect(new QGraphicsColorizeEffect);

Win7 上的结果:

嗯...结果看起来不错,但我们可以做得更好,只需更改块颜色。

这是最终结果:

重新实现QGraphicsEffect::draw以指定和自定义着色效果区域:

class Colorize : public QGraphicsEffect {
public:
    explicit Colorize(QObject *parent = Q_NULLPTR) :
        QGraphicsEffect(parent),
        strength(1),
        color(Qt::red),
        effectRect()
    { }
    quint32 strength;
    QColor color;
    QRectF effectRect;

protected:
    void draw(QPainter* painter) {
        QPoint offset;
        const QPixmap pixmap = sourcePixmap(Qt::LogicalCoordinates, &offset);
        draw(painter, offset, pixmap, QRect());
    }

    void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const
    {
        if (src.isNull())
            return;

        QImage srcImage;
        QImage destImage;

        if (srcRect.isNull()) {
            srcImage = src.toImage();
            srcImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
            destImage = QImage(srcImage.size(), srcImage.format());
        } else {
            QRect rect = srcRect.toAlignedRect().intersected(src.rect());

            srcImage = src.copy(rect).toImage();
            srcImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
            destImage = QImage(rect.size(), srcImage.format());
        }
        destImage.setDevicePixelRatio(src.devicePixelRatioF());

        // do colorizing
        QPainter destPainter(&destImage);
        grayscale(srcImage, destImage, srcImage.rect());
        destPainter.setCompositionMode(QPainter::CompositionMode_Screen);
        destPainter.fillRect(effectRect, color);
        destPainter.end();

        // alpha blending srcImage and destImage
        if(0 < strength && strength < 1){
            QImage buffer = srcImage;
            QPainter bufPainter(&buffer);
            bufPainter.setOpacity(strength);
            bufPainter.drawImage(0, 0, destImage);
            bufPainter.end();
            destImage = buffer;
        }

        if (srcImage.hasAlphaChannel())
            destImage.setAlphaChannel(srcImage.alphaChannel());

        painter->drawImage(dest, destImage);
    }
}; 

计算进度条的格子矩形:

QRectF getGrooveRect() const {
    StyleOptionProgressBar option;
    option.initFrom(this); // this ⇒ progress bar
    return style()->subElementRect(QStyle::SE_ProgressBarGroove, &option, this);
}

...

class StyleOptionProgressBar : public QStyleOptionProgressBar {
public:
    using QStyleOptionProgressBar::QStyleOptionProgressBar;

    void initFrom(const ColorizeProgressBar* w) {
        init(w);
        minimum = w->minimum();
        maximum = w->maximum();
        progress = w->value();
        text = w->text();
        textAlignment = w->alignment();
        textVisible = w->isTextVisible();
        orientation = w->orientation();
        invertedAppearance = w->invertedAppearance();
    }
};

Github 上的完整源代码。

顺便说一句,推荐Qt source code

【讨论】:

  • 将 GraphicsEffect 应用于进度条,隐藏其文本并添加一个新标签(不受 GraphicsEffect 影响)以显示百分比不是更容易吗?并不是说这不是 draw() 函数的好例子。
  • @TheSHEEEP 我想过删除文本,但 GraphicsEffect 改变了进度条的整个颜色(块 + 背景)。
  • 是的……难道没有办法只获得条形图的填充部分吗?不过可能是私有财产...
  • 第一个使用QGraphicsColorizeEffectQt::darkGray 的选项现在将实现所需的最终目标(即,给出停止的外观),除非出现更简单的将其重新着色为黄色的选项。这是我能找到的唯一更改颜色的方法,因为进度条颜色由(不可编辑?)动画控制。
  • @Jiu 我认为您可以使用内置函数使用progressBar-&gt;style()-&gt;subElementRect(SE_ProgressBarContents, opt, progressBar) 计算块大小。唯一要注意的是必须从 QProgressBar 子类中完成才能访问initStyleOption()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 1970-01-01
  • 2017-08-24
相关资源
最近更新 更多