《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

相关文章

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

基于WinForm+Halcon实现图像缩放与交互功能

《基于WinForm+Halcon实现图像缩放与交互功能》本文主要讲述在WinForm中结合Halcon实现图像缩放、平移及实时显示灰度值等交互功能,包括初始化窗口的不同方式,以及通过特定事件添加相应... 目录前言初始化窗口添加图像缩放功能添加图像平移功能添加实时显示灰度值功能示例代码总结最后前言本文将

基于C#实现PDF文件合并工具

《基于C#实现PDF文件合并工具》这篇文章主要为大家详细介绍了如何基于C#实现一个简单的PDF文件合并工具,文中的示例代码简洁易懂,有需要的小伙伴可以跟随小编一起学习一下... 界面主要用于发票PDF文件的合并。经常出差要报销的很有用。代码using System;using System.Col

redis-cli命令行工具的使用小结

《redis-cli命令行工具的使用小结》redis-cli是Redis的命令行客户端,支持多种参数用于连接、操作和管理Redis数据库,本文给大家介绍redis-cli命令行工具的使用小结,感兴趣的... 目录基本连接参数基本连接方式连接远程服务器带密码连接操作与格式参数-r参数重复执行命令-i参数指定命

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

Debian如何查看系统版本? 7种轻松查看Debian版本信息的实用方法

《Debian如何查看系统版本?7种轻松查看Debian版本信息的实用方法》Debian是一个广泛使用的Linux发行版,用户有时需要查看其版本信息以进行系统管理、故障排除或兼容性检查,在Debia... 作为最受欢迎的 linux 发行版之一,Debian 的版本信息在日常使用和系统维护中起着至关重要的作

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要