Qt:自定义一个好看的等待提示Ui控件

一、2024 永不卡顿

在这里插入图片描述

爱的魔力它转圈圈~
等待样式控件是我们在做UI时出场率还挺高的控件之一,通常情况下有如下的几种实现方式:
1> 获取一张gif的资源图,然后使用QMovie 在一个QLabel 控件上加载显示gif的waiting等待动态。
2> 自定义绘图,然后使用Qt动画,达到转圈圈的效果。本文以此方式为例,给大家一个好看的样式示例。

本篇,作为搬运工:https://github.com/snowwlex/QtWaitingSpinner

二、代码示例

使用草鸡简单,提供了一些接口,用于waiting 标签的修改。

#include <QCoreApplication>
#include <QApplication>
#include <waitingspinnerwidget.h>
#include <QFrame>
#include <QHBoxLayout>

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

	
    WaitingSpinnerWidget* spinner = new WaitingSpinnerWidget;
    /// 设置waiting组件的样式
    spinner->setRoundness(70.0);
    spinner->setMinimumTrailOpacity(15.0);
    spinner->setTrailFadePercentage(70.0);
    spinner->setNumberOfLines(12);
    spinner->setLineLength(10);
    spinner->setLineWidth(5);
    spinner->setInnerRadius(10);
    spinner->setRevolutionsPerSecond(1);
    spinner->setColor(QColor(81, 4, 71));

    spinner->start(); // gets the show on the road!


    QFrame* f = new QFrame;
    QHBoxLayout* hlayout = new QHBoxLayout;
    hlayout->addWidget(spinner);
    f->setLayout(hlayout);
    f->show();

    return a.exec();
}

具体实现代码如下:

// waitingspinnerwidget.h

/* Original Work Copyright (c) 2012-2014 Alexander Turkin
   Modified 2014 by William Hallatt
   Modified 2015 by Jacob Dawid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#pragma once

// Qt includes
#include <QWidget>
#include <QTimer>
#include <QColor>

class WaitingSpinnerWidget : public QWidget {
    Q_OBJECT
public:
    /*! Constructor for "standard" widget behaviour - use this
   * constructor if you wish to, e.g. embed your widget in another. */
    WaitingSpinnerWidget(QWidget *parent = 0,
                         bool centerOnParent = true,
                         bool disableParentWhenSpinning = true);

    /*! Constructor - use this constructor to automatically create a modal
   * ("blocking") spinner on top of the calling widget/window.  If a valid
   * parent widget is provided, "centreOnParent" will ensure that
   * QtWaitingSpinner automatically centres itself on it, if not,
   * "centreOnParent" is ignored. */
    WaitingSpinnerWidget(Qt::WindowModality modality,
                         QWidget *parent = 0,
                         bool centerOnParent = true,
                         bool disableParentWhenSpinning = true);

public slots:
    void start();
    void stop();

public:
    void setColor(QColor color);
    void setRoundness(qreal roundness);
    void setMinimumTrailOpacity(qreal minimumTrailOpacity);
    void setTrailFadePercentage(qreal trail);
    void setRevolutionsPerSecond(qreal revolutionsPerSecond);
    void setNumberOfLines(int lines);
    void setLineLength(int length);
    void setLineWidth(int width);
    void setInnerRadius(int radius);
    void setText(QString text);

    QColor color();
    qreal roundness();
    qreal minimumTrailOpacity();
    qreal trailFadePercentage();
    qreal revolutionsPersSecond();
    int numberOfLines();
    int lineLength();
    int lineWidth();
    int innerRadius();

    bool isSpinning() const;

private slots:
    void rotate();

protected:
    void paintEvent(QPaintEvent *paintEvent);

private:
    static int lineCountDistanceFromPrimary(int current, int primary,
                                            int totalNrOfLines);
    static QColor currentLineColor(int distance, int totalNrOfLines,
                                   qreal trailFadePerc, qreal minOpacity,
                                   QColor color);

    void initialize();
    void updateSize();
    void updateTimer();
    void updatePosition();

private:
    QColor  _color;
    qreal   _roundness; // 0..100
    qreal   _minimumTrailOpacity;
    qreal   _trailFadePercentage;
    qreal   _revolutionsPerSecond;
    int     _numberOfLines;
    int     _lineLength;
    int     _lineWidth;
    int     _innerRadius;

