Qt自定义QLabel做一个倒计时控件(带有圆环形进度条)


简述

记录和分享自己写的一个倒计时小控件。通过自定义QLabel控件,重写painter事件来绘制一个倒计时控件。

一、运行效果

初始化
运行程序,初始化一个时间。点击开始后,开始倒计时,外层圆形进度条慢慢缩减。
进行中

二、上代码

mylabel.h

代码如下(示例):

#ifndef MYLABEL_H
#define MYLABEL_H

#include <QObject>
#include <QLabel>
#include <QPainter>
class MyLabel : public QLabel
{
    Q_OBJECT

public:
    MyLabel(QWidget *parent = Q_NULLPTR);
    ~MyLabel();
public:
    //计时器更新 倒计时
    void setTime(double second);
signals:

public slots:

protected:
    void paintEvent(QPaintEvent *);
    virtual bool event(QEvent *e);

private:
    void drawTimer(QPainter *);//画计时器
private:
    double m_time;//倒计时时间
};
#endif // MYLABEL_H

mylabel.cpp

代码如下(示例):

#include "mylabel.h"
#include<QDebug>

#pragma execution_character_set("utf-8")

MyLabel::MyLabel(QWidget *parent)
    :QLabel (parent)
{

}

MyLabel::~MyLabel()
{

}

void MyLabel::setTime(double second)
{
    m_time = second;
    update();
}

//重写paint事件
void MyLabel::paintEvent(QPaintEvent *e)
{
    Q_UNUSED(e);

    QPainter painter(this);
    //设置抗锯齿
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);

    drawTimer(&painter);
}

bool MyLabel::event(QEvent *e)
{
    return QLabel::event(e);
}

void MyLabel::drawTimer(QPainter *p)
{
    //先设置外矩形的大小用于绘制圆形进度条
    QRect rcOut = this->rect();
    //adjust四个参数:dx1,dy1相对于左上角的点,dx2,dy2相对于右下角的点
    rcOut.adjust(10,10,-10,-10);
    QSize outSize = rcOut.size();
    //获取这个矩形的左上角坐标
    int out_X = rcOut.x();
    int out_Y = rcOut.y();

    //设置内矩形的大小用于绘制时间
    QRect rcInt = this->rect();
    rcInt.adjust(20,90,-20,-90);
    QSize inSize = rcInt.size();
    int in_X = rcInt.x();
    int in_Y = rcInt.y();

    //画内矩形
    //画矩形边框色,同主界面的背景色,不同的话会有出现一个长方形矩形
    p->setPen(QPen(QColor(68,85,123), 1, Qt::SolidLine));
    //绘制矩形
    p->drawRect(rcInt);

    //绘制时间
    //设置画笔样式
    QFont font;
    //大小根据主界面label的大小调整
    font.setPointSize(45);
    p->setFont(font);
    QPen pen;
    pen.setColor(QColor("#ffffff"));
    pen.setWidth(1);
    pen.setStyle(Qt::SolidLine);
    p->setPen(pen);

    QString timer;
    if(m_time == 0)
    {
        timer = "00:00";
        //绘制文字,用内矩形的size,文字居中
        p->drawText(in_X,in_Y,inSize.width(),inSize.height(),Qt::AlignVCenter |Qt::AlignHCenter,timer);
    }
    else {
        int time = m_time/100+1; //加1是因为小于100时就是0了,但是绘制还未结束
        timer = "00:" + QString::number(time);
        if(time < 10)
        {
            timer = "00:0" + QString::number(time);
        }
        p->drawText(in_X,in_Y,inSize.width(),inSize.height(),Qt::AlignVCenter |Qt::AlignHCenter,timer);
    }

    //绘制圆形进度条
    //QLinearGradient  参数:渐变的开始坐标,渐变的结束坐标
    QLinearGradient gradient(out_X, out_Y, outSize.height(), out_Y);//左右渐变
    //QLinearGradient gradient(out_X, out_Y, out_X, outSize.height()+out_Y);//上下渐变
    gradient.setColorAt(0, QColor("#E3521B"));
    gradient.setColorAt(1.0, QColor("#8BE31B"));

    int startAngle = 90*16;                 //开始的角度,0度在图形的最左侧
    int spanAngle = m_time/8000*(-360*16);  //覆盖的角度

    QPen penForeground;
    penForeground.setBrush(gradient);
    penForeground.setWidth(15);
    penForeground.setJoinStyle(Qt::RoundJoin);
    penForeground.setCapStyle(Qt::RoundCap);
    p->setPen(penForeground);
    //绘制圆环,用到外圈的size
    p->drawArc(rcOut, startAngle, spanAngle);
}

TimerWidget.h

#ifndef TIMERWIDGET_H
#define TIMERWIDGET_H

#include <QWidget>

class QTimer;

namespace Ui {
class TimerWidget;
}

class TimerWidget : public QWidget
{
    Q_OBJECT

public:
    explicit TimerWidget(QWidget *parent = nullptr);
    ~TimerWidget();
    //初始化
    void initForm();
private slots:
    void on_m_startBtn_clicked();
    void timeEnd();
private:
    Ui::TimerWidget *ui;
    double m_time;//时间
    QTimer *m_timer;//定时器,用于给计时器发送时间
};

#endif // TIMERWIDGET_H

TimerWidget.cpp

