《QT实用小工具·五十九》随机图形验证码,带有一些可人的交互与动画

1、概述
源码放在文章末尾

该项目实现了可交互的动画验证码控件,趣味性十足:

字符变换动画
噪音动画
可拖动交互

项目demo演示如下所示:
在这里插入图片描述

项目部分代码如下所示:

#ifndef CAPTCHAMOVABLELABEL_H
#define CAPTCHAMOVABLELABEL_H#include <QLabel>
#include <QTime>
#include <QPropertyAnimation>
#include <QDebug>
#include <QMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QApplication>
#include <QGraphicsDropShadowEffect>
#include <cmath>
#include <QTimer>#define CAPTCHA_REFRESH_DURATION 300 // 刷新的动画时长
#define CAPTCHA_CHAR_ANGLE_MAX 20 // 最大旋转角:20°
#define CAPTCHA_SHADOW_BLUR_MAX 80 // 最大的阴影模糊半径class CaptchaMovableLabel : public QLabel
{Q_OBJECTQ_PROPERTY(int refreshProgress READ getRefreshProgress WRITE setRefreshProgress)Q_PROPERTY(int pressProgress READ getPressProgress WRITE setPressProgress)
public:CaptchaMovableLabel(QWidget* parent);void setAngle(int angle);void setColor(QColor color);void setText(QString ch);void startRefreshAnimation();void setMoveBorder(QRect rect);QString text();protected:void paintEvent(QPaintEvent *) override;void mousePressEvent(QMouseEvent *ev) override;void mouseMoveEvent(QMouseEvent *ev) override;void mouseReleaseEvent(QMouseEvent *ev) override;private:void startPressAnimation(int end);void setRefreshProgress(int g);int getRefreshProgress();inline bool isNoAni();void setPressProgress(int g);int getPressProgress();private slots:void slotMovePos();private:QPoint press_pos;bool dragging =  false;bool moved = false;QGraphicsDropShadowEffect effect;QString ch;QColor color;int angle = 0;int refreshProgress = 100;QString prevCh;QColor prevColor;int prevAngle = 0;QString prevChar;int pressProgress = 0;bool inited = false;QTimer movingTimer;int moveR, moveG, moveB;
};#endif // CAPTCHAMOVABLELABEL_H
#include "captchamovablelabel.h"CaptchaMovableLabel::CaptchaMovableLabel(QWidget *parent) : QLabel(parent)
{effect.setOffset(0, 0);
//    effect.setBlurRadius(8);setGraphicsEffect(&effect);movingTimer.setInterval(30);movingTimer.setSingleShot(false);connect(&movingTimer, SIGNAL(timeout()), this, SLOT(slotMovePos()));
}void CaptchaMovableLabel::setAngle(int angle)
{this->prevAngle = this->angle;this->angle = angle;
}void CaptchaMovableLabel::setColor(QColor color)
{this->prevColor = this->color;this->color = color;moveR = qrand() % 5;moveG = qrand() % 5;moveB = qrand() % 5;movingTimer.start();
}void CaptchaMovableLabel::setText(QString text)
{this->prevCh = this->ch;this->ch = text;// 计算合适的高度QFontMetrics fm(this->font());double w = fm.horizontalAdvance(text)+2;double h = fm.height();const double PI = 3.141592;int xieHalf = sqrt(w*w/4+h*h/4); // 斜边的一半double a = atan(w/h) + CAPTCHA_CHAR_ANGLE_MAX * PI / 180; // 最大的倾斜角度int w2 = xieHalf * sin(a) * 2;a = atan(w/h) - CAPTCHA_CHAR_ANGLE_MAX * PI / 180;int h2 = xieHalf * cos(a) * 2;resize(w2, h2);
}void CaptchaMovableLabel::startRefreshAnimation()
{if (!inited) // 第一次,直接显示,取消动画{inited = true;return ;}QPropertyAnimation* ani = new QPropertyAnimation(this, "refreshProgress");ani->setStartValue(0);ani->setEndValue(100);ani->setDuration(qrand() % (CAPTCHA_REFRESH_DURATION / 3) + CAPTCHA_REFRESH_DURATION / 3);ani->start();connect(ani, SIGNAL(finished()), ani, SLOT(deleteLater()));connect(ani, SIGNAL(finished()), &movingTimer, SLOT(start()));
}QString CaptchaMovableLabel::text()
{return ch;
}void CaptchaMovableLabel::paintEvent(QPaintEvent *)
{QPainter painter(this);painter.setFont(this->font());painter.setRenderHint(QPainter::SmoothPixmapTransform);int w2 = width()/2, h2 = height()/2;painter.translate(w2, h2); // 平移到中心,绕中心点旋转if (isNoAni()) // 不在动画中,直接绘制{painter.setPen(color);painter.rotate(angle);painter.drawText(QRect(-w2, -h2, width(), height()), Qt::AlignCenter, ch);return ;}// 动画里面,前后渐变替换double newProp = refreshProgress / 100.0;double oldProp = 1.0 - newProp;double a = prevAngle * oldProp + angle * newProp + 0.5;painter.save();painter.rotate(a);QColor c = prevColor;c.setAlpha(c.alpha() * oldProp); // 旧文字渐渐消失painter.setPen(c);painter.drawText(QRect(-w2,-h2,width(),height()), Qt::AlignCenter, prevCh);c = this->color;c.setAlpha(c.alpha() * newProp); // 新文字渐渐显示painter.setPen(c);painter.drawText(QRect(-w2, -h2, width(), height()), Qt::AlignCenter, ch);painter.restore();
}void CaptchaMovableLabel::mousePressEvent(QMouseEvent *ev)
{if (ev->button() == Qt::LeftButton){// 开始拖拽press_pos = ev->pos();dragging = true;moved = false;this->raise();movingTimer.stop();startPressAnimation(200);return ev->accept();}QLabel::mousePressEvent(ev);
}void CaptchaMovableLabel::mouseMoveEvent(QMouseEvent *ev)
{if (dragging && ev->buttons() & Qt::LeftButton){if (!moved && (ev->pos() - press_pos).manhattanLength() < QApplication::startDragDistance()){return QLabel::mouseMoveEvent(ev); // 还没到这时候}moved = true;move(this->pos() + ev->pos() - press_pos);ev->accept();return ;}QLabel::mouseMoveEvent(ev);
}void CaptchaMovableLabel::mouseReleaseEvent(QMouseEvent *ev)
{if (dragging){// 结束拖拽dragging = false;movingTimer.start();startPressAnimation(0);}if (moved)return ev->accept();QLabel::mouseReleaseEvent(ev);
}void CaptchaMovableLabel::startPressAnimation(int end)
{QPropertyAnimation* ani = new QPropertyAnimation(this, "pressProgress");ani->setStartValue(pressProgress);ani->setEndValue(end);ani->setDuration(CAPTCHA_REFRESH_DURATION << 1);ani->start();connect(ani, SIGNAL(finished()), ani, SLOT(deleteLater()));
}void CaptchaMovableLabel::setRefreshProgress(int g)
{this->refreshProgress = g;update();
}int CaptchaMovableLabel::getRefreshProgress()
{return refreshProgress;
}bool CaptchaMovableLabel::isNoAni()
{return refreshProgress == 100;
}void CaptchaMovableLabel::setPressProgress(int g)
{this->pressProgress = g;double off = g / 100;effect.setBlurRadius(g / 20.0);effect.setOffset(-off, off);
}int CaptchaMovableLabel::getPressProgress()
{return pressProgress;
}void CaptchaMovableLabel::slotMovePos()
{if (refreshProgress < 100)return ;int val = color.red() + moveR;if ( val > 255){val = 255;moveR = - qrand() % 5;}else if (val < 0){val = 0;moveR = - qrand() % 5;}color.setRed(val);val = color.green() + moveG;if ( val > 255){val = 255;moveG = - qrand() % 5;}else if (val < 0){val = 0;moveG = - qrand() % 5;}color.setGreen(val);val = color.blue() + moveB;if ( val > 255){val = 255;moveB = - qrand() % 5;}else if (val < 0){val = 0;moveB = - qrand() % 5;}color.setBlue(val);
}

源码下载

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Kubernetes 教程:在 Containerd 容器中使用 GPU

原文链接:Kubernetes 教程:在 Containerd 容器中使用 GPU 云原生实验室本文介绍了如何在使用 Containerd 作为运行时的 Kubernetes 集群中使用 GPU 资源。https://fuckcloudnative.io/posts/add-nvidia-gpu-support-to-k8s-with-containerd/ 前两天闹得沸沸扬扬的事件不知道…

技术速递|使用 .NET 为 Microsoft AI 构建可扩展网关

作者&#xff1a;Kara Saucerman 排版&#xff1a;Alan Wang Microsoft AI 团队构建了全面的内容、服务、平台和技术&#xff0c;以便消费者在任何设备上、任何地方获取他们想要的信息&#xff0c;并为企业改善客户和员工的体验。我们的团队支持多种体验&#xff0c;包括 Bing、…

全栈开发之路——前端篇(6)生命周期和自定义hooks

全栈开发一条龙——前端篇 第一篇&#xff1a;框架确定、ide设置与项目创建 第二篇&#xff1a;介绍项目文件意义、组件结构与导入以及setup的引入。 第三篇&#xff1a;setup语法&#xff0c;设置响应式数据。 第四篇&#xff1a;数据绑定、计算属性和watch监视 第五篇 : 组件…

详细讲解lua中string.gsub的使用

string.gsub 是 Lua 标准库中的一个函数&#xff0c;用于全局替换字符串中的某些部分。string.gsub 是 Lua 中非常实用的一个函数&#xff0c;它可以用来进行字符串的处理和替换操作。 它的基本语法如下&#xff1a; string.gsub(s, pattern, replacement [, n])s 是要处理的…

HarmonyOS实战开发教程-如何开发一个2048游戏

今天为大家分享的是2048小游戏&#xff0c;先看效果图&#xff1a; 这个项目对于新手友友来说可能有一点难度&#xff0c;但是只要坚持看完一定会有收获。因为小编想分享的并不局限于ArkTs语言&#xff0c;而是编程思想。 这个游戏的基本逻辑是初始化一个4乘4的数组&#xff…

深度学习模型训练套路与验证套路以及如何使用GPU进行模型训练

完整的模型训练套路&#xff1a;代码模板 数据集以经典的 CIFAR10 为例。 这个例子是很简单的&#xff0c;可能不太实用&#xff0c;但重点是通过这个例子掌握一种模型训练的写法套路&#xff0c;因此很有必要学习。 import torch.optim import torchvision from torch impo…

JavaScript异步编程——02-Ajax入门和发送http请求

同步和异步回顾 同步和异步的简单理解 同步&#xff1a;必须等待前面的任务完成&#xff0c;才能继续后面的任务。 异步&#xff1a;不受当前任务的影响。 拿排队举例&#xff1a; 同步&#xff1a;在银行排队时&#xff0c;只有等到你了&#xff0c;才能够去处理业务。 异…

【C++泛型编程】(二)标准模板库 STL

文章目录 标准模板库 STL容器算法迭代器仿函数/函数对象适配器分配器示例 标准模板库 STL C 的标准模板库&#xff08;Standard Template Library&#xff0c;STL&#xff09;旨在通过模板化的设计&#xff0c;提供一种通用的编程模式&#xff0c;使程序员能方便地实现和扩展各…

数据仓库项目---Day01

文章目录 框架的安装包数据仓库概念项目需求及架构设计项目需求分析项目框架技术选型系统数据流程设计框架版本选型集群资源规划设计 数据生成模块数据埋点主流埋点方式埋点数据上报时机 服务器和JDK准备搭建三台Linux虚拟机(VMWare)编写集群分发脚本xsyncSSH无密登录配置JDK准…

实现同一份数据的各种镜像

一个数据集通过某个轴&#xff08;通常是垂直或水平轴&#xff09;的镜像对称。这可以通过简单的数学运算来实现。 如果想要通过一块数据生成四份&#xff0c;可以通过以下步骤&#xff1a; 下面是一个简单的示例&#xff0c;展示了如何通过垂直轴&#xff08;左右对称&#…

找不到模块“vue-router”。你的意思是要将 moduleResolution 选项设置为 node,还是要将别名添加到 paths 选项中?

在tsconfig.app.json中添加&#xff0c;记得一定是 tsconfig.app.json 中&#xff0c;如添加到 tsconfig.node.json 还是会报错的 哈哈哈哈&#xff0c;不瞒你们&#xff0c;我就添加错了&#xff0c;哈哈哈。所以这也算写一个demo提醒自己 "compilerOptions": {&qu…

深入理解指针1

目录 如对您有帮助&#xff0c;还望三连支持&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 1.内存和地址 计算机中常⻅的单位&#xff08;补充&#xff09;&#xff1a; 如何理解编址 2.指针变量和地址 2.1取地址操作符&#xff08;&&#xff09; 2.2指针变…

多个开源的js补环境框架测试

原文链接&#xff1a;https://mp.weixin.qq.com/s/uEMFGpE5bqmTvzSgX2twvA 前言 在做js逆向时肯定会遇到补环境的情况&#xff0c;看到github开源了好几个补环境用的框架&#xff0c;这篇文章做个测试&#xff0c;看看哪个比较好用。 https://github.com/pysunday/sdenvhttp…

Spring Boot3.x集成Disruptor4.0

Disruptor介绍 Disruptor是一个高性能内存队列&#xff0c;研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级)。基于Disruptor开发的系统单线程能支撑每秒600万订单&#xff0c;2010年在QCon演讲后&#xff0c;获得了业界关注。2011年&…

前端学习|第五章

HTML5&CSS3 新特性 前言HTML5 新特性一、语义化标签二、多媒体标签三、新增 input 类型四、新增表单属性 CSS3 新特性一、新增选择器二、盒子模型三、图片模糊处理四、calc 函数五、过渡 - transition六、2D 转换 - transform七、动画 - animation八、3D 转换 - translate3…

数据库被Elbie勒索病毒加密可以恢复吗?

一、Elbie勒索病毒简介 Elbie勒索病毒是一种严重的网络安全威胁&#xff0c;它通过加密用户文件并索要高额赎金来获取解密密钥。该病毒通常通过电子邮件附件、恶意网站、社交媒体平台以及利用用户网站服务器上的漏洞进行传播。一旦感染&#xff0c;用户的文件将被加密&#xff…

我独自升级崛起下载方法分享 下载教程

《我独自升级&#xff1a;崛起》这款精彩绝伦的动作角色扮演游戏&#xff0c;灵感来源于大热网络漫画&#xff0c;让玩家亲自踏上主角程肖宇的征途&#xff0c;从觉醒初阶到实力飞跃&#xff0c;每一步成长都扣人心弦。值得注意的是&#xff0c;尽管全球正式发布日期定在了五月…

RT-DETR-20240507周更说明|更新Inner-IoU、Focal-IoU、Focaler-IoU等数十种IoU计算方式

RT-DETR改进专栏|包含主干、模块、注意力、损失函数等改进 专栏介绍 本专栏包含模块、卷积、检测头、损失等深度学习前沿改进,目前已有改进点70&#xff01;每周更新。 20240507更新说明&#xff1a; ⭐⭐ 更新CIoU、DIoU、MDPIoU、GIoU、EIoU、SIoU、ShapeIou、PowerfulIoU、…

分析错误ValueError: could not determine the shape of object type ‘Series‘

这个错误提示 ValueError: could not determine the shape of object type Series 通常发生在尝试将 pandas 的 Series 直接转换为 PyTorch 的 tensor 时&#xff0c;尤其是当 Series 的数据类型不明确或者包含非数值类型的数据时。为了修正这个问题&#xff0c;确保在转换之前…

酷得智能电子方案 早教学习机

早教学习机是用户友好的&#xff0c;易于操作&#xff0c;同时要确保内容的科学性和适宜性&#xff0c;以促进儿童的健康成长和智力发展。 通常包括以下几个方面&#xff1a; 1.年龄分级内容&#xff1a;软件会根据儿童的不同年龄段提供相应的教育内容&#xff0c;从新生儿到…