private:
    WaitingSpinnerWidget(const WaitingSpinnerWidget&);
    WaitingSpinnerWidget& operator=(const WaitingSpinnerWidget&);

    QTimer *_timer;
    bool    _centerOnParent;
    bool    _disableParentWhenSpinning;
    int     _currentCounter;
    bool    _isSpinning;
};

// waitingspinnerwidget.cpp


/* Original Work Copyright (c) 2012-2014 Alexander Turkin
   Modified 2014 by William Hallatt
   Modified 2015 by Jacob Dawid

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// Own includes
#include "waitingspinnerwidget.h"

// Standard includes
#include <cmath>
#include <algorithm>

// Qt includes
#include <QPainter>
#include <QTimer>

WaitingSpinnerWidget::WaitingSpinnerWidget(QWidget *parent,
                                           bool centerOnParent,
                                           bool disableParentWhenSpinning)
    : QWidget(parent),
      _centerOnParent(centerOnParent),
      _disableParentWhenSpinning(disableParentWhenSpinning) {
    initialize();
}

WaitingSpinnerWidget::WaitingSpinnerWidget(Qt::WindowModality modality,
                                           QWidget *parent,
                                           bool centerOnParent,
                                           bool disableParentWhenSpinning)
    : QWidget(parent, Qt::Dialog | Qt::FramelessWindowHint),
      _centerOnParent(centerOnParent),
      _disableParentWhenSpinning(disableParentWhenSpinning){
    initialize();

    // We need to set the window modality AFTER we've hidden the
    // widget for the first time since changing this property while
    // the widget is visible has no effect.
    setWindowModality(modality);
    setAttribute(Qt::WA_TranslucentBackground);
}

void WaitingSpinnerWidget::initialize() {
    _color = Qt::black;
    _roundness = 100.0;
    _minimumTrailOpacity = 3.14159265358979323846;
    _trailFadePercentage = 80.0;
    _revolutionsPerSecond = 1.57079632679489661923;
    _numberOfLines = 20;
    _lineLength = 10;
    _lineWidth = 2;
    _innerRadius = 10;
    _currentCounter = 0;
    _isSpinning = false;

    _timer = new QTimer(this);
    connect(_timer, SIGNAL(timeout()), this, SLOT(rotate()));
    updateSize();
    updateTimer();
    hide();
}

void WaitingSpinnerWidget::paintEvent(QPaintEvent *) {
    updatePosition();
    QPainter painter(this);
    painter.fillRect(this->rect(), Qt::transparent);
    painter.setRenderHint(QPainter::Antialiasing, true);

    if (_currentCounter >= _numberOfLines) {
        _currentCounter = 0;
    }

    painter.setPen(Qt::NoPen);
    for (int i = 0; i < _numberOfLines; ++i) {
        painter.save();
        painter.translate(_innerRadius + _lineLength,
                          _innerRadius + _lineLength);
        qreal rotateAngle =
                static_cast<qreal>(360 * i) / static_cast<qreal>(_numberOfLines);
        painter.rotate(rotateAngle);
        painter.translate(_innerRadius, 0);
        int distance =
                lineCountDistanceFromPrimary(i, _currentCounter, _numberOfLines);
        QColor color =
                currentLineColor(distance, _numberOfLines, _trailFadePercentage,
                                 _minimumTrailOpacity, _color);
        painter.setBrush(color);
        // TODO improve the way rounded rect is painted
        painter.drawRoundedRect(
                    QRect(0, -_lineWidth / 2, _lineLength, _lineWidth), _roundness,
                    _roundness, Qt::RelativeSize);
        painter.restore();
    }
}

void WaitingSpinnerWidget::start() {
    updatePosition();
    _isSpinning = true;
    show();

    if(parentWidget() && _disableParentWhenSpinning) {
        parentWidget()->setEnabled(false);
    }

    if (!_timer->isActive()) {
        _timer->start();
        _currentCounter = 0;
    }
}

void WaitingSpinnerWidget::stop() {
    _isSpinning = false;
    hide();

    if(parentWidget() && _disableParentWhenSpinning) {
        parentWidget()->setEnabled(true);
    }

    if (_timer->isActive()) {
        _timer->stop();
        _currentCounter = 0;
    }
}

void WaitingSpinnerWidget::setNumberOfLines(int lines) {
    _numberOfLines = lines;
    _currentCounter = 0;
    updateTimer();
}

void WaitingSpinnerWidget::setLineLength(int length) {
    _lineLength = length;
    updateSize();
}

void WaitingSpinnerWidget::setLineWidth(int width) {
    _lineWidth = width;
    updateSize();
}

void WaitingSpinnerWidget::setInnerRadius(int radius) {
    _innerRadius = radius;
    updateSize();
}

QColor WaitingSpinnerWidget::color() {
    return _color;
}

qreal WaitingSpinnerWidget::roundness() {
    return _roundness;
}

qreal WaitingSpinnerWidget::minimumTrailOpacity() {
    return _minimumTrailOpacity;
}

qreal WaitingSpinnerWidget::trailFadePercentage() {
    return _trailFadePercentage;
}

qreal WaitingSpinnerWidget::revolutionsPersSecond() {
    return _revolutionsPerSecond;
}

int WaitingSpinnerWidget::numberOfLines() {
    return _numberOfLines;
}

int WaitingSpinnerWidget::lineLength() {
    return _lineLength;
}

int WaitingSpinnerWidget::lineWidth() {
    return _lineWidth;
}

int WaitingSpinnerWidget::innerRadius() {
    return _innerRadius;
}

bool WaitingSpinnerWidget::isSpinning() const {
    return _isSpinning;
}

void WaitingSpinnerWidget::setRoundness(qreal roundness) {
    _roundness = std::max(0.0, std::min(100.0, roundness));
}

void WaitingSpinnerWidget::setColor(QColor color) {
    _color = color;
}

void WaitingSpinnerWidget::setRevolutionsPerSecond(qreal revolutionsPerSecond) {
    _revolutionsPerSecond = revolutionsPerSecond;
    updateTimer();
}

void WaitingSpinnerWidget::setTrailFadePercentage(qreal trail) {
    _trailFadePercentage = trail;
}

void WaitingSpinnerWidget::setMinimumTrailOpacity(qreal minimumTrailOpacity) {
    _minimumTrailOpacity = minimumTrailOpacity;
}

void WaitingSpinnerWidget::rotate() {
    ++_currentCounter;
    if (_currentCounter >= _numberOfLines) {
        _currentCounter = 0;
    }
    update();
}

void WaitingSpinnerWidget::updateSize() {
    int size = (_innerRadius + _lineLength) * 2;
    setFixedSize(size, size);
}

void WaitingSpinnerWidget::updateTimer() {
    _timer->setInterval(1000 / (_numberOfLines * _revolutionsPerSecond));
}

void WaitingSpinnerWidget::updatePosition() {
    if (parentWidget() && _centerOnParent) {
        move(parentWidget()->width() / 2 - width() / 2,
             parentWidget()->height() / 2 - height() / 2);
    }
}

int WaitingSpinnerWidget::lineCountDistanceFromPrimary(int current, int primary,
                                                       int totalNrOfLines) {
    int distance = primary - current;
    if (distance < 0) {
        distance += totalNrOfLines;
    }
    return distance;
}

QColor WaitingSpinnerWidget::currentLineColor(int countDistance, int totalNrOfLines,
                                              qreal trailFadePerc, qreal minOpacity,
                                              QColor color) {
    if (countDistance == 0) {
        return color;
    }
    const qreal minAlphaF = minOpacity / 100.0;
    int distanceThreshold =
            static_cast<int>(ceil((totalNrOfLines - 1) * trailFadePerc / 100.0));
    if (countDistance > distanceThreshold) {
        color.setAlphaF(minAlphaF);
    } else {
        qreal alphaDiff = color.alphaF() - minAlphaF;
        qreal gradient = alphaDiff / static_cast<qreal>(distanceThreshold + 1);
        qreal resultAlpha = color.alphaF() - gradient * countDistance;

        // If alpha is out of bounds, clip it.
        resultAlpha = std::min(1.0, std::max(0.0, resultAlpha));
        color.setAlphaF(resultAlpha);
    }
    return color;
}

三、祝愿

本章代码小而美,生活中也有无数个小美好。
祝愿朋友们:
		新年一路向上!
		事业永不卡顿!
		共赴美好,开启新征程~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/286837.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

怎么快速修复mfc140.dll文件?解决mfc140.dll缺失的方法

面对计算机报告的 ​mfc140.dll​ 文件遗失错误&#xff0c;这通常表明系统中缺少一个关键的动态链接库文件&#xff0c;该文件对于运行以 Microsoft Foundation Class (MFC) 库编写的程序十分重要&#xff0c;尤其是那些需要图形界面的应用程序和一些游戏。若没有这个文件&…

【数字图像处理技术与应用】2023-2024上图像处理期中-云南农业大学

一、填空题&#xff08;每空2 分&#xff0c;共 30 分&#xff09; 1、图像就是3D 场景在 二维 平面上的影像&#xff0c;根据其存储方式和表现形式&#xff0c;可以将图像分为 模拟 图像和数字图像两大类&#xff1b; 2、在用计算机对数字图像处理中&#xff0c;常用一个 二…

【userfaultfd 条件竞争】starCTF2019 - hackme

前言 呜呜呜&#xff0c;这题不难&#xff0c;但是差不多一个多月没碰我的女朋友 kernel pwn 了&#xff0c;对我的 root 宝宝也是非常想念&#xff0c;可惜这题没有找到我的 root 宝宝&#xff0c;就偷了她的 flag。 哎有点生疏了&#xff0c;这题没看出来堆溢出&#xff0c…

引导过程的解析以及教程za

bios加电自检------mbr--------grub-------加载内核文件------启动第一个进程 bios的主要作用&#xff1a;检测硬件是否正常&#xff0c;然后根据bios中的启动项设置&#xff0c;去找内核文件 boot开机启动项顺序&#xff0c;你可以把内核文件放在何处&#xff1f; 1.硬盘 …

Vue3 watch 的使用,如何监听一个对象中的属性值的变化 vue3 + ts + vite

Vue3 watch 的使用&#xff0c;如何监听一个对象中的属性值的变化 由 vue2 转到 vue3 ts vite 之后都不会写这些玩意了。搜了下&#xff0c;找到了答案&#xff1a; vue2 的 watch export default {watch: {$route.query.id(newValue){// 可以这样监听路由的变化},formUse…

CGAL的D维空间搜索(基于KD树)

1、介绍 空间搜索包通过提供支持以下算法的实现来实现精确和近似距离的实现 最近和最远邻居搜索 精确和近似搜索 &#xff08;近似&#xff09;范围搜索 &#xff08;近似&#xff09;k-最近邻和k-最远邻搜索 &#xff08;近似&#xff09;增量最近邻和增量最远邻搜索 表示点和…

SPSS23软件安装包下载及安装教程

SPSS 23下载链接&#xff1a;https://docs.qq.com/doc/DUkRHVUxFUkVBUUlj 1.选中下载好的安装包&#xff0c;鼠标右键解压到“SPSS 23 64bit”文件夹 2.打开”Setup“文件夹 3.选中”Setup.exe“鼠标右击选择以管理员身份运行 4.点击“下一步” 5.点击“下一步” 6.选择“我接受…

安全与认证Week4

目录 本章需要理解的问题 Web Security (TLS/SSL) 关于网络 使用网络会受到的威胁 各层安全协议 S/MIME、PGP&#xff08;后面和S/MIME一起出现&#xff09;、Kerberos、TLS/SSL 和 IP/IPSec 分别是&#xff1a; S/MIME (Secure/Multipurpose Internet Mail Extensions)&#x…

Redis缓存保卫战:拒绝缓存击穿的进攻【redis问题 三】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Redis缓存保卫战&#xff1a;拒绝缓存击穿的进攻 前言缓存击穿的定义和原理为何会发生缓存击穿缓存击穿的危害防范缓存击穿结语: 前言 你是否曾经遇到过系统在高并发情况下出现严重性能问题&#xff…

【计算机图形学】NAP: Neural 3D Articulation Prior

文章目录 1. 这篇论文做了什么事&#xff0c;有什么贡献&#xff1f;2. Related Work铰接物体建模3D中的Diffusion model扩散模型 3. Pipeline铰接树参数化基于Diffusion的铰接树生成去噪网络 4. 实验评价铰接物体生成——以往做法与本文提出的新指标NAP捕捉到的铰接物体分布质…

用户管理第2节课--idea 2023.2 后端--实现基本数据库操作(操作user表) -- 自动生成 --【本人】

一、插件安装 1.1 搜索插件 mybatis 安装 1.2 接受安装 1.3 再次进入&#xff0c;说明安装好了 1.4 与鱼皮不同点 1&#xff09;mybatis 版本不一致 鱼皮&#xff1a; 本人&#xff1a; 2&#xff09;鱼皮需重启安装 本人不需要 1.5 【需完成 三、步骤&#xff0c;再来看】 …

Noisy DQN 跑 CartPole-v1

gym 0.26.1 CartPole-v1 NoisyNet DQN NoisyNet 就是把原来Linear里的w/b 换成 mu sigma * epsilon, 这是一种非常简单的方法&#xff0c;但是可以显著提升DQN的表现。 和之前最原始的DQN相比就是改了两个地方&#xff0c;一个是Linear改成了NoisyLinear,另外一个是在agent在t…

车载 Android之 核心服务 - CarPropertyService 解析

重要类的源码文件名及位置&#xff1a; CarPropertyManager.java packages/services/Car/car-lib/src/android/car/hardware/property/ CarPropertyService.java packages/services/Car/service/src/com/android/car/ 类的介绍&#xff1a; CarPropertyManager&#xff1a…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)在EventLoop中处理被激活的文件描述符的事件

文件描述符处理与回调函数 一、主要概念 反应堆模型&#xff1a;一种处理系统事件或网络事件的模型&#xff0c;当文件描述符被激活时&#xff0c;可以检测到文件描述符&#xff1a;在操作系统中&#xff0c;用于标识打开的文件、套接字等的一种数据类型 处理激活的文件描述符…

k8s中ConfigMap详解及应用

一、ConfigMap概述 ConfigMap是k8s的一个配置管理组件&#xff0c;可以将配置以key-value的形式传递&#xff0c;通常用来保存不需要加密的配置信息&#xff0c;加密信息则需用到Secret&#xff0c;主要用来应对以下场景&#xff1a; 使用k8s部署应用&#xff0c;当你将应用配置…

DrGraph原理示教 - OpenCV 4 功能 - 二值化

二值化&#xff0c;也就是处理结果为0或1&#xff0c;当然是针对图像的各像素而言的 1或0&#xff0c;对应于有无&#xff0c;也就是留下有用的&#xff0c;删除无用的&#xff0c;有用的部分&#xff0c;就是关心的部分 在图像处理中&#xff0c;也不仅仅只是1或0&#xff0c;…

docker安装postgresql15或者PG15

1. 查询版本 docker search postgresql docker pull postgres:15.3 # 也可以拉取其他版本2.运行容器并挂载数据卷 mkdir -p /data/postgresql docker run --name postgres \--restartalways \-e POSTGRES_PASSWORDpostgresql \-p 5433:5432 \-v /data/postgresql:/var/lib/p…

工业制造领域,折弯工艺如何进行优化?

若将消费互联网与工业互联网相比较&#xff0c;消费互联网就好似一片宽度为1000米、深度仅有1米的水域&#xff0c;而工业互联网则类似于宽度有1000米、深达10000米的海域。消费互联网因为被限制了深度&#xff0c;便只能在浅显的焦虑中创造出一种消费趋势。相较之下&#xff0…

数据库迁移工具包:DBSofts ESF Database Migration Crack

ESF 数据库迁移工具包 - 11.2.17 允许您通过 3 个步骤在各种数据库格式之间迁移数据&#xff0c;无需任何脚本&#xff01; DBSofts ESF Database Migration它极大地减少了与以下任何数据库格式之间迁移的工作量、成本和风险&#xff1a;Oracle、MySQL、MariaDB、SQL Server、…

(15)Linux 进程创建与终止函数forkslab 分派器

前言&#xff1a;本章我们主要讲解进程的创建与终止&#xff0c;最后简单介绍一下 slab 分派器。 一、进程创建&#xff08;Process creation&#xff09; 1、分叉函数 fork 在 中&#xff0c; fork 函数是非常重要的函数&#xff0c;它从已存在进程中创建一个新的进程。 …