Qt实现简单的导航进度条——自定义控件

导航进度条通过其动态的视觉效果,‌不仅提供了任务进度的实时反馈,‌还增强了用户体验的流畅性和直观性。‌"进度"的设计方式多种多样,不同种类的运用需要根据具体场景来规划具体的进度方式,一般都要在清楚了解了每个方式的设计优势时,根据自身的产品定位,再去设计体验方式,这才是正确的设计方式与流程,然后再通过这些细节来提升产品的转化率,增加产品的趣味度方为良策。

一、简述

Qt实现导航进度条控件。进度条组件提供了一种直观的方式来显示任务的进度,让用户清晰地了解任务的完成情况。

二、实现的功能

1、可设置前景色/背景色/当前值前景色/当前值背景色

2、可设置最大步数及当前第几步

3、可设置导航标签队列文字信息

三、效果
四、核心代码
1、头文件
#ifndef NAVIGATIONPROGRESSBAR_H
#define NAVIGATIONPROGRESSBAR_H

#include <QWidget>

class NavigationProgressBarPrivate;
class NavigationProgressBar : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QStringList messageList READ messageList WRITE setMessageList CONSTANT)
    Q_PROPERTY(int step READ step WRITE setStep CONSTANT)
    Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor CONSTANT)
    Q_PROPERTY(QColor currentBackgroundColor READ currentBackgroundColor WRITE setCurrentBackgroundColor CONSTANT)
    Q_PROPERTY(QColor foregroundColor READ foregroundColor WRITE setForegroundColor CONSTANT)
public:
    explicit NavigationProgressBar(QWidget *parent = nullptr);
    ~NavigationProgressBar();

    QSize sizeHint() const override;
    QSize minimumSizeHint() const override;

    void setMessageList(const QStringList &list);
    QStringList messageList() const;

    void setStep(const int step);
    int step() const;

    void setBackgroundColor(const QColor &color);
    QColor backgroundColor() const;

    void setCurrentBackgroundColor(const QColor &color);
    QColor currentBackgroundColor() const;

    void setForegroundColor(const QColor &color);
    QColor foregroundColor() const;

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    void drawBackground(QPainter *painter, const bool ok);
    void drawText(QPainter *painter, const bool ok);

    QScopedPointer<NavigationProgressBarPrivate> d;
};

#endif // NAVIGATIONPROGRESSBAR_H
2、cpp文件
#include "navigationprogressbar.h"

#include <QPainter>
#include <QDateTime>

class NavigationProgressBarPrivate{
public:
    NavigationProgressBarPrivate(QWidget *parent)
        : owner(parent){
        for(int i=0; i<maxStep; i++)
            topInfo << QString("Step%1").arg(i+1);
    }
    QWidget *owner;
    QColor backgroundColor = QColor(80, 80, 80);
    QColor foregroundColor = QColor(254, 254, 254);
    QColor currentBackgroundColor = QColor(QLatin1String("#4da1ff"));
    int maxStep = 5;
    int step = 0;
    QStringList topInfo;
    QStringList dateList;
};

NavigationProgressBar::NavigationProgressBar(QWidget *parent)
    : QWidget(parent)
    , d(new NavigationProgressBarPrivate(this))
{
}

NavigationProgressBar::~NavigationProgressBar()
{
}

QSize NavigationProgressBar::sizeHint() const
{
    return QSize(500, 100);
}

QSize NavigationProgressBar::minimumSizeHint() const
{
    return QSize(300, 75);
}

void NavigationProgressBar::setMessageList(const QStringList &list)
{
    d->topInfo = list;
    d->maxStep = list.size();
    update();
}

QStringList NavigationProgressBar::messageList() const
{
    return d->topInfo;
}

