QT滑块图片验证程序

news2025/1/8 23:52:10

使用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);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1905487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python语法及写的工具代码总结

目录 python画图&处理图片python增大图片的大小&#xff08;比如将几百K的照片增加到几mb&#xff09;解决python画图无法显示中文的问题python画折线图 & 一张图上三条折线 & 设置折线marker & chatgpt画折线图的提示词python将png格式的图片转换为jpg格式的图…

Rockstar Games:铸造游戏传奇的不朽征程

在电子游戏的历史长廊中&#xff0c;Rockstar Games&#xff08;R星&#xff09;犹如一座巍峨的丰碑&#xff0c;以其无与伦比的创造力和深刻的社会影响力&#xff0c;成为了游戏界的传奇缔造者。自1998年诞生于纽约的喧嚣中&#xff0c;这家由Houser兄弟掌舵的游戏公司&#x…

每天一道面试题之浅浅讲一下java5中的自动装箱和自动拆箱

自动装箱自动拆箱 我们在java5中引入概念 把基本数据类型自动装箱成包装类 把包装类自动拆箱成基本数据类型 我们可以用javap查看字节码文件 首先我们要通过javac编译.java文件 获取字节码.class文件 然后用javap查看 源码 import java.util.ArrayList; import java.uti…

spRAG框架学习小结

spRAG是什么 spRAG是一个针对非结构化数据的检索引擎。它特别擅长处理对密集文本的复杂查询&#xff0c;比如财务报告、法律文件和学术论文。有两种关键方法用于提高性能&#xff0c;超越了普通的RAG系统&#xff1a; 自动上下文&#xff08;AutoContext&#xff09;&#xff…

C++语言相关的常见面试题目(三)

1. List底层实现原理 省流&#xff1a; list底层实现了一个双向循环链表。 每个元素&#xff08;或节点&#xff09;包含三个部分&#xff1a;数据域(_M_Storage)、前驱指针(_M_prev)、后继指针(_M_next)。 数据域&#xff1a;存储实际数据。 前驱指针&#xff1a;指向链表中…

一篇就够了,为你答疑解惑:锂电池一阶模型-在线参数辨识(附代码)

锂电池一阶模型-在线参数辨识 背景在线 VS 离线 参数辨识递推最小二乘法一阶戴维南Z域离散表达式 背景 锂电池一阶戴维南等效模型的基础知识和离线辨识方法&#xff0c;已经在上一期非常详细地讲解了一轮&#xff08;上期文章请戳此处&#xff09;&#xff0c;本期继续讲解一下…

美光科技在2024年1γ工艺技术在10纳米级别启动EUV试产

美光科技&#xff08;Micron&#xff09;在2024年针对其1γ&#xff08;1-gamma&#xff09;工艺技术在10纳米级别启动EUV&#xff08;极紫外光刻&#xff09;试产&#xff0c;这标志着存储行业巨头在EUV采用上的重要一步&#xff0c;尽管相比英特尔和台积电等其他半导体制造商…

PIP换源的全面指南

##概述 在Python的世界里&#xff0c;pip是不可或缺的包管理工具&#xff0c;它帮助开发者安装和管理Python软件包。然而&#xff0c;由于网络条件或服务器位置等因素&#xff0c;直接使用默认的pip源有时会遇到下载速度慢或者连接不稳定的问题。这时&#xff0c;更换pip源到一…

SpringBoot整合DataX数据同步(自动生成job文件)

SpringBoot整合Datax数据同步 文章目录 SpringBoot整合Datax数据同步1.简介设计理念 DataX3.0框架设计DataX3.0核心架构核心模块介绍DataX调度流程 2.DataX3.0插件体系3.数据同步1.编写job的json文件2.进入bin目录下&#xff0c;执行文件 4.SpringBoot整合DataX生成Job文件并执…

SAP_MM模块-特殊业务场景下的系统实现方案

一、业务背景 目前公司有一种电商业务&#xff0c;卖的是备品配件&#xff0c;是公司先跟供应商采购&#xff0c;然后再销售给客户&#xff0c;系统账就是按照正常业务来流转&#xff0c;公司进行采购订单入库&#xff0c;然后销售订单出库。 不过这种备品配件&#xff0c;实…

【服务器搭建】✈️用自己电脑搭建一个服务器!

目录 &#x1f44b;前言 &#x1f440;一、内网穿透 &#x1f331;二、内网穿透工具 &#x1f49e;️三、本地测试 3.1 环境准备 3.2 nginx 修改启动页面 3.3 神卓互联注册&#xff0c;创建映射规则 &#x1f4eb;四、章末 &#x1f44b;前言 小伙伴们大家好&#xff0c;一…

【算法笔记自学】第 7 章 提高篇(1)——数据结构专题(1)

7.1栈的应用 #include <iostream> #include <string> #include <stack> using namespace std;int main() {int n, x;string action;cin >> n;stack<int> s;for (int i 0; i < n; i) {cin >> action;if (action "push") {ci…

微信小程序毕业设计-社区门诊管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

从资金管理的角度 谈谈伦敦金投资技巧

刚进入伦敦金市场的时候&#xff0c;笔者认为技术分析是很重要的&#xff0c;所以将学习伦敦金投资技巧的精力全部投入到技术分析的学习中。经过一系列交易的亏损&#xff0c;笔者才发现&#xff0c;其实交易管理才是最重要的。如果管理得好&#xff0c;30%的胜率&#xff0c;投…

Liunx网络配置

文章目录 一、查看网络配置永久修改网卡临时修改网卡 二、查看主机名称 hostname三、查看路由表条目 route四、查看网络连接情况netstat五、获取socket统计信息ss六、查看当前系统中打开的文件和进程的工具lsof七、测试网络连通性ping八、跟踪数据包 traceroute九、域名解析 ns…

一个最简单的comsol斜坡稳定性分析例子——详细步骤

一个最简单的comsol斜坡稳定性分析例子——详细步骤 标准模型例子—详细步骤 线弹性模型下的地应力平衡预应力与预应变、土壤塑性和安全系数求解的辅助扫描

计算机网络之令牌环

1.令牌环工作原理 令牌环&#xff08;Token Ring&#xff09;是一种局域网&#xff08;LAN&#xff09;的通信协议&#xff0c;最初由IBM在1984年开发并标准化为IEEE 802.5标准。在令牌环网络中&#xff0c;所有的计算机或工作站被连接成一个逻辑或物理的环形拓扑结构。网络中…

Kyutai 推出了 Moshi Chat,这是一种既可以实时收听又可以说话的 AI

Kyutai 是一家专注于开放式 AI 研究的非营利性实验室&#xff0c;它推出了开源的 Moshi Chat 项目 Kyutai 是一家致力于推进人工智能 &#xff08;AI&#xff09; 开放研究的非营利性实验室&#xff0c;其最新创新 Moshi Chat 取得了重大进展。这种尖端的实时原生多模态基础模…

STM32-USART

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. 串口通信协议1.1 通信接口1.2 串口通信1.3 硬件电路1.4 电平标准1.5 串口参数及时序1.6 串口时序 2. USART串口通信2.1 USART简介2.2 USART框图2.3 USART基本结构2.4 数据帧2.5 数据帧-配置停止位2.6 起始位侦测2.…

dell Vostro 3690安装win11 23h2 方法

下载rufus-4.5.exe刻U盘去除限制 https://www.dell.com/support/home/zh-cn/product-support/product/vostro-3690-desktop/drivers dell官网下载驱动解压到U盘 https://dl.dell.com/FOLDER09572293M/2/Intel-Rapid-Storage-Technology-Driver_88DM9_WIN64_18.7.6.1010_A00_01…