《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://www.rhkb.cn/news/321164.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Pytorch】6.torch.nn.functional.conv2d的使用

阅读之前应该先了解基础的CNN网络的逻辑 conv2d的作用 是PyTorch中用于执行二维卷积操作的函数。它的作用是对输入数据进行二维卷积操作&#xff0c;通常用于图像处理和深度学习中的卷积神经网络&#xff08;CNN&#xff09;模型。 conv2d的使用 我们先查看一下官方文档 inpu…

nn.TransformerEncoderLayer详细解释,使用方法!!

nn.TransformerEncoderLayer nn.TransformerEncoderLayer 是 PyTorch 的 torch.nn 模块中提供的一个类&#xff0c;用于实现 Transformer 编码器的一个单独的层。Transformer 编码器层通常包括一个自注意力机制和一个前馈神经网络&#xff0c;中间可能还包含层归一化&#xff…

AutoTable, Hibernate自动建立表替代方案

痛点 之前一直使用JPA为主要ORM技术栈&#xff0c;主要是因为Mybatis没有实体逆向建表功能。虽然Mybatis有从数据库建立实体&#xff0c;但是实际应用却没那么美好&#xff1a;当实体变更时&#xff0c;往往不会单独再建立一个数据库重新生成表&#xff0c;然后把表再逆向为实…

matplotlib和pandas与numpy

1.matplotlib介绍 一个2D绘图库&#xff1b; 2.Pandas介绍&#xff1a; Pandas一个分析结构化数据的工具&#xff1b; 3.NumPy 一个处理n纬数组的包&#xff1b; 4.实践&#xff1a;绘图matplotlip figure()生成一个图像实例 %matplotlib inline&#xff1a;图形直接在…

(三)JSP教程——JSP动作标签

JSP动作标签 用户可以使用JSP动作标签向当前输出流输出数据&#xff0c;进行页面定向&#xff0c;也可以通过动作标签使用、修改和创建对象。 <jsp:include>标签 <jsp:include>标签将同一个Web应用中静态或动态资源包含到当前页面中。资源可以是HTML、JSP页面和文…

5月6(信息差)

&#x1f30d;一次预测多个token&#xff0c;Meta新模型推理加速3倍&#xff0c;编程任务提高17% https://hub.baai.ac.cn/view/36857 &#x1f384; LeetCode 周赛超越 80% 人类选手&#xff0c;推理性能超 Llama3-70B。 ✨ 我国量子计算机实现“四算合一” 实现通算、…

鸿蒙OpenHarmony南向:【Hi3516标准系统入门(命令行方式)】

Hi3516标准系统入门&#xff08;命令行方式&#xff09; 注意&#xff1a; 从3.2版本起&#xff0c;标准系统不再针对Hi3516DV300进行适配验证&#xff0c;建议您使用RK3568进行标准系统的设备开发。 如您仍然需要使用Hi3516DV300进行标准系统相关开发操作&#xff0c;则可能会…

一加12/11/10/Ace2/Ace3手机上锁回锁BL无限重启黑屏9008模式救砖

一加12/11/10/Ace2/Ace3手机官方都支持解锁BL&#xff0c;搞机的用户也比较多&#xff0c;相对于其他品牌来说&#xff0c;并没有做出限制&#xff0c;这也可能是搞机党最后的救命稻草。而厌倦了root搞机的用户&#xff0c;就习惯性回锁BL&#xff0c;希望彻底变回官方原来的样…

数字旅游以科技创新为核心:推动旅游服务的智能化、精准化、个性化,为游客提供更加贴心、专业、高效的旅游服务

目录 一、引言 二、数字旅游以科技创新推动旅游服务智能化 1、智能化技术的应用 2、提升旅游服务的效率和质量 三、数字旅游以科技创新推动旅游服务精准化 1、精准化需求的识别与满足 2、精准化营销与推广 四、数字旅游以科技创新推动旅游服务个性化 1、个性化服务的创…

3D相机及应用

