自定义 QProgressBar

Posted

技术标签:

【中文标题】自定义 QProgressBar【英文标题】:Customizing QProgressBar 【发布时间】:2016-07-29 14:23:53 【问题描述】:

我有一个日记程序,用户可以在其中创建任务,然后为它们添加休息时间。每个Task 对象都有一个QTime start_timeQTime end_timevectorBreaks。每个Break 都有一个QTime start_timeQTime end_time 成员,就像Task 一样。我想通过使用自定义QProgressBar 来显示当前任务的进度以显示“时间线”。它应该是一条绿线,由代表中断的红色块分隔,其上方的三角形表示当前进度。这是我的***画作:

要求:三角形应该每分钟左右平稳地向终点移动,而不是跳跃。它还必须根据它是在红色块上还是绿色上来改变它的颜色。该行必须可调整大小,但这不应影响tasks 或breaks 时间变量。用户不能添加多个中断时间。 现在我的问题是,这甚至可能吗?如果是,那怎么办? 我试图做一个没有中断的任务,只画一条绿线和一个没有红色块的三角形,但我立即遇到了调整大小的问题。如果线宽增加,那么三角形的“步长”也应该增加。我试图实现这一点,但没有取得太大的成功。 代码如下:

//class CustomProgressBar: public QProgressBar
void CustomProgressBar::paintEvent(QPaintEvent* event)

    setMaximum(this->width());
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);

    QPoint start_point;
    start_point.setX(0);
    start_point.setY(13);
    QPoint end_point;
    end_point.setY(13);
    end_point.setX(this->width()); //has to be resizable

    //"TimeLine"
    painter.setPen(QPen(Qt::green, 2, Qt::SolidLine, Qt::RoundCap));
    painter.drawLine(start_point, end_point);

    //Triangle
    int progress = this->value();
    QPoint triangle_start_point;
    triangle_start_point.setX(this->value() + this->width() / 15  + 1);
    triangle_start_point.setY(0);
    QPoint triangle_bot_point;
    triangle_bot_point.setX(this->value() + this->width() / 15 + 6);
    triangle_bot_point.setY(10);
    QPoint triangle_top_point;
    triangle_top_point.setX(this->value() + this->width() / 15 + 11);
    triangle_top_point.setY(0);
    QPainterPath path;
    path.moveTo(triangle_start_point);
    path.lineTo(triangle_bot_point);
    path.lineTo(triangle_top_point);
    path.lineTo(triangle_start_point);
    painter.setPen (Qt :: NoPen);
    painter.fillPath(path, QBrush(QColor (Qt::green)));

【问题讨论】:

【参考方案1】:

我调整了你的绘画事件并扩展了一些简单的格式来显示休息和跑步,看看吧。

QList<QPoint> CustomProgessBar::breaks()

    QList<QPoint> times;
    times.append(QPoint(0, 20));
    times.append(QPoint(20, 50));
    times.append(QPoint(50, 80));
    times.append(QPoint(80, 100));
    return times;


void CustomProgessBar::paintEvent(QPaintEvent *e)

    Q_UNUSED(e)
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);

    QPoint start_point;
    start_point.setX(0);
    start_point.setY(13);
    QPoint end_point;
    end_point.setY(13);
    end_point.setX(this->width());

    //"TimeLine"
    for (int i = 0; i < breaks().length(); ++i) 
        start_point.setX((int)((float)this->width() / 100 * breaks().at(i).x()));
        end_point.setX((int)((float)this->width() / 100 * breaks().at(i).y()));
        if (i % 2 == 0) 
            painter.setPen(QPen(Qt::red, 2, Qt::SolidLine, Qt::RoundCap));
         else 
            painter.setPen(QPen(Qt::green, 2, Qt::SolidLine, Qt::RoundCap));
        
        painter.drawLine(start_point, end_point);
    

    //Triangle
    QPoint triangle_start_point;
    triangle_start_point.setX((int)((float)this->width() / this->maximum() * this->value()) - 5);
    triangle_start_point.setY(0);
    QPoint triangle_bot_point;
    triangle_bot_point.setX((int)((float)this->width() / this->maximum() * this->value()) + 0);
    triangle_bot_point.setY(10);
    QPoint triangle_top_point;
    triangle_top_point.setX((int)((float)this->width() / this->maximum() * this->value()) + 5);
    triangle_top_point.setY(0);
    QPainterPath path;
    path.moveTo(triangle_start_point);
    path.lineTo(triangle_bot_point);
    path.lineTo(triangle_top_point);
    path.lineTo(triangle_start_point);
    painter.setPen (Qt :: NoPen);

    for (int i = 0; i < breaks().length(); ++i) 
        int x = (int)((float)triangle_bot_point.x() * 100 / this->width());
        if (x >= breaks().at(i).x() && x <= breaks().at(i).y() && i % 2 == 0)
            painter.fillPath(path, QBrush(QColor (Qt::red)));
        if (x >= breaks().at(i).x() && x <= breaks().at(i).y() && i % 2 == 1)
            painter.fillPath(path, QBrush(QColor (Qt::green)));
    

提到的跳跃是由于整数运算而发生的。转换为浮动和返回可修复此行为。


也不要试图将开始和停止时间紧紧地链接到图表上的开始和停止点。在提供的示例中,我有一个生成百分比值的中间步骤。

【讨论】:

尽管这可行,但它并不能满足所有要求。我肯定会尝试使用“时间轴”和三角形着色部分,但现在我不能接受这个答案。如果我想出一个使用你的代码的工作实现,我会在编辑中发布它并接受你的回答。 @7Y3RPXK3ETDCNRDD 线可调整大小,着色工作,没有啤酒花。哪些要求没有满足?而是为您提供所有课程的完整解决方案,很好地解决了您的问题,让您进一步进步。我不明白你的意思。 您的代码解决了一些问题,但不是全部。三角形表示从task.start_timetask.end_time 的进度,也就是说,它应该移动恒定的次数,但它的“步长”(它通过每个进度的像素数量)应该随线宽缩放。我还写了Breaks 有start_timeend_time 并且有一个Breaks 的向量。所以红色块的大小和数量可能会有所不同。也许我的帖子不够明确。如果是这样的话,我很抱歉混淆。但是我还是不能接受你的回答,因为问题还没有完全解决。 @7Y3RPXK3ETDCNRDD 仔细查看方法breaks,它返回一个QList,其中包含both、breaks 和progress。每个元素都有可能单独变化的开始和结束。所以这个就完成了。 paint 方法使用一些模 2 操作进行着色,因此每隔一个条目就会中断一次。这只是拥有两种状态的一些简单约定。您也可以轻松地在队列中纠缠另一个中断,请注意所选值与进度条的最大数量相匹配。同样,三角形不是直接移动一个像素,而是恰好移动QProgressBar 的一个。完成

以上是关于自定义 QProgressBar的主要内容,如果未能解决你的问题,请参考以下文章

自定义UI 自定义布局

自定义UI 自定义布局

自定义UI 自定义布局

自定义 view - 自定义属性

Springboot+自定义注解+自定义AOP前置增强+自定义异常+自定义异常捕获

Android 自定义View