如何用Qt抠一个圆形头像出来

简介: 如何用Qt抠一个圆形头像出来

如题,如何使用Qt抠一个圆形头像出来?

先来看效果:

首先加载一张图片,显示一个透明圆形,圆形外半透明,滚动鼠标滚轮,圆形区域变大变小。

鼠标按下可以拖动图片移动,来选定要截取的图片位置,按下”剪切并保存“按钮后,将会截取圆形区域下的图片,得到一张圆形图片。比如:

来看一下运行效果:

实现原理如下:

这个窗口使用的是QGraphicsView,其中图片是继承自QGraphicsPixmapItemcustompixmap,这里重新实现了它的itemChange方法,以限制图片的移动范围:

QVariant custompixmap::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemPositionChange  &&  scene()) // 控件发生移动
    {
        QPointF newPos = value.toPointF(); //即将移动的位置
        //限制的区域
        QRectF rect(-scene()->width() / 3, -scene()->width() / 3, (scene()->width() / 3) * 2, (scene()->width() / 3) * 2);
        SHOW(rect)
        if (!rect.contains(newPos)) // 是否在区域内
        {
            newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));
            newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top())));
            return newPos;
        }
    }
    return QGraphicsItem::itemChange(change, value);
}

其中需要注意的是限制的区域的设定,比如这里的

QRectF rect(-scene()->width() / 3, -scene()->width() / 3, (scene()->width() / 3) * 2, (scene()->width() / 3) * 2);

这里scene的宽度为220,输出rect看一下:

QRectF(-73.3333,-73.3333 146.667x146.667)

那这个矩形的范围大概也就是这样:

也就是图片的左上角只能在这个矩形区域内活动,也就限制了图片移动的范围。

再来看圆形区域的绘制:

这里定义一个CustomView继承自QGraphicsView,重新实现它的paintEventwheelEvent方法:

int radius = 150;//半径
void CustomView::paintEvent(QPaintEvent *e)
{
    //https://www.it610.com/article/3860174.htm
    //先调用QGraphicsView::paintEvent(e);再画自己的
    QGraphicsView::paintEvent(e);
    //https://www.codenong.com/cs106784396/
    QPainter painter(this->viewport());
    QPainterPath path1;
    //构建圆形路径
    mPoint.setX((width() / 2) - radius / 2);
    mPoint.setY((height() / 2) - radius / 2);
    path1.addEllipse(mPoint.x(), mPoint.y(), radius, radius);
    SHOW(radius)
    //设置颜色为半透明
    QColor color(192, 192, 192, 150);
    //填充除去圆形的范围
    painter.setBrush(QBrush(color));
    QPainterPath path;
    //整个view的路径
    path.addRect(rect());
    //path减去圆形的范围
    path -= path1;
    painter.setClipPath(path);
    //画矩形,注意,这里把圆形范围剔除了
    painter.drawRect(rect());
}
void CustomView::wheelEvent(QWheelEvent *event)
{
    QGraphicsView::wheelEvent(event);
    //限制圆形半径范围为[150,180]
    if(event->delta() > 0 && (radius - 10) >= 150){// 当滚轮远离使用者时
        radius -= 10;
    }else if (event->delta() < 0 && (radius + 10) <= 180){// 当滚轮向使用者方向旋转时
        radius += 10;
    }
    //https://www.codenong.com/cs106784396/
    this->viewport()->update();
}

paintEvent方法中填充一个半透明区域,注意要通过setClipPath减去一个圆形区域。在wheelEvent方法中根据滚轮,改变半径大小,并通过this->viewport()->update();刷新界面,重新绘制减去圆形区域的半透明区域,从而达到缩放圆形的效果。

当按下”剪切并保存“按钮后,根据当前圆形区域所在点的坐标及半径,并通过grab方法截取当前窗体这块区域:

void CustomView::grabPicture()
{
    SHOW(mPoint)
    //按照圆形所在矩形范围,截取当前截图
    QPixmap pixmap = grab(QRect(mPoint.x(), mPoint.y(), radius, radius));
    //截完后,扣圆形图片
    pixmap = PixmapToRound(pixmap, radius);
    //保存图片
    pixmap.save("here.png");
}

可以发现,这时截取的图片还不是圆形:

这里参考网上的方法,根据传入圆形区域的半径,抠取一个圆形图片:

//网上的方法,扣一个圆形图片出来
QPixmap PixmapToRound(const QPixmap &src, int radius)
{
    if (src.isNull()) {
        return QPixmap();
    }
    //构建一个透明的图片
    QPixmap pixmap(radius,radius);
    pixmap.fill(Qt::transparent);
    //在透明的图片上画
    QPainter painter(&pixmap);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    QPainterPath path;
    //画的范围为一个圆形
    path.addEllipse(0, 0, radius, radius);
    painter.setClipPath(path);
    //画图片
    painter.drawPixmap(0, 0, radius, radius, src);
    //返回这个图片
    return pixmap;
}

抠完后便得到了一个周围透明,形状为圆形的图片,保存即可!

所以,总结下来,前面做的工作都是根据用户鼠标的拖动及滚动确定要截取的图片大小及位置,之后通过截图截出一个小范围的图片,再根据圆形区域半径,抠一个圆形图片出来。嗯,就是酱~

正文结束。

下面介绍一种好用的调试方法:

我们可以新建一个common.h文件,里面定义一个调试用的宏:

#ifndef COMMON_H
#define COMMON_H
#ifdef DEBUG
    #include <QDebug>
#endif
#ifdef DEBUG
#define SHOW(x) qDebug() << #x << " : " << (x);
#else
#define SHOW(x)
#endif
#endif // COMMON_H

在Qt的pro文件中,配置在debug模式下,定义一个DEBUG宏:

CONFIG(debug, debug|release) {
    DEFINES += DEBUG
}

这样,在需要输出某个变量值的时候,只需要引入common.h头文件,在需要打印变量时使用SHOW即可,比如:

#include "common.h"
int a = 1;
SHOW(a)

这样做的一个好处是,输出只在debug模式下才有,release模式下不会产生输出,并且不会额外增大源文件。

完~

最后来抠一个小姐姐的头像:

项目地址:https://gitee.com/gao-yuelong/qtdemo/tree/master/cutpicture

欢迎下载试玩!

相关文章
|
2月前
|
前端开发 数据可视化 JavaScript
【五一创作】QML、Qt Quick /Qt中绘制圆形
【五一创作】QML、Qt Quick /Qt中绘制圆形
227 0
|
9月前
QT圆形进度条(QT桌面项目光照强度检测)
QT圆形进度条(QT桌面项目光照强度检测)
64 0
Qt之QRoundProgressBar(圆形进度条)
简述 QRoundProgressBar类能够实现一个圆形进度条,继承自QWidget,并且有和QProgressBar类似的API接口。 简述 详细说明 风格 颜色 字体 共有函数 共有槽函数 详细说明 主要有以下特性: 圆形进度条控件 高度可定制的 源码下载: Qt Circular Progress Bar Widget QRoundP
3636 0
|
2月前
|
网络协议 C++
C++ Qt开发:QTcpSocket网络通信组件
`QTcpSocket`和`QTcpServer`是Qt中用于实现基于TCP(Transmission Control Protocol)通信的两个关键类。TCP是一种面向连接的协议,它提供可靠的、双向的、面向字节流的通信。这两个类允许Qt应用程序在网络上建立客户端和服务器之间的连接。Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QTcpSocket`组件实现基于TCP的网络通信功能。
62 8
C++ Qt开发:QTcpSocket网络通信组件
|
2月前
|
算法 编译器 Linux
【Qt4 部署】ARM系统上使用Qt 4 进行开发的QWS 等环境变量部署
【Qt4 部署】ARM系统上使用Qt 4 进行开发的QWS 等环境变量部署
48 0
|
12天前
|
关系型数据库 MySQL 项目管理
数据库大作业——基于qt开发的图书管理系统(四)项目目录的整理与绘制登录页面
数据库大作业——基于qt开发的图书管理系统(四)项目目录的整理与绘制登录页面
|
12天前
|
SQL 关系型数据库 MySQL
数据库大作业——基于qt开发的图书管理系统(三)Qt连接Mysql数据库
数据库大作业——基于qt开发的图书管理系统(三)Qt连接Mysql数据库
|
12天前
|
SQL 数据可视化 关系型数据库
数据库大作业——基于qt开发的图书管理系统(二) 相关表结构的设计
数据库大作业——基于qt开发的图书管理系统(二) 相关表结构的设计
|
12天前
|
安全 BI 数据库
数据库大作业——基于qt开发的图书管理系统 (一)环境的配置与项目需求的分析
数据库大作业——基于qt开发的图书管理系统 (一)环境的配置与项目需求的分析
|
2月前
|
区块链
【qt】最快的开发界面效率——混合编程3
【qt】最快的开发界面效率——混合编程
45 1

推荐镜像

更多