无论是2D相机和3D相机&#xff0c;在工业应用中都有着不可或缺的作用。3D相机与2D相机的最大区别在于&#xff0c;3D相机可以获取真实世界尺度下的3D信息&#xff0c;而2D相机只能获取像素尺度下的2D平面图像信息。通过3D相机得到的数据&#xff0c;我们可以还原出被测量物体的…

java线上问题排查之内存分析(三)

java线上问题排查之内存分析 使用top命令 top命令显示的结果列表中&#xff0c;会看到%MEM这一列&#xff0c;这里可以看到你的进程可能对内存的使用率特别高。以查看正在运行的进程和系统负载信息&#xff0c;包括cpu负载、内存使用、各个进程所占系统资源等。 2.用jstat命令…

RapidJSON介绍

1.简介 RapidJSON 是一个 C 的 JSON 解析库&#xff0c;由腾讯开源。 支持 SAX 和 DOM 风格的 API&#xff0c;并且可以解析、生成和查询 JSON 数据。RapidJSON 快。它的性能可与strlen() 相比。可支持 SSE2/SSE4.2 加速。RapidJSON 独立。它不依赖于 BOOST 等外部库。它甚至…

从互联网医院源码到搭建:开发视频问诊小程序的技术解析

如今&#xff0c;视频问诊小程序作为医疗服务的一种新形式&#xff0c;正逐渐受到人们的关注和青睐。今天&#xff0c;小编将为您详解视频问诊小程序的开发流程。 一、背景介绍 互联网医院源码是视频问诊小程序开发的基础&#xff0c;它提供了一套完整的医疗服务系统框架&…

Windows PC上从零开始部署ChatGML-6B-int4量化模型

引言 ChatGLM-6B是清华大学知识工程和数据挖掘小组&#xff08;Knowledge Engineering Group (KEG) & Data Mining at Tsinghua University&#xff09;发布的一个开源的对话机器人。6B表示这是ChatGLM模型的60亿参数的小规模版本&#xff0c;约60亿参数。 ChatGML-6B-in…

spring高级篇(七)

1、异常处理 在DispatcherServlet中&#xff0c;doDispatch(HttpServletRequest request, HttpServletResponse response) 方法用于进行任务处理&#xff1a; 在捕获到异常后没有立刻进行处理&#xff0c;而是先用一个局部变量dispatchException进行记录&#xff0c;然后统一由…

文心一言 VS 讯飞星火 VS chatgpt (253)-- 算法导论18.2 6题

六、假设 B-TREE-SEARCH 的实现是在每个结点内采用二分查找&#xff0c;而不是线性查找。证明&#xff1a;无论怎样选择 t ( t 为 n 的函数)&#xff0c;这种实现所需的 CPU 时间都为 O(lgn)。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 首先&#xff0c;我…

ChatGPT理论分析

ChatGPT "ChatGPT"是一个基于GPT&#xff08;Generative Pre-trained Transformer&#xff09;架构的对话系统。GPT 是一个由OpenAI 开发的自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;它使用深度学习来生成文本。以下是对ChatGPT进行理论分析的几个主…

PTA|小字辈

题目 本题给定一个庞大家族的家谱&#xff0c;要请你给出最小一辈的名单。 输入格式&#xff1a; 输入在第一行给出家族人口总数 N&#xff08;不超过 100 000 的正整数&#xff09; —— 简单起见&#xff0c;我们把家族成员从 1 到 N 编号。随后第二行给出 N 个编号&#x…

c#数据库: 10.调用存储过程查询信息,并显示在窗体上

查询女生信息&#xff0c;并将信息显示在窗体上: 原数据表//右键数据库名,新建查询 ------------- 新建查询窗口,添加新建存储过程Procedure_GetGirls1和查询代码如下 : CREATE PROCEDURE dbo.Procedure_GetGirls1 /*存储过程名称*/ AS SELECT * f…

《设计一款蓝牙热敏打印机》

主控芯片用易兆威蓝牙ic&#xff0c;通讯接口&#xff1a;蓝牙、串口、usb 安卓apk用java kotlin编写、上位机用Qt编写。