摘要:支持多种自定义功能。支持长度自定义,字体自定义,颜色自定义,噪点干扰线各种属性自定义,话不多说,先上图。
动态设置背景和边框颜色
动态修改圆角矩形,圆角比例可自定义
动态更改验证码长度和噪点以及感染线数量
支持自定义的范围包括但不限于上图内容,有关所有自定义功能参考下面的结构体定义
/// 图片验证码控件风格数据结构体
typedef struct LQTIMGVERUIFY_STYLE_{
double dRcRoundRadius = 0.01; ///矩形背景圆角半径
uint uObstructPoint = 200; ///噪点数量
double dObstructPsize = 2.0; ///噪点大小
bool bAoutPointSize = true; ///是否为自动噪点大小
bool bAutoPointClrs = true; ///使用自动噪点颜色
QColor cObstructPoint = QColor(235,98,30); ///指定噪点颜色
uint uObstructLines = 50; ///干扰线数量
double dObstructLsize = 2.0; ///干扰线大小
bool bAutoLinesSize = true; ///使用自动干扰大小
bool bAutoLinesClrs = true; ///使用自动干扰线颜色
QColor cObstructLines = QColor(53,177,146); ///指定干扰线颜色
bool bDarwBkgColors = true; ///绘制背景
bool bDrawFrmBorder = true; ///绘制边框
double dBordersWidths = 1.0; ///边框宽度
uint uCodeMaxLength = 10; ///验证码字符最大长度
uint uCodeMinLength = 4; ///验证码字符最小长度
uint uCodeSetLength = 6; ///验证码字符设置长度
bool bCaseSensitive = false; ///区分大小写
bool bAutoTextColor = true; ///自动验证码文字颜色
QColor cCodeTextColor = QColor(11,11,29); ///指定验证码文字颜色
QFont fCodeTextFonts; ///验证码文字字体
QColor cBkgndColorVal = QColor(220,220,220);///背景颜色
QColor cBordersColors = QColor(192,192,192);///边框颜色
bool bAutoFontSizes = true; ///自动字体大小
bool operator == (const LQTIMGVERUIFY_STYLE_& rhs) // == 操作运算符重载
{
return (uObstructPoint == rhs.uObstructPoint)
&& (QString("%1").arg(dRcRoundRadius) == QString("%1").arg(rhs.dRcRoundRadius))
&& (QString("%1").arg(dObstructPsize) == QString("%1").arg(rhs.dObstructPsize))
&& (bAoutPointSize == rhs.bAoutPointSize)
&& (bAutoPointClrs == rhs.bAutoPointClrs)
&& (cObstructPoint == rhs.cObstructPoint)
&& (uObstructLines == rhs.uObstructLines)
&& (QString("%1").arg(dObstructLsize) == QString("%1").arg(rhs.dObstructLsize))
&& (bAutoLinesSize == rhs.bAutoLinesSize)
&& (bAutoLinesClrs == rhs.bAutoLinesClrs)
&& (cObstructLines == rhs.cObstructLines)
&& (bDarwBkgColors == rhs.bDarwBkgColors)
&& (bDrawFrmBorder == rhs.bDrawFrmBorder)
&& (QString("%1").arg(dBordersWidths) == QString("%1").arg(rhs.dBordersWidths))
&& (uCodeMaxLength == rhs.uCodeMaxLength)
&& (uCodeMinLength == rhs.uCodeMinLength)
&& (uCodeSetLength == rhs.uCodeSetLength)
&& (bCaseSensitive == rhs.bCaseSensitive)
&& (bAutoTextColor == rhs.bAutoTextColor)
&& (cCodeTextColor == rhs.cCodeTextColor)
&& (cBkgndColorVal == rhs.cBkgndColorVal)
&& (cBordersColors == rhs.cBordersColors)
&& (bAutoFontSizes == rhs.bAutoFontSizes);
}
bool operator != (const LQTIMGVERUIFY_STYLE_& rhs) // != 操作运算符重载
{
return !(*this == rhs);
}
}LQTIMGVERUIFY_STYLE,*PLQTIMGVERUIFY_STYLE;
下面上正菜,头文件主要代码如下
protected:
///重写鼠标按钮按下事件
void mousePressEvent(QMouseEvent *event) override;
///重写系统绘制事件
void paintEvent(QPaintEvent *event) override;
///绘制验证码
void OnDrawVerifyCode(QPainter *painter);
///重写大小更改事件
void resizeEvent(QResizeEvent *event) override;
private:
///控件风格数据结构体
LQTIMGVERUIFY_STYLE tCtrlStyleData;
///验证码文字数据
QString sVerifyCodeTxt;
///使用内部验证码生成
bool bInneBuildCode = true;
private:
/// 生成验证码随机文本
/// \brief BuildRandCodeVal
///
void BuildRandCodeVal();
/// 绘制验证码图片
/// \brief DrawVerifyImages
/// \return
///
QPixmap DrawVerifyImages();
public:
///更新图形验证码
/// \brief UpdateImagesCode
///
void UpdateImagesCode();
/// 验证字符是否与验证码匹配
/// \brief VerifyImagesCode
/// \param sCode
/// \return
///
bool VerifyImagesCode(const QString& sCode);
/// 保存验证码图片
/// \brief SavVerifyCodeImg
/// \param sFileName
/// \param sErr
/// \return
///
bool SavVerifyCodeImg(const std::u16string &sFileName,std::u16string &sErr);
/// 复制验证码图片到剪贴板
/// \brief CpyVerifyCodeImg
/// \return
///
bool CpyVerifyCodeImg();
public:
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
核心绘图代码如下:
///重写鼠标按钮按下事件
void Lncf_QImageVerify::mousePressEvent(QMouseEvent *event)
{
if(this->bInneBuildCode)
UpdateImagesCode();
else emit VerifyCodeClicks();
QWidget::mousePressEvent(event);
}
///重写系统绘制事件
void Lncf_QImageVerify::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing|QPainter::TextAntialiasing|QPainter::SmoothPixmapTransform);
OnDrawVerifyCode(&painter);
}
///绘制验证码
void Lncf_QImageVerify::OnDrawVerifyCode(QPainter *painter)
{
painter->setBrush(tCtrlStyleData.bDarwBkgColors?tCtrlStyleData.cBkgndColorVal:Qt::transparent);
painter->setPen(tCtrlStyleData.bDrawFrmBorder?QPen(tCtrlStyleData.cBordersColors,tCtrlStyleData.dBordersWidths):Qt::NoPen);
QRectF rcGlobal = this->rect().adjusted(tCtrlStyleData.dBordersWidths,tCtrlStyleData.dBordersWidths,-tCtrlStyleData.dBordersWidths,-tCtrlStyleData.dBordersWidths);
double dRectRadius = this->rect().height()*this->tCtrlStyleData.dRcRoundRadius;
QPainterPath pathGlobal;
pathGlobal.addRoundedRect(rcGlobal,dRectRadius,dRectRadius);
painter->fillPath(pathGlobal,QBrush(tCtrlStyleData.bDarwBkgColors?tCtrlStyleData.cBkgndColorVal:Qt::transparent));
painter->drawRoundedRect(rcGlobal,dRectRadius,dRectRadius);
QRectF rcBkgd = rcGlobal.adjusted(tCtrlStyleData.dBordersWidths+dRectRadius,tCtrlStyleData.dBordersWidths,-tCtrlStyleData.dBordersWidths-dRectRadius,-tCtrlStyleData.dBordersWidths);
QPen pen;
//画点
double dPointSize = tCtrlStyleData.bAoutPointSize?rcBkgd.height()/8.0:tCtrlStyleData.dObstructPsize;
int rcOffsetVal = tCtrlStyleData.dBordersWidths+1;
if(dPointSize<1.0) dPointSize = 1.0;
//pen.setWidthF(dPointSize);
painter->setPen(Qt::NoPen);
painter->setBrush(this->tCtrlStyleData.cObstructPoint);
double dPointRadius = this->tCtrlStyleData.dObstructPsize;
if(dPointRadius<0.75)dPointRadius=1.0;
for(uint i = 0;i < tCtrlStyleData.uObstructPoint;++i)
{
if(this->tCtrlStyleData.bAutoPointClrs){
#if QT_DEPRECATED_SINCE(5, 15)
painter->setBrush(QColor(QRandomGenerator::global()->bounded(256),QRandomGenerator::global()->bounded(256),QRandomGenerator::global()->bounded(256)));
#else
painter->setBrush(QColor(qrand()%256,qrand()%256,qrand()%256));
#endif
}
if(tCtrlStyleData.bAoutPointSize){
#if QT_DEPRECATED_SINCE(5, 15)
dPointRadius = QRandomGenerator::global()->bounded(dPointSize);
#else
dPointRadius = qrand()%(int)dPointSize;
#endif
if(dPointRadius<0.75)dPointRadius=1.0;
}
#if QT_DEPRECATED_SINCE(5, 15)
painter->drawEllipse(QRandomGenerator::global()->bounded((int)(rcBkgd.left()+rcOffsetVal),rcBkgd.right()),QRandomGenerator::global()->bounded(rcOffsetVal,rcBkgd.height()-rcOffsetVal),dPointRadius,dPointRadius);
#else
painter->drawEllipse(qrand()%(int)(rcBkgd.width()-rcOffsetVal),qrand()%(int)(rcBkgd.height()-rcOffsetVal),dPointRadius,dPointRadius);
#endif
}
//画线
double dLinesSize = tCtrlStyleData.bAutoLinesSize?rcBkgd.height()/20.0:tCtrlStyleData.dObstructLsize;
pen.setColor(this->tCtrlStyleData.cObstructLines);
painter->setBrush(Qt::NoBrush);
double dLineWidth = this->tCtrlStyleData.dObstructLsize;
if(dLineWidth<0.75)dLineWidth = 1.0;
pen.setWidthF(dLineWidth);
for(uint i = 0;i < tCtrlStyleData.uObstructLines;++i)
{
if(this->tCtrlStyleData.bAutoLinesClrs){
#if QT_DEPRECATED_SINCE(5, 15)
pen.setColor(QColor(QRandomGenerator::global()->bounded(256),QRandomGenerator::global()->bounded(256),QRandomGenerator::global()->bounded(256)));
#else
pen.setColor(QColor(qrand()%256,qrand()%256,qrand()%256));
#endif
}
int nIndex = 1;
#if QT_DEPRECATED_SINCE(5, 15)
nIndex =QRandomGenerator::global()->bounded(1,8);
#else
nIndex =qrand()%8;
#endif
pen.setStyle((Qt::PenStyle)nIndex);
if(tCtrlStyleData.bAutoLinesSize){
#if QT_DEPRECATED_SINCE(5, 15)
dLineWidth = QRandomGenerator::global()->bounded(dLinesSize);
#else
dLineWidth = qrand()%(int)dLinesSize;
#endif
if(dLineWidth<0.75)dLineWidth = 1.0;
pen.setWidthF(dLineWidth);
}
painter->setPen(pen);
#if QT_DEPRECATED_SINCE(5, 15)
painter->drawLine(QRandomGenerator::global()->bounded((int)(rcBkgd.left()+rcOffsetVal),rcBkgd.right()),QRandomGenerator::global()->bounded(rcOffsetVal,rcBkgd.height()),
QRandomGenerator::global()->bounded((int)(rcBkgd.left()+rcOffsetVal),rcBkgd.right()),QRandomGenerator::global()->bounded(rcOffsetVal,rcBkgd.height()));
#else
painter->drawLine(qrand()%(int)rcBkgd.width(),qrand()%(int)(rcBkgd.height()-rcOffsetVal),
qrand()%(int)rcBkgd.width(),qrand()%(int)(rcBkgd.height()-rcOffsetVal));
#endif
}
double dTextMargin = 2.0;
QRectF rcText = rcBkgd.adjusted(dTextMargin,dTextMargin,-dTextMargin,-dTextMargin);
double dFontMaxSize = rcText.height();
QFont fTextObjs = tCtrlStyleData.fCodeTextFonts;
fTextObjs.setBold(true);
fTextObjs.setPointSize(dFontMaxSize/3);
painter->setFont(fTextObjs);
//绘画字
pen.setColor(this->tCtrlStyleData.cCodeTextColor);
painter->setPen(pen);
if(this->sVerifyCodeTxt.length()!=tCtrlStyleData.uCodeSetLength){
this->sVerifyCodeTxt = "";
for(uint i=0;itCtrlStyleData.uCodeSetLength;i++){
this->sVerifyCodeTxt.append("0");
}
}
for(uint i = 0;i < this->tCtrlStyleData.uCodeSetLength;i++)
{
if(this->tCtrlStyleData.bAutoTextColor){
#if QT_DEPRECATED_SINCE(5, 15)
pen.setColor(QColor(QRandomGenerator::global()->bounded(256),QRandomGenerator::global()->bounded(256),QRandomGenerator::global()->bounded(256)));
#else
pen.setColor(QColor(qrand()%256,qrand()%256,qrand()%256));
#endif
painter->setPen(pen);
}
if(this->tCtrlStyleData.bAutoFontSizes){
#if QT_DEPRECATED_SINCE(5, 15)
fTextObjs.setPointSize(QRandomGenerator::global()->bounded((int)(dFontMaxSize/5),(dFontMaxSize/2)));
#else
fTextObjs.setPointSize(qrand()(dFontMaxSize/2));
#endif
painter->setFont(fTextObjs);
}
float fLeftMargin = rcText.left()+i*((rcText.width()/(tCtrlStyleData.uCodeSetLength)));
float fCharsWidth = rcText.width()/tCtrlStyleData.uCodeSetLength;
QRectF rcChar = QRectF(fLeftMargin,rcText.top(),fCharsWidth,rcText.height());
painter->drawText(rcChar,Qt::AlignCenter,sVerifyCodeTxt.at(i));
}
}
困了,先到这里