QT实现头像图片剪切框

近期在做一个qt项目,在用户选择头像图片后,需要将图片载入,并对其进行用户自定义裁剪。通过研究参照各流行软件的裁剪方式后,发现qq实现的裁剪比较好看,于是,我想那就做一个和qq相似的吧。先放一张qq实现的效果,然后最后再放我实现的效果。

1. 怎样去实现裁剪


于一张载入的图片,要实现用户自定义裁剪,那么首先我需要有一个能够响应用户自由缩放的边框,当用户缩放到心仪大小,再摆到适当位置,我能知道框的位置及
长宽,那么获取框里面的图片就很简单了。另外,我需要阴影,只有在框里面的图像部分是正常的,其他部分均被阴影覆盖。于是,实现该功能,大致需要两件东
西,框及阴影。

框的实现可以定义无边框的窗口,如widget,frame,当一个窗口被定义为无边框时,那么该窗口势必无法再响应鼠标的拖动事件,也就是该边框将不能移动,也不能缩放,因此,我们需要重写鼠标事件,实现边框的拖动,以及自由缩放。

阴影的实现可以使用黑色的画笔,并设置透明度,去填充边框之外的区域。

2. 缩放边框的实现

要想缩放边框实现拖动及自由缩放,那么需要重写该边框的mousePressEvent、mouseMoveEvent、mouseReleaseEvent三个事件。具体见如下代码

2.1对mousePressEvent的重写

m_startPoint 用户记录鼠标点击下的事件,  而后期只需要算出移动时鼠标的坐标与初始坐标的差值,进行移动即可。代码如下:

[html] view plain copy

  1. void CutDialog::mousePressEvent(QMouseEvent * event)
  2. {
  3. m_startPoint = event->pos();
  4. m_mouse_down = event->button() == Qt::LeftButton;
  5. }

2.2 对mouseMoveEvent 的重写


鼠标移动过程中,获取鼠标当前的位置,判断鼠标当前状态,如果是落在边框上,则改变鼠标形状成对应的边界鼠标形状,如果落在窗口区域内,则改变鼠标形状为
移动形状。如果鼠标在移动之前有点击事件,则进行相应判断,决定是移动还是放大缩小。

[cpp] view plain copy

  1. void CutDialog::mouseMoveEvent(QMouseEvent * event)
  2. {
  3. QPoint dragPoint = event->pos();
  4. int x = event->x();
  5. int y = event->y();
  6. if(m_mouse_down)
  7. {
  8. QRect g = getResizeGem(geometry(), dragPoint);

[cpp] view plain copy

  1. <span style="white-space:pre">        </span>//实现对当前窗口的拖放
  2. if(parentWidget()->rect().contains(g))
  3. setGeometry(g);
  4. m_startPoint = QPoint(!m_right? m_startPoint.x():event->x(),!m_bottom? m_startPoint.y():event->y());
  5. <span style="white-space:pre">    </span>

[cpp] view plain copy

  1. <span style="white-space:pre">        </span>//实现对当前的移动
  2. if(!m_left && !m_right && !m_bottom && !m_top)
  3. {
  4. QPoint p = QPoint((pos().x()+dragPoint.x() - m_startPoint.x()), (pos().y()+dragPoint.y() - m_startPoint.y()));
  5. QPoint dragEndge = p;
  6. dragEndge.setX(dragEndge.x() + rect().width());
  7. dragEndge.setY(dragEndge.y() + rect().height());
  8. p.setX(p.x() < 0? 0 : p.x());
  9. p.setX(dragEndge.x() > parentWidget()->width()?parentWidget()->width()-rect().width():p.x());
  10. p.setY(p.y() < 0? 0 : p.y());
  11. p.setY(dragEndge.y() > parentWidget()->height()?parentWidget()->height()-rect().height():p.y());
  12. move(p);
  13. }
  14. }
  15. else
  16. {

[cpp] view plain copy

  1. <span style="white-space:pre">        </span>//根据位置判断相应的鼠标形状
  2. QRect r = rect();
  3. m_left = qAbs(x - r.left())  < 5;
  4. m_right = qAbs(x - r.right()) < 5;
  5. m_bottom = qAbs(y - r.bottom()) < 5;
  6. m_top = qAbs(y - r.top()) < 5;
  7. bool lorr = m_left | m_right;
  8. bool torb = m_top | m_bottom;
  9. if(lorr && torb)
  10. {
  11. if((m_left && m_top) || (m_right && m_bottom))
  12. {
  13. setCursor(Qt::SizeFDiagCursor);
  14. }
  15. else
  16. setCursor(Qt::SizeBDiagCursor);
  17. }
  18. else if(lorr)
  19. setCursor(Qt::SizeHorCursor);
  20. else if(torb)
  21. setCursor(Qt::SizeVerCursor);
  22. else
  23. {
  24. setCursor(Qt::SizeAllCursor);
  25. m_bottom = m_left = m_right = m_top = false;
  26. }
  27. }
  28. }

