QT圆形加载进度条

QT圆形加载进度条

如果出现VIP浏览或者其它的限制,请联系我,我解除限制。

运行环境和编译工具如下:

效果图

LoadingWidgets.h

cpp 复制代码
#ifndef LOADINGWIDGETS_H
#define LOADINGWIDGETS_H

#include <QWidget>
#include <QPainter>
#include <QTimer>
#include <QLabel>
#include <QVBoxLayout>

// --- 组件 1: 旋转的渐变圆环 ---
class ProgressRing : public QWidget {
    Q_OBJECT
public:
    explicit ProgressRing(QWidget *parent = nullptr);

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    qreal m_angle; // 旋转角度
    QTimer *m_timer;
};

// --- 组件 2: Loading 弹窗 ---
class LoadingBox : public QWidget {
    Q_OBJECT
public:
    explicit LoadingBox(QWidget *parent = nullptr);

    // 专门的显示函数,自动计算居中位置
    void showCentered();

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    ProgressRing *m_ring;
    QLabel *m_lblCenterText;
    QLabel *m_lblSubTitle;
};

#endif // LOADINGWIDGETS_H

LoadingWidgets.cpp

cpp 复制代码
#include "LoadingWidgets.h"
#include <QApplication>
#include <QScreen>
#include <QDebug>

// ================= ProgressRing 实现 =================

ProgressRing::ProgressRing(QWidget *parent) : QWidget(parent), m_angle(0) {
    // 强制固定大小,防止被布局压缩看不见
    setFixedSize(100, 100); 
    
    m_timer = new QTimer(this);
    connect(m_timer, &QTimer::timeout, this, [=]() {
        m_angle += 10; // 加快一点速度
        if (m_angle >= 360) m_angle = 0;
        update();
    });
    m_timer->start(30); 
}

void ProgressRing::paintEvent(QPaintEvent *event) {
    Q_UNUSED(event);
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);

    int width = this->width();
    int height = this->height();
    int side = qMin(width, height);
    int radius = side / 2 - 10; 

    // 坐标系移到中心
    p.translate(width / 2, height / 2);
    p.rotate(m_angle); // 旋转坐标系

    // 定义锥形渐变 (QConicalGradient)
    // 中心点(0,0),起始角度 -90度(让颜色从顶部开始)
    QConicalGradient gradient(0, 0, -90);
    gradient.setColorAt(0, QColor(46, 204, 113));     // 头部:亮绿色
    gradient.setColorAt(0.2, QColor(46, 204, 113));   
    gradient.setColorAt(0.5, QColor(64, 158, 255));   // 中段:蓝色
    gradient.setColorAt(1, QColor(64, 158, 255, 0));  // 尾部:完全透明

    QPen pen(gradient, 8); // 线宽8
    pen.setCapStyle(Qt::RoundCap);
    p.setPen(pen);
    p.setBrush(Qt::NoBrush);

    // 绘制整个圆,因为渐变本身包含了透明度,所以画满圆就有拖尾效果
    p.drawEllipse(QPoint(0, 0), radius, radius);
}

// ================= LoadingBox 实现 =================

LoadingBox::LoadingBox(QWidget *parent) : QWidget(parent) {
    setFixedSize(260, 220);
    // FramelessWindowHint 去掉标题栏
    // Dialog 保证它是独立的窗口层级(不会被父窗口裁剪)
    setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
    setAttribute(Qt::WA_TranslucentBackground);
    setAttribute(Qt::WA_DeleteOnClose, false); // 关闭时不自动销毁,方便重复使用

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setContentsMargins(0, 30, 0, 20);
    layout->setSpacing(15);

    // 1. 圆环区域
    // 使用一个中间容器来居中圆环
    QWidget *ringContainer = new QWidget(this);
    ringContainer->setFixedSize(100, 100);
    
    // 圆环
    m_ring = new ProgressRing(ringContainer); 
    m_ring->move(0, 0); // 在容器内左上角对齐(也就是(0,0)到(100,100))

    // 中间文字 "登录中"
    m_lblCenterText = new QLabel("登录中", ringContainer);
    m_lblCenterText->setGeometry(0, 0, 100, 100);
    m_lblCenterText->setAlignment(Qt::AlignCenter);
    m_lblCenterText->setStyleSheet("color: #409EFF; font-weight: bold; font-size: 14px;");

    // 添加到主布局并居中
    layout->addWidget(ringContainer, 0, Qt::AlignCenter);

    // 2. 底部提示文字
    m_lblSubTitle = new QLabel("正在验证用户信息...", this);
    m_lblSubTitle->setAlignment(Qt::AlignCenter);
    m_lblSubTitle->setStyleSheet("color: #666; font-size: 13px;");
    layout->addWidget(m_lblSubTitle);
}

