QT控件--QProgressBar进度条控件使用QTimeLine时间轴实现简单加载动画特效

QProgressBar进度条,在修改了默认背景或进度条的颜色后,就没有了默认样式中加载高亮的动画效果,如果遇到后台耗时操作时,就会给用户以为软件卡住了没有进度。所以需要给进度条一个动画效果,表示操作仍在继续。
这里使用QTimeLine实现进度条的简单效果,主要是动态修改QProgressBar进度条控件的qss样式.

  • 修改默认样式

QProgressBar控件可以通过QSS修改样式,
主要使用QProgressBar {}QProgressBar::chunk{}修改样式,
例如,要实现这种效果:
请添加图片描述
只需要给进度条添加一个渐进背景,如:

QProgressBar{
background: rgba(0, 0, 0, 50);
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 50);
border-radius: 12px;
}

QProgressBar::chunk
{
border-radius: 11px;
	background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 255, 255, 255), stop:1 rgba(219, 223, 255, 255));
}

或者实现这种效果:
请添加图片描述
修改样式:

QProgressBar{
background: rgba(0, 0, 0, 50);
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 50);
border-radius: 12px;
}
QProgressBar::chunk
{
border-radius: 11px;
	
	background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));

}

其他样式或控件属性可以参考以下文章:


  • 添加动画效果

当修改了默认样式后,如果遇到操作进度停留过久,就会让人觉得是内部操作卡住了,这个时候就需要有一个QProgressBar进度条默认高亮的动画效果,表示操作仍在继续。如:
请添加图片描述
就有个循环高亮的动画,不会让人觉得进度卡住了。
在这里主要使用QTimeLine时间轴来实现多种动画特效:

  • 添加一个一直加载的动画

有时候不是所有的操作都能获取的一个具体的进度,像遍历文件列表这种,一开始也不知道有多少个文件,要实现一个进度条的效果,一般都是通过一个GIF图片循环播放来实现。
这里也可以使用QTimeLine时间轴来不停的修改QProgressBar进度条Value值,实现进度条不停的循环加载
像这种:
请添加图片描述
这种就是使用QTimeLine 设置5000毫秒内值从1到100的输出,再设置
setLoopCount(0) 不断循环;

  • 代码示例:

//! 动态加载 --不停的循环加载
class Effect_Dynamic_Loading:public QObject
{
    Q_OBJECT
public:
    Effect_Dynamic_Loading(QProgressBar* _proBar,int ms=5000);

    //! 是否开始动画效果
    void IsStartAnimation(bool bol);
public slots:
   //! 进度条的改变
   void Bar_valueChanged(int value);

private:
    //! 进度条控件
    QProgressBar* proControl=nullptr;

    //! 时间轴
    QTimeLine* timeLine=nullptr;

};

Effect_Dynamic_Loading::Effect_Dynamic_Loading(QProgressBar* _proControl,int ms)
    :proControl(_proControl)
{

    //! 时间轴动画
    timeLine = new QTimeLine(ms, _proControl); // 持续时间为5000ms
    timeLine->setFrameRange(1, 100); // 动画的百分比范围
    timeLine->setLoopCount(0);
    timeLine->setCurveShape(QTimeLine::LinearCurve);
    connect(timeLine, &QTimeLine::frameChanged, this, &Effect_Dynamic_Loading::Bar_valueChanged);

    //! 绑定到动态属性  用于进度条的开启和关闭
    proControl->setProperty("Dynamic",QVariant::fromValue(static_cast<Effect_Dynamic_Loading*>(this)));

}

void Effect_Dynamic_Loading::IsStartAnimation(bool bol)
{
    if(bol)
        timeLine->start();
    else
    {
        timeLine->stop();
        Bar_valueChanged(100);
    }
}

//! 进度条的改变
void Effect_Dynamic_Loading::Bar_valueChanged(int value)
{
    proControl->setValue(value);
    proControl->update();
}
  • 调用:

通过直接传入QProgressBar控件,绑定QTimeLine时间轴信号修改Value值,修改value值后记得刷新控件,否则在界面操作密集的时候会失去连续效果。

Effect_Dynamic_Loading* loading=new Effect_Dynamic_Loading(ui->progressBar);
loading->IsStartAnimation(true);

同时通过设置 Dynamic的动态属性,来控制进度条动画的开启关闭:

// 为了在其他控件或者方法中能控制加载开关
Effect_Dynamic_Loading* loadings=  qvariant_cast<Effect_Dynamic_Loading*>(ui->progressBar_loopload->property("Dynamic"));
if(loadings!=NULL && loadings!=nullptr)
{
    loadings->IsStartAnimation(true);
}
  • 添加一个进度切割线

使用QTimeLine将一个切割线从进度条的开头移动到结尾的渐进背景,动态修改QProgressBar进度条的样式,由于是动态计算的距离,所以在移动过程中竖线会变宽,
同时设置当QProgressBar进度条达到最大值时自动停止动画特效。

请添加图片描述

  • 代码示例:

//! 动态竖直线
//! 只要进度条不满百分百,就会一直加载特效
class Effect_Scale_Mark:public QObject
{
    Q_OBJECT
public:
     Effect_Scale_Mark(QProgressBar* _proControl);

public slots:
     //! 动态样式
     void updateValue(int frame);

     //! 进度条的改变
     //! 控制进度条的启动关闭
     void Bar_valueChanged(int value);
private:
     //! 进度条控件
     QProgressBar* proControl=nullptr;

     //! 时间轴
     QTimeLine* timeLine=nullptr;

     //! 是否被暂停
     bool IsStartRun=false;

};

Effect_Scale_Mark::Effect_Scale_Mark(QProgressBar* _proControl)
    :proControl(_proControl)
{
    //! 进度条业务值改变
    connect(_proControl, &QProgressBar::valueChanged, this, &Effect_Scale_Mark::Bar_valueChanged);
    //! 时间轴动画
    timeLine = new QTimeLine(2500, _proControl); // 持续时间为1000ms
    timeLine->setFrameRange(1, 100); // 动画的百分比范围
    timeLine->setLoopCount(0);
    timeLine->setCurveShape(QTimeLine::LinearCurve);
    connect(timeLine, &QTimeLine::frameChanged, this, &Effect_Scale_Mark::updateValue);
    timeLine->start();
    IsStartRun=true;
}


void Effect_Scale_Mark::updateValue(int frame)
{
    //    qDebug()<<"[frame] "<<frame;
    double num=qMin((double)frame/100.0,1.0);
    QString threshold=QString::number(qMin(num,1.0),'f',2);
    QString threshold1=QString::number(qMin(num+0.01,1.0),'f',2);
    QString threshold2=QString::number(qMin(num+0.02,1.0),'f',2);
    //    qDebug()<<"[threshold] "<<threshold<<" [threshold1] "<<threshold1<<" [threshold2] "<<threshold2;
    QString DefaultStyle="QProgressBar{ "
                         "border: 0px;"
                         "background-color: #EAEAEA;"
                         "border-radius: 11px;"
                         "}"
                         "QProgressBar::chunk"
                         "{"
                         "border-radius: 11px;"
                         "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
                         " stop:0 rgba(240, 33, 33, 255),"
                         " stop:"+threshold+" rgba(240, 33, 33, 255), "
                                            " stop:"+threshold1+" rgba(255, 255, 255, 255), "
                                                                " stop:"+threshold2+" rgba(236, 99, 76, 255), "
                                                                                    " stop:1 rgba(236, 99, 76, 255)); "
                                                                                    "}";

    proControl->setStyleSheet(DefaultStyle);
}


void Effect_Scale_Mark::Bar_valueChanged(int value)
{
    if(value==proControl->maximum())
    {
        if(IsStartRun)
        {
            timeLine->stop();
            QString DefaultStyle="QProgressBar{ "
                                 "border: 0px;"
                                 "background-color: #EAEAEA;"
                                 "border-radius: 11px;"
                                 "}"
                                 "QProgressBar::chunk"
                                 "{"
                                 "border-radius: 11px;"
                                 "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0,"
                                 " stop:0 rgba(240, 33, 33, 255),"
                                 " stop:1 rgba(236, 99, 76, 255)); "
                                 "}";
            proControl->setStyleSheet(DefaultStyle);
            IsStartRun=false;
        }
    }
    else
    {
        if(!IsStartRun)
        {
            timeLine->start();
            IsStartRun=true;
        }

    }
}

  • 调用:

每一个动画特效都是单个的QOBJECT对象,只需要在窗体初始化时声明对象就可以了。不需要重写QProgressBar控件。

    Effect_Scale_Mark* mark=new Effect_Scale_Mark(ui->progressBar);
  • 添加一个炫彩进度特效

这个旋转进度条特效本质上也是QTimeLine时间轴不停循环了一个颜色的数组,
动态修改了QProgressBar进度条控件的样式:请添加图片描述

  • 代码示例:

//! 旋转样式特效
class Effect_Kaleidoscope:public QObject
{
    Q_OBJECT

    /*! 默认样式
    QProgressBar{
    background: rgba(0, 0, 0, 50);
    border-radius: 4px;
    border: 1px solid rgba(0, 0, 0, 50);
    border-radius: 12px;
    }
    QProgressBar::chunk
    {
    border-radius: 11px;
    background-color: qconicalgradient(cx:0, cy:0, angle:135,
    stop:0 rgba(255, 255, 0, 69),
    stop:0.375 rgba(255, 255, 0, 69),
    stop:0.423533 rgba(251, 255, 0, 145),
    stop:0.45 rgba(247, 255, 0, 208),
    stop:0.477581 rgba(255, 244, 71, 130),
    stop:0.518717 rgba(255, 218, 71, 130),
    stop:0.55 rgba(255, 255, 0, 255),
    stop:0.57754 rgba(255, 203, 0, 130),
    stop:0.625 rgba(255, 255, 0, 69),
    stop:1 rgba(255, 255, 0, 69));
    }
    */

    QStringList colorList;
public:
     Effect_Kaleidoscope(QProgressBar* _proControl);