实现鼠标在移动过程中获得新的鼠标欲拉伸的大小,在这里需要注意的是,因为剪切的图片应该是正方形,所以,在改变大小时长和宽都要做等比例的缩放。代码实
现如下:

[cpp] view plain copy

  1. QRect CutDialog::getResizeGem(QRect oldgeo, QPoint mousePoint)
  2. {
  3. QRect g = oldgeo;
  4. bool lorr = m_left | m_right;
  5. bool torb = m_top | m_bottom;
  6. int dx = mousePoint.x() - m_startPoint.x();
  7. int dy = mousePoint.y() - m_startPoint.y();
  8. if(lorr && torb)
  9. {
  10. int maxLen = qMin(qAbs(dx),qAbs(dy));
  11. if(m_left && m_top && dx*dy >0)
  12. {
  13. g.setLeft(dx >0 ?g.left() + maxLen : g.left() - maxLen);
  14. g.setTop(dy >0? g.top() + maxLen : g.top() - maxLen);
  15. }
  16. if(m_right && m_top && dx*dy < 0)
  17. {
  18. g.setRight(dx>0 ? g.right() + maxLen:g.right() - maxLen);
  19. g.setTop(dy >0? g.top() + maxLen : g.top() - maxLen);
  20. }
  21. if(m_right && m_bottom && dx*dy > 0)
  22. {
  23. g.setRight(dx>0 ? g.right() + maxLen:g.right() - maxLen);
  24. g.setBottom(dy >0? g.bottom() + maxLen : g.bottom() - maxLen);
  25. }
  26. if(m_left && m_bottom && dx*dy < 0)
  27. {
  28. g.setLeft(dx >0 ?g.left() + maxLen : g.left() - maxLen);
  29. g.setBottom(dy >0? g.bottom() + maxLen : g.bottom() - maxLen);
  30. }
  31. return g;
  32. }
  33. else if(lorr)
  34. {
  35. if(m_left)
  36. g.setLeft(g.left() + dx);
  37. if(m_right)
  38. g.setRight(g.right() + dx);
  39. int len = g.width() - oldgeo.width();
  40. int intHight = (int) len/2.0;
  41. g.setTop(g.top() - intHight);
  42. g.setBottom(g.bottom() + len - intHight);
  43. }
  44. else if(torb)
  45. {
  46. if(m_bottom)
  47. g.setBottom(g.bottom() + dy);
  48. if(m_top)
  49. g.setTop(g.top() + dy);
  50. int dheigt = g.height() - oldgeo.height();
  51. int intWidth = (int) dheigt/2.0;
  52. g.setLeft(g.left() - intWidth);
  53. g.setRight(g.right() + dheigt - intWidth);
  54. }
  55. return g;
  56. }

2.3 对mouseReleaseEvent的重写

[cpp] view plain copy

  1. void CutDialog::mouseReleaseEvent(QMouseEvent * event)
  2. {
  3. m_mouse_down = false;
  4. }

3. 阴影的实现

阴影的实现需要创建新的窗口类,并在该窗口类中初始化上面的缩放边框,并对边框外的区域进行阴影填充。代码如下:

[html] view plain copy

  1. void PhotoShotDialog::paintEvent(QPaintEvent *e)
  2. {
  3. QPainterPath painterPath;
  4. QPainterPath p;
  5. p.addRect(x(),y(),rect().width(),rect().height());
  6. painterPath.addRect(dialog->geometry());
  7. QPainterPath drawPath =p.subtracted(painterPath);
  8. QPainter paint(this);
  9. paint.setOpacity(0.7);
  10. paint.fillPath(drawPath,QBrush(Qt::black));
  11. }

4. 切图

[cpp] view plain copy

  1. 切图只需使用到QPixmap的copy函数即可,函数参数即是窗口的位置及大小。

[cpp] view plain copy

  1. QPixmap pix = scaledPix.copy(pdialog->getShotGeometry());
  2. pix.save("C:/Users/dana/Desktop/1.png","png");

若有下载源码的需要,请戳:http://download.csdn.net/detail/u010511236/8462929

最终实现效果如下:

时间: 2024-08-24 01:28:01

QT实现头像图片剪切框的相关文章

qt实现头像上传功能(写了4个类,朝十晚八的博客,非常好)

想必大家都使用过qt的自定义头像功能吧,那么图1应该不会陌生,本片文章我就是要模拟一个这样的功能,虽然没有这么强大的效果,但是能够满足一定的需求. 图1 qq上传图片 首先在讲解功能之前,我先给出一片文章,QT实现的类似QQ的头像选择框,这篇文章也是讲解头像上传功能的,而我自己的代码是从这个demo中优化而来,不仅对代码进行了重构,而且处理了快速拖动时,边框消失的问题.使用事件和双缓冲来尽量减少重新绘制的几率.接下里我会一步一步进行讲解,怎么实现图片自定义截取功能.一.概要首选,我给出4个类,并

qt实现头像上传功能

想必大家都使用过qt的自定义头像功能吧,那么图1应该不会陌生,本片文章我就是要模拟一个这样的功能,虽然没有这么强大的效果,但是能够满足一定的需求. 图1 qq上传图片 首先在讲解功能之前,我先给出一片文章,QT实现的类似QQ的头像选择框,这篇文章也是讲解头像上传功能的,而我自己的代码是从这个demo中优化而来,不仅对代码进行了重构,而且处理了快速拖动时,边框消失的问题.使用事件和双缓冲来尽量减少重新绘制的几率.接下里我会一步一步进行讲解,怎么实现图片自定义截取功能.一.概要首选,我给出4个类,并

小程序_图片剪切功能(支持多图片上传)

前端图片剪切上传功能是常见的功能,在开发过程中,研发一个这样的功能要花的时间也会很多,现在把一个研发好了的图片剪切插件发出来.支持剪切和大小缩放. wxml 1 <!--图片展示 --> 2 <view bindtap='upEwm' data-which='1'> 3 <view>第一个图</view> 4 <image style='width:200rpx;height:200rpx;background-color:red' src='{{he

IOS 图片剪切(封装数据)

封装 :生成头像(UIImage (NJ).h / .m @interface UIImage (NJ) /** * 生成头像 * * @param icon 头像图片名称 * @param border 头像边框大小 * @param color 头像边框的颜色 * * @return 生成好的头像 */ + (instancetype)imageWithIcon:(NSString *)icon border:(NSInteger)border color:(UIColor *)color;

图片剪切效果

第一篇博文,把今天写的一个实现图片剪切效果的JS脚本发上来 基本思路: 三层结构,第一层为透明度是0.7的图片,第二层为正常的图片,第三层使用一个DIV作为选取框,采用CSS中的绝对定位进行覆盖 HTML代码 <div id="box"> <img id="img-1" src="imgs/cat-1.jpg"/> <img id="img-2" src="imgs/cat-2.jpg&

用Canvas+Javascript FileAPI 实现一个跨平台的图片剪切、滤镜处理、上传下载工具(转)

直接上代码,其中上传功能需要自己配置允许跨域的文件服务器地址~ 或者将html文件贴到您的站点下同源上传也OK. 支持: 不同尺寸图片获取. 原图缩小放大. 原图移动. 选择框大小改变. 下载选中的区域. 上传选中的区域. 几种简单的滤镜(自己添加滤镜函数即可添加滤镜效果) 移动端适配要点: ① 替换事件名称 if(/^.*(Android|iPad|iPhone){1}.*$/.test(navigator.userAgent)){ eventName={down:"touchstart&qu

用Canvas+Javascript FileAPI 实现一个图片剪切、滤镜处理、上传下载工具

直接上代码,其中上传功能需要自己配置允许跨域的文件服务器地址~ 或者将html文件贴到您的站点下同源上传也OK. 支持: 不同尺寸图片获取. 原图缩小放大. 原图移动. 选择框大小改变. 下载选中的区域. 上传选中的区域. 几种简单的滤镜(自己添加滤镜函数即可添加滤镜效果) <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dt

图片剪切之Croppic插件

前几天做图片上传时需要进行图片的剪切和缩放,上网查找时找到了这个插件.样式很好看,功能也很OK.但是网上都是php进行后台处理图片的例子,然后只好慢慢琢磨C#的处理.插件地址是:http://www.croppic.net/; 首先下载好插件,放入程序文件中.新建页面,引入croppic.js,croppic.min.js,croppic.css文件,同时不要忘记引入jquery文件,我用的是1.8.2的版本.之前没引入1.8.2的版本,而是使用的下载下来的demo中的https://code.

PHP结合JQueryJcrop实现头像图片裁切实例代码

看到一些网站上有图片剪切的功能,觉得挺炫,后来找了一款专用于图片裁切的插件,jquery.Jcrop.min.js,用这个插件可以方便的实现这个功能,使用时鼠标在图片上圈选出选区,即可把图片裁切成所选部分,非常适合用于头像的裁切编辑功能.前端UI分享 演示分为HTML和php两部分: 第一部分,HTML代码: .代码   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.