void NavigationProgressBar::setStep(const int step)
{
    if(d->step >= step || step > d->maxStep)
        return;

    int s = step - d->step;
    for(int i=0; i<s; i++)
        d->dateList.append(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
    d->step = step;
    Q_ASSERT(d->step == d->dateList.size());
    update();
}

int NavigationProgressBar::step() const
{
    return d->step;
}

void NavigationProgressBar::setBackgroundColor(const QColor &color)
{
    d->backgroundColor = color;
    update();
}

QColor NavigationProgressBar::backgroundColor() const
{
    return d->backgroundColor;
}

void NavigationProgressBar::setCurrentBackgroundColor(const QColor &color)
{
    d->currentBackgroundColor = color;
    update();
}

QColor NavigationProgressBar::currentBackgroundColor() const
{
    return d->currentBackgroundColor;
}

void NavigationProgressBar::setForegroundColor(const QColor &color)
{
    d->foregroundColor = color;
    update();
}

QColor NavigationProgressBar::foregroundColor() const
{
    return d->foregroundColor;
}

void NavigationProgressBar::paintEvent(QPaintEvent *event)
{
    QWidget::paintEvent(event);
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    drawBackground(&painter, false);
    drawText(&painter, false);
    drawBackground(&painter, true);
    drawText(&painter, true);
}

void NavigationProgressBar::drawBackground(QPainter *painter, const bool ok)
{
    //圆半径为高度一定比例,计算宽度,将宽度等分
    double w = width() / d->maxStep * 1.0;
    double h = height() / 3 * 1.0;
    double radius = qMin(w, h) / 2;
    double initX = 0;
    double initY = height() / 2.0;

    //逐个绘制连接线条
    initX = w / 2;

    int step = d->maxStep;
    int penWidth = radius / 4;
    QColor backgroundColor = d->backgroundColor;
    if(ok){
        step = d->step;
        penWidth = radius / 8;
        backgroundColor = d->currentBackgroundColor;
        radius = radius / 7 * 6;
    }

    QPen pen(backgroundColor);
    pen.setWidthF(penWidth);
    pen.setCapStyle(Qt::RoundCap);
    painter->setPen(pen);
    painter->setBrush(Qt::NoBrush);

    for (int i = 0; i < step - 1; i++) {
        painter->drawLine(QPoint(initX, initY), QPoint(initX + w, initY));
        initX += w;
    }

    if(ok && (d->step > 0) && (d->step < d->maxStep))
        painter->drawLine(QPoint(initX, initY), QPoint(initX + w / 2, initY));

    //逐个绘制圆
    initX = w / 2;
    painter->setPen(Qt::NoPen);
    painter->setBrush(backgroundColor);

    for (int i = 0; i < step; i++) {
        painter->drawEllipse(QPointF(initX, initY), radius, radius);
        initX += w;
    }

    //逐个绘制圆中的数字
    initX = w / 2;
    QFont font("Microsoft YaHei", radius);
    painter->setFont(font);
    painter->setPen(d->foregroundColor);
    painter->setBrush(Qt::NoBrush);

    for (int i = 0; i < step; i++) {
        QRect textRect(initX - radius, initY - radius, radius * 2, radius * 2);
        painter->drawText(textRect, Qt::AlignCenter, QString::number(i + 1));
        initX += w;
    }
}

void NavigationProgressBar::drawText(QPainter *painter, const bool ok)
{
    double w = width() / d->maxStep * 1.0;
    double h = height() / 3.0;
    double initX = 0;
    double initY = 0;

    QColor color = ok? d->currentBackgroundColor: d->backgroundColor;
    painter->setFont(QFont("Microsoft YaHei", h / 4));
    painter->setPen(color);
    painter->setBrush(Qt::NoBrush);

    int step = ok ? d->step: d->maxStep;
    for (int i = 0; i < step; i++) {
        QRect textRect(initX, initY, w, h);
        painter->drawText(textRect, Qt::AlignCenter, d->topInfo.at(i));
        initX += w;
    }

    if(ok){
        initX = 0;
        initY = h * 2;
        for (int i = 0; i < step; i++) {
            QRect textRect(initX, initY, w, h);
            painter->drawText(textRect, Qt::AlignCenter, d->dateList.at(i));
            initX += w;
        }
    }
}
3、示例代码

下面是一个示例代码,演示了如何创建一个 NavigationProgressBar控件

#include "mainwindow.h"
#include "navigationprogressbar.h"

#include <QtWidgets>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    NavigationProgressBar *nav = new NavigationProgressBar(this);
    QStringList topInfo;
    topInfo << "拍下商品" << "已付款" << "卖家发货" << "确认收货" << "评价";
    nav->setMessageList(topInfo);
    QSlider *slider = new QSlider(this);
    slider->setRange(0, 5);
    connect(slider, &QSlider::valueChanged, nav, &NavigationProgressBar::setStep);

    QWidget *widget = new QWidget(this);
    QHBoxLayout *layout = new QHBoxLayout(widget);
    layout->addWidget(nav);
    layout->addWidget(slider);
    setCentralWidget(widget);
    resize(850, 150);
}

MainWindow::~MainWindow()
{
}

本示例演示了淘宝订单流程样式。控件自适应任何分辨率,可以自由调整自身大小以适应分辨率的改变,总步骤以及当前步骤都是自动计算占用区域比例,直接提供接口设置步骤对应的文字信息等,接口非常友好。

这个示例只是一个基本的实现,实际应用中可能需要更复杂的逻辑来处理实时更新和动画显示,如文字自适应大小等。

在设计技巧方面,‌主要思路如下:‌

1、清晰的反馈机制:‌采用直观的标签、‌百分比或其他可视化元素,‌使用户可以轻松识别任务的进行状态,‌建立用户对应用程序的信任度,‌并让他们感到更有控制权和参与感。‌

2、利用动画效果:‌动画效果如渐变、‌平滑过渡等,‌使进度条显得更富有生命力,‌提升用户体验,‌让进度的变化更为直观。‌

3、适配用户期望的颜色搭配:‌在UI设计中,‌色彩运用极为关键,‌通过适配用户期望的颜色搭配,‌增强进度条的吸引力和易用性。

谢谢您的阅读,希望本文对您有所启发。如果您还有任何问题或需要进一步帮助,请随时与我联系。祝您度过愉快的一天!

五、源代码下载 ​
相关推荐
可均可可4 分钟前
C++之OpenCV入门到提高004:Mat 对象的使用
c++·opencv·mat·imread·imwrite
杨荧20 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
白子寰26 分钟前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_0131 分钟前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj37 分钟前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT38 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
为将者,自当识天晓地。40 分钟前
c++多线程
java·开发语言
-Even-41 分钟前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus
小政爱学习!42 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript