QT滑块图片验证程序

使用QT实现滑块验证程序,原理是画个图片,然后在图片上画个空白区域,再画个滑块图片。

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private:
    void initForm();
    void drawPicture();

private slots:
    void onUpdateWidget();
    void onSliderValueChanged(int value);
    void onSliderReleased();
    void onUpdatePixmap();

protected:
    bool eventFilter(QObject *watched, QEvent *event);
    void paintEvent(QPaintEvent *event);

private:
    Ui::Widget *ui;

    QString m_pixmap;
    QPoint m_offsetPoint;
    int m_value;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPainterPath>
#include <QDebug>
#include <QMessageBox>
#include <QTimer>
#include <QSlider>
#include <QRandomGenerator>

const int squarewidth = 46;
const int squareradius = 20;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setFixedHeight(600);
    this->setFixedWidth(800);

    m_value = 0;
    m_offsetPoint = QPoint(0, 0);
    ui->widget->installEventFilter(this);
    this->initForm();
}

Widget::~Widget()
{
    delete ui;
}

void Widget::initForm()
{
    QTimer::singleShot(10, this, SLOT(onUpdateWidget()));
    connect(ui->horizontalSlider, &QSlider::valueChanged, this, &Widget::onSliderValueChanged);
    connect(ui->horizontalSlider, &QSlider::sliderReleased, this, &Widget::onSliderReleased);
    m_pixmap = QString("H:\\picture\\TorchLight\\TorchLight0.bmp");

    QTimer::singleShot(100, this, SLOT(onUpdatePixmap()));

}

void Widget::onUpdateWidget()
{
    ui->horizontalSlider->setRange(0, ui->widget->width() - squarewidth);
}

void Widget::onUpdatePixmap()
{
    m_offsetPoint.rx() = qBound(0, QRandomGenerator::global()->bounded(1024*10) % this->width() + squarewidth + squareradius,
                                                                  this->width() - squarewidth);
    m_offsetPoint.ry() = qBound(0, QRandomGenerator::global()->bounded(1024*10) % ui->widget->height() + squarewidth + squareradius,
                                                                  ui->widget->height() - squarewidth - squareradius);
    qDebug()<<m_offsetPoint.rx()<<m_offsetPoint.ry();
    this->update();
}

void Widget::onSliderValueChanged(int value)
{
    //ui->widget->setValue(value);
    m_value = qBound(0, value, ui->widget->width() - squarewidth);
    update();
}

void Widget::onSliderReleased()
{
    bool isOverlap = qAbs(-m_offsetPoint.x() + m_value) < 5;
    QString content = isOverlap ? "验证成功!" : "验证失败!";
    QMessageBox msgBox;
    msgBox.setWindowTitle("滑块图片验证");
    msgBox.setText(content);
    msgBox.exec();

}

void Widget::drawPicture()
{
    QPainter painter(ui->widget);
    painter.setRenderHint(QPainter::Antialiasing);
    QPainterPath clippath;
    clippath.addRoundedRect(ui->widget->rect(), 4, 4);
    painter.setClipPath(clippath);
    //画背景图
    const QPixmap & pixmap = QPixmap(m_pixmap).scaled(ui->widget->width(), ui->widget->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    painter.drawPixmap(0, 0, ui->widget->width(), ui->widget->height(), pixmap);

    QPainterPath cutoutpath;
    cutoutpath.setFillRule(Qt::WindingFill);
    QRect rect(m_offsetPoint, QSize(squarewidth, squarewidth));
    cutoutpath.addEllipse(rect);

    //画被扣除的空白区域
    QPainterPath subellipsepath;
    subellipsepath.addEllipse(rect.x(), rect.y() - rect.height() / 2, rect.width(), rect.height());
    cutoutpath = cutoutpath.united(subellipsepath);

    painter.setPen(QPen(QColor(80, 80, 80), 1));
    painter.setBrush(QColor(200, 200, 200, 220));
    painter.drawPath(cutoutpath);

    //画滑块图片
    QPixmap puzzlePixmap(ui->widget->size());
    puzzlePixmap.fill(Qt::transparent);
    QPainter puzzlePainter(&puzzlePixmap);
    puzzlePainter.setRenderHints(QPainter::Antialiasing);
    puzzlePainter.setClipPath(cutoutpath);
    puzzlePainter.setPen(QPen(QColor(229, 228, 228), 2));

    puzzlePainter.drawPixmap(0, 0, ui->widget->width(), ui->widget->height(), pixmap);
    puzzlePainter.drawPath(cutoutpath);

    painter.drawPixmap(-m_offsetPoint.x() + m_value, 0, ui->widget->width(), ui->widget->height(), puzzlePixmap);

}

bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == ui->widget && event->type() == QEvent::Paint)
    {
        drawPicture();
        return true;
    }
    return QWidget::eventFilter(watched, event);
}

void Widget::paintEvent(QPaintEvent *)
{

}

QSlider的样式表

 QSlider::groove:horizontal {
     border: 1px solid #999999;
     height: 10px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */
     background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c004);
     margin: 2px 0;
 }

 QSlider::handle:horizontal {
     background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f0f8f);
     border: 1px solid #5c0c5c;
     width: 18px;
     margin: -12px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */
     border-radius: 3px;
 }

空白区域画法

在painter中绘制一个封闭的painterpath。path中的路径通过添加形状的方式自己设置。背景色通过setBrush设置。

QPainterPath cutoutpath;
cutoutpath.setFillRule(Qt::WindingFill);
QRect rect(m_offsetPoint, QSize(squarewidth, squarewidth));
cutoutpath.addEllipse(rect);

//画被扣除的空白区域
QPainterPath subellipsepath;
subellipsepath.addEllipse(rect.x(), rect.y() - rect.height() / 2, rect.width(), rect.height());
cutoutpath = cutoutpath.united(subellipsepath);

painter.setPen(QPen(QColor(80, 80, 80), 1));
painter.setBrush(QColor(200, 200, 200, 220));
painter.drawPath(cutoutpath);

形状可以任意修改

//画被扣除的空白区域
    QPainterPath cutoutpath;
    cutoutpath.setFillRule(Qt::WindingFill);
    QRect rect(m_offsetPoint, QSize(squarewidth, squarewidth));
    cutoutpath.addEllipse(rect);
    cutoutpath.addRect(QRect(m_offsetPoint.x() + squarewidth/2, m_offsetPoint.y() + squarewidth/2, squarewidth, squarewidth));


    painter.setPen(QPen(QColor(80, 80, 80), 1));
    painter.setBrush(QColor(200, 200, 200, 220));
    painter.drawPath(cutoutpath);

填充规则

QPainterPath中setFillRule()共有两个填充规则:Qt::OddEvenFillQt::WindingFill

其中,Qt::OddEvenFill使用的是奇偶填充规则,具体来说就是:如果要判断一个点是否在图形中,那么可以从该点向图形外引一条水平线﹐如果该水平线与图形的交点的个数为奇数,那么该点就在图形中。这个规则是默认值;

Qt::WindingFill使用的是非零弯曲规则,具体来说就是:如果要判断一个点是否在图形中,那么可以从该点向图形外引一条水平线,如果该水平线与图形的边线相交,这个边线是顺时针绘制的,就记为1;是逆时针绘制的就记为-1。然后将所有数值相加,如果结果不为0,那么该点就在图形中。


对于Qt::OddEvenFill规则,第一个交点记为1,第二个交点记为2;
对于Qt::WindingFill规则,因为椭圆和矩形都是以顺时针进行绘制的,所以各个交点对应的边都使用1来代表。

滑块图片画法

注意puzzlePainter指向puzzlePixmap,puzzlePixmap是个透明图,在里面绘制同上方空白区域的painterpath可见,然后合并图片和空白区域的painter。

QPixmap puzzlePixmap(ui->widget->size());
    puzzlePixmap.fill(Qt::transparent);
    QPainter puzzlePainter(&puzzlePixmap);
    puzzlePainter.setRenderHints(QPainter::Antialiasing);
    puzzlePainter.setClipPath(cutoutpath);
    puzzlePainter.setPen(QPen(QColor(229, 228, 228), 2));

    puzzlePainter.drawPixmap(0, 0, ui->widget->width(), ui->widget->height(), pixmap);
    puzzlePainter.drawPath(cutoutpath);

    painter.drawPixmap(-m_offsetPoint.x() + m_value, 0, ui->widget->width(), ui->widget->height(), puzzlePixmap);

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt 是一款跨平台的 C++ 图形用户界面开发框架,可以用于实现各种图形图像处理软件。我们可以利用 Qt 的图形界面编程功能来开发一个图片编辑程序。 首先,我们需要创建一个主窗口,并在主窗口中添加一些工具栏、菜单栏和画布控件。工具栏中可以放置一些常用的图像编辑工具,如画笔、填充、橡皮擦等。菜单栏中可以添加文件、编辑、视图等功能菜单,如打开、保存、撤销、重做等。画布控件用于显示图像并进行操作。 在图像编辑程序中,我们还需要实现一些基本的图像处理功能。比如,我们可以添加一个裁剪工具,让用户选择感兴趣的区域,并裁剪图像。还可以实现缩放功能,让用户调整图像的大小。此外,我们还可以添加一些滤镜效果,如黑白、模糊、亮度调整等,让用户对图像进行艺术处理。 另外,我们还可以实现一些高级的图像编辑功能。比如,添加绘图工具,让用户可以在图像上绘制各种图形,如线条、矩形、椭圆等。还可以实现图像融合功能,将多张图像叠加在一起,并调整不透明度,实现合成效果。此外,还可以实现一些特效功能,如马赛克、文字添加等,让用户能够对图像进行创意处理。 总的来说,通过使用 Qt 的图形界面编程功能,我们可以实现一个功能丰富的图片编辑程序。这个程序可以提供各种图像处理工具和效果,让用户能够方便快捷地进行图片编辑和美化。同时,通过 Qt 的跨平台特性,我们可以将这个程序运行在多个操作系统上,提供更好的用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值