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

本文主要是介绍《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);
}

源码下载

这篇关于《QT实用小工具·五十九》随机图形验证码,带有一些可人的交互与动画的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/968649

相关文章

Django开发时如何避免频繁发送短信验证码(python图文代码)

《Django开发时如何避免频繁发送短信验证码(python图文代码)》Django开发时,为防止频繁发送验证码,后端需用Redis限制请求频率,结合管道技术提升效率,通过生产者消费者模式解耦业务逻辑... 目录避免频繁发送 验证码1. www.chinasem.cn避免频繁发送 验证码逻辑分析2. 避免频繁

精选20个好玩又实用的的Python实战项目(有图文代码)

《精选20个好玩又实用的的Python实战项目(有图文代码)》文章介绍了20个实用Python项目,涵盖游戏开发、工具应用、图像处理、机器学习等,使用Tkinter、PIL、OpenCV、Kivy等库... 目录① 猜字游戏② 闹钟③ 骰子模拟器④ 二维码⑤ 语言检测⑥ 加密和解密⑦ URL缩短⑧ 音乐播放

python中列表应用和扩展性实用详解

《python中列表应用和扩展性实用详解》文章介绍了Python列表的核心特性:有序数据集合,用[]定义,元素类型可不同,支持迭代、循环、切片,可执行增删改查、排序、推导式及嵌套操作,是常用的数据处理... 目录1、列表定义2、格式3、列表是可迭代对象4、列表的常见操作总结1、列表定义是处理一组有序项目的

基于Python实现简易视频剪辑工具

《基于Python实现简易视频剪辑工具》这篇文章主要为大家详细介绍了如何用Python打造一个功能完备的简易视频剪辑工具,包括视频文件导入与格式转换,基础剪辑操作,音频处理等功能,感兴趣的小伙伴可以了... 目录一、技术选型与环境搭建二、核心功能模块实现1. 视频基础操作2. 音频处理3. 特效与转场三、高

基于Python开发一个图像水印批量添加工具

《基于Python开发一个图像水印批量添加工具》在当今数字化内容爆炸式增长的时代,图像版权保护已成为创作者和企业的核心需求,本方案将详细介绍一个基于PythonPIL库的工业级图像水印解决方案,有需要... 目录一、系统架构设计1.1 整体处理流程1.2 类结构设计(扩展版本)二、核心算法深入解析2.1 自

python生成随机唯一id的几种实现方法

《python生成随机唯一id的几种实现方法》在Python中生成随机唯一ID有多种方法,根据不同的需求场景可以选择最适合的方案,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习... 目录方法 1:使用 UUID 模块(推荐)方法 2:使用 Secrets 模块(安全敏感场景)方法

Ubuntu 24.04启用root图形登录的操作流程

《Ubuntu24.04启用root图形登录的操作流程》Ubuntu默认禁用root账户的图形与SSH登录,这是为了安全,但在某些场景你可能需要直接用root登录GNOME桌面,本文以Ubuntu2... 目录一、前言二、准备工作三、设置 root 密码四、启用图形界面 root 登录1. 修改 GDM 配

PostgreSQL中rank()窗口函数实用指南与示例

《PostgreSQL中rank()窗口函数实用指南与示例》在数据分析和数据库管理中,经常需要对数据进行排名操作,PostgreSQL提供了强大的窗口函数rank(),可以方便地对结果集中的行进行排名... 目录一、rank()函数简介二、基础示例:部门内员工薪资排名示例数据排名查询三、高级应用示例1. 每

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构