#include "TimerWidget.h"
#include "ui_TimerWidget.h"
#include <QTimer>

TimerWidget::TimerWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TimerWidget)
{
    ui->setupUi(this);
    initForm();
    connect(m_timer,&QTimer::timeout,this,&TimerWidget::timeEnd);
}

TimerWidget::~TimerWidget()
{
    delete ui;
}

//初始化
void TimerWidget::initForm()
{
    //设置背景色,qss
    QString strStyle = "QWidget#TimerWidget{background-color:rgb(68,85,123);}";
    setStyleSheet(strStyle);

    setFixedSize(300,300);
    ui->m_timer->setFixedSize(250,250);
    ui->m_startBtn->setText("开始");
    m_timer = new QTimer(this);
    m_time = 7999;
    ui->m_timer->setTime(m_time);
}

//开始
void TimerWidget::on_m_startBtn_clicked()
{
    //每10毫秒执行一次
    //每10毫秒刷新一次为了让进度条更流畅
    m_timer->start(10);
}

void TimerWidget::timeEnd()
{
    //如果小于0停止计时
    if(m_time < 0)
    {
        m_timer->stop();
        return;
    }
    ui->m_timer->setTime(m_time);
    m_time --;
}

TimerWidget ui设计

主界面
添加一个开始按钮和一个QLabel,QLabel需要提升为mylabel,控件的提升不会的站里很多例子。
提升控件

main.cpp

#include "TimerWidget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TimerWidget w;
    w.show();
    return a.exec();
}


总结

第一次写,有很多不足之处,分享一下互相学习。
程序目的主要是实现一个圆形的进度条,带有渐变色和时间。

1. 设置控件属性 首先需要在Qt Creator中创建一个新的自定义控件,可以通过以下步骤完成: 1. 在Qt Creator中选择“File” -> “New File or Project” -> “Qt” -> “Qt Designer Form” -> “Widget” -> “Choose”。 2. 给控件一个名称,例如“TrafficLightWidget”。 3. 添加三个形的QLabel控件作为信号灯,设置它们的颜色和大小。可以使用QLabel的setStyleSheet()函数设置样式表,例如:setStyleSheet("background-color: green;border-radius: 20px;")。 4. 在Qt Creator中打开“Object Inspector”窗口,选择“TrafficLightWidget”,在“Property Editor”中添加以下属性: - int state:当前信号灯的状态,可以是0(红灯)、1(黄灯)或2(绿灯)。 - int interval:每个状态的持续时间,以毫秒为单位。 2. 实现功能 在实现交通灯控件的功能之前,需要先了解Qt的信号和槽机制。信号是对象发出的事件,槽是响应该事件的函数。可以使用connect()函数将信号和槽连接起来。 在TrafficLightWidget类中添加以下成员变量和函数: ``` private: int m_state; int m_interval; QTimer* m_timer; private slots: void onTimeout(); ``` m_state表示当前的信号灯状态,m_interval表示每个状态的持续时间,m_timer是一个计时器,用于定时改变信号灯状态。onTimeout()一个槽函数,用于处理计时器超时事件。 在TrafficLightWidget的构造函数中,初始化成员变量和计时器,并将计时器的timeout()信号连接到onTimeout()槽函数: ``` TrafficLightWidget::TrafficLightWidget(QWidget *parent) : QWidget(parent), ui(new Ui::TrafficLightWidget) { ui->setupUi(this); m_state = 0; m_interval = 3000; m_timer = new QTimer(this); connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeout())); m_timer->start(m_interval); } ``` 在onTimeout()槽函数中,根据当前的信号灯状态改变信号灯颜色,并更新m_state和计时器的间隔时间: ``` void TrafficLightWidget::onTimeout() { switch (m_state) { case 0: // 红灯 ui->redLight->setStyleSheet("background-color: red;border-radius: 20px;"); ui->yellowLight->setStyleSheet("background-color: gray;border-radius: 20px;"); ui->greenLight->setStyleSheet("background-color: gray;border-radius: 20px;"); m_state = 1; m_interval = 2000; break; case 1: // 黄灯 ui->redLight->setStyleSheet("background-color: gray;border-radius: 20px;"); ui->yellowLight->setStyleSheet("background-color: yellow;border-radius: 20px;"); ui->greenLight->setStyleSheet("background-color: gray;border-radius: 20px;"); m_state = 2; m_interval = 4000; break; case 2: // 绿灯 ui->redLight->setStyleSheet("background-color: gray;border-radius: 20px;"); ui->yellowLight->setStyleSheet("background-color: gray;border-radius: 20px;"); ui->greenLight->setStyleSheet("background-color: green;border-radius: 20px;"); m_state = 0; m_interval = 3000; break; } m_timer->start(m_interval); } ``` 3. 使用控件Qt Creator中打开一个新的窗口,将TrafficLightWidget拖动进去,设置它的大小和位置,运行程序即可看到交通灯的效果。 ``` #include "mainwindow.h" #include "ui_mainwindow.h" #include "trafficlightwidget.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); TrafficLightWidget* trafficLightWidget = new TrafficLightWidget(this); trafficLightWidget->setGeometry(50, 50, 100, 300); } MainWindow::~MainWindow() { delete ui; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

眸中yue

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

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

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

打赏作者

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

抵扣说明:

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

余额充值