     //! 动画效果的开关
     void IsStartAnimation(bool bol);
public slots:
     //! 动态样式
     void updateValue(int frame);

private:
     //! 进度条控件
     QProgressBar* proControl=nullptr;

     //! 时间轴
     QTimeLine* timeLine=nullptr;
};

Effect_Kaleidoscope::Effect_Kaleidoscope(QProgressBar* _proControl)
    :proControl(_proControl)
{

    //! 时间轴动画
    timeLine = new QTimeLine(500, _proControl); // 持续时间为1000ms
    timeLine->setLoopCount(0);
    timeLine->setCurveShape(QTimeLine::LinearCurve);
    connect(timeLine, &QTimeLine::frameChanged, this, &Effect_Kaleidoscope::updateValue);

    colorList<<"rgba(255, 255, 0, 69)";
    colorList<<"rgba(251, 255, 0, 145)";
    colorList<<"rgba(247, 255, 0, 208)";
    colorList<<"rgba(255, 244, 71, 130)";

    colorList<<"rgba(255, 218, 71, 130)";
    colorList<<"rgba(255, 255, 0, 255)";
    colorList<<"rgba(255, 203, 0, 130)";
    colorList<<"rgba(255, 255, 0, 69)";

    timeLine->setFrameRange(1, colorList.count()); // 动画的范围


}

void Effect_Kaleidoscope::IsStartAnimation(bool bol)
{
    if(bol)
        timeLine->start();
    else
    {
        timeLine->stop();
    }
}

void Effect_Kaleidoscope::updateValue(int frame)
{
    int threshold_value=colorList.count();
    int index=frame-1;
    auto getV=[&](int& _index,int max)->int{
        if(_index+1==max)
            _index=0;
        else
            _index++;
        return _index;
    };


    QString diffqss=" QProgressBar{ "
            "background: rgba(0, 0, 0, 50);"
            "border-radius: 4px;"
            "border: 1px solid rgba(0, 0, 0, 50);"
            "border-radius: 12px;"
            "}"
            "QProgressBar::chunk"
            "{"
            "border-radius: 11px;"
            "background-color: qconicalgradient(cx:0, cy:0, angle:135,"
            "stop:0 "+colorList[index]+","
            "stop:0.375 "+colorList[index]+","
            "stop:0.423533 "+colorList[getV(index,threshold_value)]+","
            "stop:0.45 "+colorList[getV(index,threshold_value)]+","
            "stop:0.477581 "+colorList[getV(index,threshold_value)]+","
            "stop:0.518717 "+colorList[getV(index,threshold_value)]+","
            "stop:0.55 "+colorList[getV(index,threshold_value)]+","
            "stop:0.57754 "+colorList[getV(index,threshold_value)]+","
            "stop:0.625 "+colorList[getV(index,threshold_value)]+","
            "stop:1 "+colorList[index]+");"
            "}";
    proControl->setStyleSheet(diffqss);
    proControl->update();
}
  • 调用:

调用的同时,启动动画效果,这里也可以设置QProgressBar控件的动态属性来控制动画的开启关闭,只是这里没加。

    Effect_Kaleidoscope* Kaleid=new Effect_Kaleidoscope(ui->progressBar_4);
    Kaleid->IsStartAnimation(true);
下面是多线程 QProgressBar 实现进度条的示例代码: ```python from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtWidgets import QApplication, QWidget, QProgressBar, QPushButton, QVBoxLayout import time class Worker(QThread): progress_updated = pyqtSignal(int) def run(self): for i in range(101): time.sleep(0.1) self.progress_updated.emit(i) class MainWindow(QWidget): def __init__(self): super().__init__() self.progress_bar = QProgressBar() self.start_button = QPushButton("Start") self.start_button.clicked.connect(self.start_worker) layout = QVBoxLayout() layout.addWidget(self.progress_bar) layout.addWidget(self.start_button) self.setLayout(layout) self.worker = Worker() self.worker.progress_updated.connect(self.update_progress) def start_worker(self): self.worker.start() def update_progress(self, value): self.progress_bar.setValue(value) if __name__ == "__main__": app = QApplication([]) main_window = MainWindow() main_window.show() app.exec_() ``` 在这个示例中,我们创建了一个 `Worker` 类,它继承自 `QThread` 类。在 `Worker` 类中,我们定义了一个 `progress_updated` 信号,用于在进度更新时发射信号。在 `run` 方法中,我们使用一个循环模拟了一个长时间的任务,并且在每次循环中都让线程休眠了一小段时间。在循环中,我们发射了 `progress_updated` 信号,并且将当前进度作为参数传递。 在 `MainWindow` 类中,我们创建了一个 `QProgressBar` 控件和一个 `QPushButton` 控件,用于启动线程。当用户点击 `Start` 按钮时,我们启动了 `Worker` 线程。我们还定义了一个 `update_progress` 方法,用于更新进度条的值。在 `MainWindow` 类的构造函数中,我们连接了 `Worker` 的 `progress_updated` 信号到 `update_progress` 方法。 最后,我们创建了一个 `QApplication` 实例,并且创建了一个 `MainWindow` 实例并显示。当用户关闭窗口时,`app.exec_()` 方法会返回并退出应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

得鹿梦鱼、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值