一、前言
作者:小成Charles
转载请标注作者原链接:https://blog.csdn.net/weixin_42999453/article/details/109709684
今天没事用Qt写了一个验证码模块的demo,平时很少用Qpainter,这次就做了这个demo练练手,话不多说直接上图看效果
二、分析
做这种的效果主要是弄清楚坐标的位置关系以及paintEvent
事件的灵活运用
(1)分析坐标
为了方便理解我画了一张图如下,要注意的一点就是当前矩形的x,y
坐标的起点位置是左上角点,其中ABCD
使我们需要的坐标位置来存放验证码的位置,这样均分看起来就比较美观嘛,第一个字符X坐标为(x+w/4)/2
,依此类推,他们之间相差的距离都为w/2
。然后Y
坐标就是固定的(y+h)/2
,这样每一个字符的坐标位置就很明确了;
(2)paintEvent事件分析
其中有一些注意点像我这样的小白玩家需要注意:
painEvent
中如果需要创建多个Qpainter
对象时,需要将前一个Qpainter
对象end
,才能进行下一个Qpainter
对象,不然无法加载下一个!- 在
painEvent
事件中不要做一些数据存储的代码块,因为非Qpainter
类下的代码块会被重复运行,我就是因为在里面写随机数获取存储的内容被重复运行,然后导致我最后验证码数据和图片不匹配,所以尽量在外部把数据处理好了再传到paintEvent
里面去
三、上代码!
mainWindow.h 头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPaintEvent>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *e);
void paintDots();//画背景点
void drawChars();//画字符
QString textCode="初始化验证码";
QString chrs= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";//字符集
void getRandchar();//获取随机字符
~MainWindow();
private slots:
void on_btnChange_2_clicked();
void on_btnVretifiy_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
这里是画背景的代码块paintDots()
,实现了各色随机的点
void MainWindow::paintDots()
{
int maxPosX=ui->label->pos().x()+ui->label->width();
int minPosX=ui->label->pos().x();
int maxPosY=ui->label->pos().y()+ui->label->height();
int minPosY=ui->label->pos().y();
//画点
QPainter *painterPoints=new QPainter;
painterPoints->begin(this);
QPen pen;
QBrush brush;
brush.setColor(Qt::white);
brush.setStyle(Qt::SolidPattern);
painterPoints->setBrush(brush);
painterPoints->drawRect(QRect( ui->label->pos(),QPoint(maxPosX,maxPosY)));
QColor color;
pen.setWidth(3);
pen.setStyle(Qt::DotLine);
// qDebug()<<maxPosX<<maxPosY;
QPoint *points=new QPoint[500];
for (int i=0;i<300;i++) {
points[i]=QPoint(qrand()%(maxPosX-minPosX)+minPosX,qrand()%(maxPosY-minPosY)+minPosY);
int R=qrand()%255;
int G=qrand()%255;
int B=qrand()%255;
color.setRgb(R,G,B);
pen.setColor(color);
painterPoints->setPen(pen);
painterPoints->drawPoint(points[i]);
}
painterPoints->end();
}
这里是drawChars()
,实现了在图中华出四个随机的字符,且每个字符的颜色都不一样
void MainWindow::drawChars()
{//画字符
qreal labelWidth=ui->label->width();
qreal labelHeight=ui->label->height();
qreal labelx=ui->label->pos().x();
qreal labely=ui->label->pos().y();
int maxPosX=ui->label->pos().x()+ui->label->width();
int maxPosY=ui->label->pos().y()+ui->label->height();
QRect rect( ui->label->pos(),QPoint(maxPosX,maxPosY));
QPainter *painter=new QPainter;
painter->begin(this);
QFont font;
QPen pen;
pen.setWidth(3);
font.setPointSize(20);
font.setBold(true);
painter->setFont(font);
//画随机字符
for(int i=0;i<4;i++)
{
// qDebug()<<str;
int R=qrand()%255;
int G=qrand()%255;
int B=qrand()%255;
QColor color;
color.setRgb(R,G,B);
pen.setColor(color);
painter->setPen(pen);
QPointF pointF;
pointF.setX(labelx+(labelWidth/7+(labelWidth/4)*(i*2))/2);
pointF.setY(labely+(labelHeight/1.5));
// qDebug()<<pointF;
// int randomx=qrand()%(chrs.length()-1);
painter->drawText(pointF,textCode.at(i));
// textCode.append(textCode.at(i));
}
painter->end();
}.
接下来就是paintEvent
中调用这两个函数,依次画图合成了验证码,利用update()可以实现验证码的刷新,这里注意,因为获取随机验证码字符串是在外部函数实现的,更新的时候需要将getRandchar()
调用一下
void MainWindow::getRandchar()
{
textCode.clear();
int chrs_size = chrs.length();//字符集数组长度
for(int i=0;i<4;i++)
{
int randomx=qrand()%(chrs_size-1);
QString str = chrs.at(randomx);
textCode.append(str);
}
qDebug()<<textCode;
}
void MainWindow::paintEvent(QPaintEvent *e)
{
paintDots();
drawChars();
}
void MainWindow::on_btnChange_2_clicked()
{
//
getRandchar();
this->update();
}
void MainWindow::on_btnVretifiy_clicked()
{
if(textCode==ui->lineEdit->text())
{
QMessageBox::information(this,"right","验证码正确");
qDebug()<<"正确";
}else {
QMessageBox::information(this,"right","验证码错误");
qDebug()<<"错误";
}
}