QT实现头像图片剪切框



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



1. 怎样去实现裁剪

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

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

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

 

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.     }  
  16.     else  
  17.     {  
[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.   
  42.         g.setTop(g.top() - intHight);  
  43.         g.setBottom(g.bottom() + len - intHight);  
  44.     }  
  45.     else if(torb)  
  46.     {  
  47.         if(m_bottom)  
  48.             g.setBottom(g.bottom() + dy);  
  49.         if(m_top)  
  50.             g.setTop(g.top() + dy);  
  51.         int dheigt = g.height() - oldgeo.height();  
  52.         int intWidth = (int) dheigt/2.0;  
  53.   
  54.         g.setLeft(g.left() - intWidth);  
  55.         g.setRight(g.right() + dheigt - intWidth);  
  56.     }  
  57.     return g;  

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             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.   
  9.     QPainter paint(this);  
  10.     paint.setOpacity(0.7);  
  11.     paint.fillPath(drawPath,QBrush(Qt::black));  
  12. }  


 

 

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

最终实现效果如下:






转载于:https://www.cnblogs.com/zhujiangbk/p/4348325.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值