现在的位置: 首页 > 综合 > 正文

QT实现头像图片剪切框

2018年05月03日 ⁄ 综合 ⁄ 共 5142字 ⁄ 字号 评论关闭

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




1. 怎样去实现裁剪

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

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

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

 

2. 缩放边框的实现

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

2.1对mousePressEvent的重写

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

void CutDialog::mousePressEvent(QMouseEvent * event)
{
	m_startPoint = event->pos();
	m_mouse_down = event->button() == Qt::LeftButton;
}

2.2 对mouseMoveEvent 的重写      

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

void CutDialog::mouseMoveEvent(QMouseEvent * event)
{
	QPoint dragPoint = event->pos();
	int x = event->x();
	int y = event->y();
	if(m_mouse_down)
	{
	    QRect g = getResizeGem(geometry(), dragPoint);
<span style="white-space:pre">		</span>//实现对当前窗口的拖放
		if(parentWidget()->rect().contains(g))
			setGeometry(g);
		m_startPoint = QPoint(!m_right? m_startPoint.x():event->x(),!m_bottom? m_startPoint.y():event->y());
	<span style="white-space:pre">	</span>
<span style="white-space:pre">		</span>//实现对当前的移动
		if(!m_left && !m_right && !m_bottom && !m_top)
		{
			QPoint p = QPoint((pos().x()+dragPoint.x() - m_startPoint.x()), (pos().y()+dragPoint.y() - m_startPoint.y()));
			QPoint dragEndge = p;
			dragEndge.setX(dragEndge.x() + rect().width());
			dragEndge.setY(dragEndge.y() + rect().height());
			p.setX(p.x() < 0? 0 : p.x());
			p.setX(dragEndge.x() > parentWidget()->width()?parentWidget()->width()-rect().width():p.x());
			p.setY(p.y() < 0? 0 : p.y());
			p.setY(dragEndge.y() > parentWidget()->height()?parentWidget()->height()-rect().height():p.y());
			move(p);
		}
	
	}
	else
	{
<span style="white-space:pre">		</span>//根据位置判断相应的鼠标形状
		QRect r = rect();
		m_left = qAbs(x - r.left())  < 5;
		m_right = qAbs(x - r.right()) < 5;
		m_bottom = qAbs(y - r.bottom()) < 5;
		m_top = qAbs(y - r.top()) < 5;
		bool lorr = m_left | m_right;
		bool torb = m_top | m_bottom;
		if(lorr && torb)
		{
			if((m_left && m_top) || (m_right && m_bottom))
			{
				setCursor(Qt::SizeFDiagCursor);
			}
			else
				setCursor(Qt::SizeBDiagCursor);
		}
		else if(lorr)
			setCursor(Qt::SizeHorCursor);
		else if(torb)
			setCursor(Qt::SizeVerCursor);
		else
		{
			setCursor(Qt::SizeAllCursor);
			m_bottom = m_left = m_right = m_top = false;
		}
	}
}

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

QRect CutDialog::getResizeGem(QRect oldgeo, QPoint mousePoint)
{
	QRect g = oldgeo;
	bool lorr = m_left | m_right;
	bool torb = m_top | m_bottom;
	int dx = mousePoint.x() - m_startPoint.x();
	int dy = mousePoint.y() - m_startPoint.y();
	if(lorr && torb)
	{
		int maxLen = qMin(qAbs(dx),qAbs(dy));
		if(m_left && m_top && dx*dy >0)
		{
			g.setLeft(dx >0 ?g.left() + maxLen : g.left() - maxLen);
			g.setTop(dy >0? g.top() + maxLen : g.top() - maxLen);
		}
		if(m_right && m_top && dx*dy < 0)
		{
			g.setRight(dx>0 ? g.right() + maxLen:g.right() - maxLen);
			g.setTop(dy >0? g.top() + maxLen : g.top() - maxLen);
		}
		if(m_right && m_bottom && dx*dy > 0)
		{
			g.setRight(dx>0 ? g.right() + maxLen:g.right() - maxLen);
			g.setBottom(dy >0? g.bottom() + maxLen : g.bottom() - maxLen);
		}
		if(m_left && m_bottom && dx*dy < 0)
		{
			g.setLeft(dx >0 ?g.left() + maxLen : g.left() - maxLen);
			g.setBottom(dy >0? g.bottom() + maxLen : g.bottom() - maxLen);
		}
		return g;
	}
	else if(lorr)
	{
		if(m_left)
			g.setLeft(g.left() + dx);
		if(m_right)
			g.setRight(g.right() + dx);
		int len = g.width() - oldgeo.width();
		int intHight = (int) len/2.0;

		g.setTop(g.top() - intHight);
		g.setBottom(g.bottom() + len - intHight);
	}
	else if(torb)
	{
		if(m_bottom)
			g.setBottom(g.bottom() + dy);
		if(m_top)
			g.setTop(g.top() + dy);
		int dheigt = g.height() - oldgeo.height();
		int intWidth = (int) dheigt/2.0;

		g.setLeft(g.left() - intWidth);
		g.setRight(g.right() + dheigt - intWidth);
	}
 	return g;
}

                                                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                               
                                                                                                                                                                                                           2.3 对mouseReleaseEvent的重写


void CutDialog::mouseReleaseEvent(QMouseEvent * event)
{
	m_mouse_down = false;
}

 

3. 阴影的实现

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

void PhotoShotDialog::paintEvent(QPaintEvent *e)
{
	QPainterPath painterPath;
	QPainterPath p;
	p.addRect(x(),y(),rect().width(),rect().height());
	painterPath.addRect(dialog->geometry());
        QPainterPath drawPath =p.subtracted(painterPath);

	QPainter paint(this);
	paint.setOpacity(0.7);
	paint.fillPath(drawPath,QBrush(Qt::black));
}

 

4. 切图

切图只需使用到QPixmap的copy函数即可,函数参数即是窗口的位置及大小。
	QPixmap pix = scaledPix.copy(pdialog->getShotGeometry());
	pix.save("C:/Users/dana/Desktop/1.png","png");

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

最终实现效果如下:

抱歉!评论已关闭.