如何用Qt实现头像剪辑窗口---手把手系列

利用Qt制作一个头像获取剪辑窗口,这里重点说的是可移动双窗口的实现流程。

bfeb861c43294b8bb4afe3d2d7d51f54.png

实现效果如下,通过移动中间的裁剪区域可以获得一张裁剪后的图片。右边是两个预览窗口,并且支持本地图片上传和截图的保存。

下面我主要讲解的是中间裁剪区域双窗口的实现逻辑,至于如何上传图片,如何将截图获取出来,以及如何更改预览图片实现裁剪同步。可以参考一下后续发布的源码。

把中间的区域单独拎出来,是这么个效果:

998caf02da1d4850a31d5d4bae74ad66.png

整个窗口分两部分,一部分是用来显示一张完整的图片,另一个小窗口用来获取目前准备裁剪的图片。

底层窗口上,因为它只是显示一张完整的图片,所以很容易想到在QWidget部件的基础上添加一个QLabel,创建一个自定义部件进行实现。

需要注意的是,它的绘图方式有所不同,正常情况下QWidget的部件绘图是全部高亮的,但是这里发现除了裁剪区域以外的部分都是暗黑色。

因此我们这里要做一个区分,把QWidget中显示图片的label分成正在被裁剪窗口选中的矩形区域和未被选中的矩形区域,其中,被选中的矩形区域,因为需要它随着鼠标的拖动而去移动,所以它也是一个自定义部件。并且这个自定义部件要重写mousePressEvent等鼠标移动的函数。

具体实现如下:

这段代码实现了装载图片显示的整个窗口,重点关注它的重绘事件。需要注意的是,

m_cutDialog是裁剪矩形,也就是一个高亮部分的矩形,这个矩形当然也可以用QWidget去实现,但是需要重写mousePressEvent函数,使它能跟着鼠标拖动,并且设置好它的初始坐标和在整个图片中的初始位置。
#include "photoshotdialog.h"
#include <QPainterPath>
#include <QPainter>
#include <QBrush>
PhotoShotDialog::PhotoShotDialog(QWidget *parent):QWidget(parent)
{
    this->setGeometry(0,0,parentWidget()->width(),parentWidget()->height());
    m_cutDialog = new CutDialog(this);
    m_cutDialog->show();
}

PhotoShotDialog::~PhotoShotDialog()
{

}

void PhotoShotDialog::paintEvent(QPaintEvent *event)
{
    QPainterPath painterPath;
    QPainterPath p;
    p.addRect(x(),y(),this->rect().width(),this->rect().height());//整个矩形
    painterPath.addRect(m_cutDialog->geometry());//裁剪矩形
    QPainterPath drawPath = p.subtracted(painterPath);//整个矩形中除了裁剪矩形之外的窗口
    QPainter painter(this);
    painter.setOpacity(0.5);//设置透明度,0表示全透明,1表示不透明,这里是部分透明
    painter.fillPath(drawPath,QBrush(Qt::black));

}

QRect PhotoShotDialog::getCutGeometry()
{
    return m_cutDialog->geometry();
}

m_cutDialog类实现如下:

这里一开始设置好坐标和大小,坐标我选择放在图片的正中间。

m_mousePress是鼠标是否按下的标志位,一开始设置为false。

#include "cutdialog.h"
#define CUT_WIDTH 100
#define CUT_HEIGHT 100
CutDialog::CutDialog(QWidget *parent) : QWidget(parent)
{
    setGeometry(parent->width()/2-CUT_WIDTH/2,parent->height()/2-CUT_HEIGHT/2,CUT_WIDTH,CUT_HEIGHT);
    m_mousePress = false;
}

CutDialog::~CutDialog()
{

这段代码的初始化效果如下:

92f53ef678674da5b087d985cdf7df8c.png

重点是下面的鼠标事件处理函数:

void CutDialog::mousePressEvent(QMouseEvent *event)
{
    //鼠标开始的位置
    if(event->buttons() == Qt::LeftButton)
    {
        m_startPoint = event->pos();
        m_mousePress = true;
    }
}
void CutDialog::mouseMoveEvent(QMouseEvent *event)
{
    QPoint dragPoint = event->pos();
    if(m_mousePress)
    {
        QPoint p =QPoint(pos().x()+dragPoint.x()-m_startPoint.x(),pos().y()+dragPoint.y()-m_startPoint.y());
        QPoint dragEndge;
        dragEndge.setX(p.x()+rect().width());
        dragEndge.setY(p.y()+rect().height());
        if(p.x()<0)p.setX(0);
        if(p.y()<0)p.setY(0);
        if(dragEndge.x()>parentWidget()->width())p.setX(parentWidget()->width()-rect().width());
        if(dragEndge.y()>parentWidget()->height())p.setY(parentWidget()->height()-rect().height());
        move(p);
    }
}

void CutDialog::mouseReleaseEvent(QMouseEvent *event)
{
    //if(event->buttons() == Qt::LeftButton)
    //{
        m_mousePress = false;
    //}
}

逻辑解释:

在鼠标左键按下的时候,获取鼠标位置为m_startPoint,并将标志位置为ture。

鼠标拖动时,获取鼠标当前的位置,然后得出窗口需要移动的点为:

鼠标当前位置减去鼠标开始位置在加上窗口一开始位于部件的位置。

dd8edf12ed12410591f7aef22dfdb783.png

后面是一些不能超出窗口界限的判断。

最后送开时鼠标标志位置为false即可。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
qt-vs-addin-1.2.4-opensource是一个开源的Qt集成开发环境插件。Qt是一种跨平台的应用程序开发框架,它允许开发者使用统一的代码库编写跨平台的应用程序。Qt提供了丰富的库和工具,使得开发者可以更方便地创建GUI应用程序、网络应用程序、嵌入式应用程序等。 而qt-vs-addin-1.2.4-opensource则是为了方便使用Visual Studio开发Qt应用程序而开发的插件。Visual Studio是一种常用的集成开发环境,它提供了强大的编辑器、调试器和其他开发工具。而通过qt-vs-addin-1.2.4-opensource插件,开发者可以在Visual Studio中直接使用Qt的功能,如自动生成Qt项目、添加Qt类、设计器支持等。 qt-vs-addin-1.2.4-opensource主要的特点包括: 1. 支持多个Visual Studio版本:这个插件可以与不同版本的Visual Studio(如2010、2012、2013等)兼容,方便开发者选择自己喜欢的开发环境。 2. 丰富的项目模板:插件提供了多种项目模板,包括Qt Widgets应用程序、Qt Quick应用程序等,可以帮助开发者快速创建项目并开始开发。 3. 代码自动补全:插件可以提供Qt类的代码自动补全功能,方便编写代码并减少出错。 4. 可视化设计器:插件还提供了可视化设计器,开发者可以通过拖放控件来快速设计界面。 5. 调试支持:插件可以与Visual Studio的调试器集成,方便开发者进行调试。 总体而言,qt-vs-addin-1.2.4-opensource是一个强大且易于使用的插件,它为开发者提供了更好的开发体验和效率,使得使用Qt开发跨平台应用程序更加便捷。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值