void LoadingBox::showCentered() {
    QWidget *p = this->parentWidget();
    if (p) {
        // 核心修正:获取父窗口在【屏幕】上的中心点
        QPoint parentCenter = p->mapToGlobal(p->rect().center());
        // 计算 Loading 窗口左上角位置
        int x = parentCenter.x() - this->width() / 2;
        int y = parentCenter.y() - this->height() / 2;
        this->move(x, y);
    } else {
        // 没有父窗口则居中于屏幕
        QRect screenGeometry = QApplication::primaryScreen()->geometry();
        int x = (screenGeometry.width() - this->width()) / 2;
        int y = (screenGeometry.height() - this->height()) / 2;
        this->move(x, y);
    }
    this->show();
}

void LoadingBox::paintEvent(QPaintEvent *event) {
    Q_UNUSED(event);
    QPainter p(this);
    p.setRenderHint(QPainter::Antialiasing);

    // 绘制圆角背景
    p.setBrush(QColor(255, 255, 255, 240)); // 白色,微透明
    p.setPen(Qt::NoPen);
    p.drawRoundedRect(this->rect(), 12, 12);
    
    // 绘制边框阴影效果可以增加 QGraphicsDropShadowEffect,这里简单画个细边框
    p.setBrush(Qt::NoBrush);
    p.setPen(QPen(QColor(230, 230, 230), 1));
    p.drawRoundedRect(this->rect().adjusted(0,0,-1,-1), 12, 12);
}

main.cpp

cpp 复制代码
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QTimer>
#include "LoadingWidgets.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    // 1. 主窗口
    QWidget loginWindow;
    loginWindow.setWindowTitle("系统登录");
    loginWindow.resize(400, 300);

    QVBoxLayout *layout = new QVBoxLayout(&loginWindow);
    QPushButton *btnLogin = new QPushButton("点击登录", &loginWindow);
    btnLogin->setFixedHeight(50);
    layout->addStretch();
    layout->addWidget(btnLogin);
    layout->addStretch();

    // 2. 创建 Loading 对象,指定 loginWindow 为父对象
    LoadingBox *loading = new LoadingBox(&loginWindow);

    // 3. 按钮点击事件
    QObject::connect(btnLogin, &QPushButton::clicked, [&]() {

        // A. 显示 Loading (会自动计算位置)
        loading->showCentered();

        // B. 【模拟业务逻辑】
        // 警告:千万不要在这里写 Sleep(3000)!那会卡死动画。
        // 实际开发中,这里应该是发送网络请求,或者启动一个线程。
        // 这里我们用 QTimer::singleShot 模拟 "3秒后登录成功"

        QTimer::singleShot(3000, [&]() {
            // 3秒后执行的代码:
            loading->hide(); // 隐藏 Loading
            // 可以在这里跳转主界面...
        });

    });

    loginWindow.show();
    return a.exec();
}
相关推荐
3824278272 小时前
汇编:条件汇编、
前端·汇编·数据库
啊董dong2 小时前
noi-2025年12月16号作业
数据结构·c++·算法·noi
white-persist2 小时前
【攻防世界】reverse | simple-check-100 详细题解 WP
c语言·开发语言·汇编·数据结构·c++·python·算法
A0_張張2 小时前
记录一个PDF盖章工具(PyQt5 + PyMuPDF)
开发语言·python·qt·pdf
欧特克_Glodon3 小时前
C++医学图像处理经典ITK库用法详解<四>: 图像分割模块功能
c++·图像处理·图像分割·itk
仰泳的熊猫3 小时前
1083 List Grades
数据结构·c++·算法·pat考试
蜘蛛小助理3 小时前
研发团队效率神器:手把手教你用蜘蛛表格构建自动化任务管理中枢
数据库·自动化·任务管理·多维表格·蜘蛛表格
淼淼7633 小时前
工厂方法模式
开发语言·c++·windows·qt·工厂方法模式
Tan_Zhixia3 小时前
时间复杂度判断
数据结构·c++·算法