一、简述
在 Qt 之 简单截图功能(一)实现鼠标选中区域截图 、 Qt 之 简单截图功能(二)实现可移动选中区域 中简单叙述了实现截图功能的两小步,今天第三篇来实现可拖拽选中矩形顶点进行重新选择截图区域,话不多说先看效果图,再上代码。
模仿微信截图
效果图:
二、代码之路
这一篇中将实现实现如何通过鼠标拖拽重新选取截图区域。代码可能稍长,整体代码是在前两篇的基础上完善的,建议先从 Qt 之 简单截图功能(一)实现鼠标选中区域截图 、 Qt 之 简单截图功能(二)实现可移动选中区域 这两篇看起。
—— 完整代码请见文章结尾下载链接。
capturescreen.cpp
#include "capturescreen.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QMouseEvent>
#include <QDebug>
// 矩形选中区边框宽度;
#define SELECT_RECT_BORDER_WIDTH 1
// 选中矩形8个拖拽点小矩形的宽高;
#define STRETCH_RECT_WIDTH 6
#define STRETCH_RECT_HEIGHT 6
CaptureScreen::CaptureScreen(QWidget *parent)
: QWidget(parent)
, m_currentCaptureState(InitCapture)
{
initWindow();
initStretchRect();
loadBackgroundPixmap();
}
CaptureScreen::~CaptureScreen()
{
}
void CaptureScreen::initWindow()
{
this->setMouseTracking(true);
// 由于存在类似QQ这样界面始终显示在最顶层,设置属性 Qt::WindowStaysOnTopHint;
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
setWindowState(Qt::WindowActive | Qt::WindowFullScreen);
this->setMouseTracking(true);
}
void CaptureScreen::initStretchRect()
{
m_stretchRectState = NotSelect;
m_topLeftRect = QRect(0 , 0 , 0 , 0);
m_topRightRect = QRect(0, 0, 0, 0);
m_bottomLeftRect = QRect(0, 0, 0, 0);
m_bottomRightRect = QRect(0, 0, 0, 0);
m_leftCenterRect = QRect(0, 0, 0, 0);
m_topCenterRect = QRect(0, 0, 0, 0);
m_rightCenterRect = QRect(0, 0, 0, 0);
m_bottomCenterRect = QRect(0, 0, 0, 0);
}
// 获取当前屏幕图片;
void CaptureScreen::loadBackgroundPixmap()
{
m_loadPixmap = QPixmap::grabWindow(QApplication::desktop()->winId()); //抓取当前屏幕的图片;
m_screenwidth = m_loadPixmap.width();
m_screenheight = m_loadPixmap.height();
}
void CaptureScreen::mousePressEvent(QMouseEvent *event)
{
m_stretchRectState = getStrethRectState(event->pos());
if (event->button() == Qt::LeftButton)
{
if (m_currentCaptureState == InitCapture)
{
m_currentCaptureState = BeginCaptureImage;
m_beginPoint = event->pos();
}
// 是否在拉伸的小矩形中;
else if (m_stretchRectState != NotSelect)
{
m_currentCaptureState = BeginMoveStretchRect;
// 当前鼠标在拖动选中区顶点时,设置鼠标当前状态;
setStretchCursorStyle(m_stretchRectState);
m_beginMovePoint = event->pos();
}
// 是否在选中的矩形中;
else if (isPressPointInSelectRect(event->pos()))
{
m_currentCaptureState = BeginMoveCaptureArea;
m_beginMovePoint = event->pos();
}
}
return QWidget::mousePressEvent(event);
}
void CaptureScreen::mouseMoveEvent(QMouseEvent* event)
{
if (m_currentCaptureState == BeginCaptureImage)
{
m_endPoint = event->pos();
update();
}
else if (m_currentCaptureState == BeginMoveCaptureArea)
{
m_endMovePoint = event->pos();
update();
}
else if (m_currentCaptureState == BeginMoveStretchRect)
{
m_endMovePoint = event->pos();
update();
// 当前鼠标在拖动选中区顶点时,在鼠标未停止移动前,一直保持鼠标当前状态;
return QWidget::mouseMoveEvent(event);
}
// 根据鼠标是否在选中区域内设置鼠标样式;
StretchRectState stretchRectState = getStrethRectState(event->pos());
if (stretchRectState != NotSelect)
{
setStretchCursorStyle(stretchRectState);
}
else if (isPressPointInSelectRect(event->pos()))
{
setCursor(Qt::SizeAllCursor);
}
else if (!isPressPointInSelectRect(event->pos()) && m_currentCaptureState != BeginMoveCaptureArea)
{
setCursor(Qt::ArrowCursor);
}
return QWidget::mouseMoveEvent(event);
}
void CaptureScreen::mouseReleaseEvent(QMouseEvent *event)
{
if (m_currentCaptureState == BeginCaptureImage)
{
m_currentCaptureState = FinishCaptureImage;
m_endPoint = event->pos();
update();
}
else if (m_currentCaptureState == BeginMoveCaptureArea)
{
m_currentCaptureState = FinishMoveCaptureArea;
m_endMovePoint = event->pos();
update();
}
else if (m_currentCaptureState == BeginMoveStretchRect)
{
m_currentCaptureState = FinishMoveStretchRect;
m_endMovePoint = event->pos();
update();
}
return QWidget::mouseReleaseEvent(event);
}
// 当前鼠标坐标是否在选取的矩形区域内;
bool CaptureScreen::isPressPointInSelectRect(QPoint mousePressPoint)
{
QRect selectRect = getRect(m_beginPoint, m_endPoint);
if (selectRect.contains(mousePressPoint))
{
return true;
}
return false;
}
void CaptureScreen::paintEvent(QPaintEvent *event)
{
m_painter.begin(this); //进行重绘;
QColor shadowColor = QColor(0, 0, 0, 120); //阴影颜色设置;
m_painter.drawPixmap(0, 0, m_loadPixmap); //将背景图片画到窗体上;
m_painter.fillRect(m_loadPixmap.rect(), shadowColor); //画影罩效果;
switch (m_currentCaptureState)
{
case InitCapture:
break;
case BeginCaptureImage:
case FinishCaptureImage:
case BeginMoveCaptureArea:
case FinishMoveCaptureArea:
case BeginMoveStretchRect:
case FinishMoveStretchRect:
m_currentSelectRect = getSelectRect();
drawCaptureImage();
case FinishCapture:
break;
default:
break;
}
m_painter.end(); //重绘结束;
}
// 根据当前截取状态获取当前选中的截图区域;
QRect CaptureScreen::getSelectRect()
{
QRect selectRect(0, 0, 0, 0);
if (m_currentCaptureState == BeginCaptureImage || m_currentCaptureState == FinishCaptureImage)
{
selectRect = getRect(m_beginPoint, m_endPoint);
}
else if (m_currentCaptureState == BeginMoveCaptureArea || m_currentCaptureState == FinishMoveCaptureArea)
{
selectRect = getMoveRect();
}
else if (m_currentCaptureState == BeginMoveStretchRect || m_currentCaptureState == FinishMoveStretchRect)
{
selectRect = getStretchRect();
}
if (m_currentCaptureState == FinishCaptureImage || m_currentCaptureState == FinishMoveCaptureArea || m_currentCaptureState == FinishMoveStretchRect)
{
m_currentCaptureState = FinishCapture;
}
return selectRect;
}
// 绘制当前选中的截图区域;
void CaptureScreen::drawCaptureImage()
{
m_capturePixmap = m_loadPixmap.copy(m_currentSelectRect);
m_painter.drawPixmap(m_currentSelectRect.topLeft(), m_capturePixmap);
m_painter.setPen(QPen(QColor(0, 180, 255), SELECT_RECT_BORDER_WIDTH)); //设置画笔;
m_painter.drawRect(m_currentSelectRect);
drawStretchRect();
}
// 绘制选中矩形各拖拽点小矩形;
void CaptureScreen::drawStretchRect()
{
QColor color = QColor(0, 174, 255);
// 四个角坐标;
QPoint topLeft = m_currentSelectRect.topLeft();
QPoint topRight = m_currentSelectRect.topRight();
QPoint bottomLeft = m_currentSelectRect.bottomLeft();
QPoint bottomRight = m_currentSelectRect.bottomRight();
// 四条边中间点坐标;
QPoint leftCenter = QPoint(topLeft.x(), (topLeft.y() + bottomLeft.y()) / 2);
QPoint topCenter = QPoint((topLeft.x() + topRight.x()) / 2, topLeft.y());
QPoint rightCenter = QPoint(topRight.x(), leftCenter.y());
QPoint bottomCenter = QPoint(topCenter.x(), bottomLeft.y());
m_topLeftRect = QRect(topLeft.x() - STRETCH_RECT_WIDTH / 2, topLeft.y() - STRETCH_RECT_HEIGHT / 2, STRETCH_RECT_WIDTH, STRETCH_RECT_HEIGHT);
m_topRightRect = QRect(topRight.x() - STRETCH_RECT_WIDTH / 2, topRight.y() - STRETCH_RECT_HEIGHT / 2, STRETCH_RECT_WIDTH, STRETCH_RECT_HEIGHT);
m_bottomLeftRect = QRect(bottomLeft.x() - STRETCH_RECT_WIDTH / 2, bottomLeft.y() - STRETCH_RECT_HEIGHT / 2, STRETCH_RECT_WIDTH, STRETCH_RECT_HEIGHT);
m_bottomRightRect = QRect(bottomRight.x() - STRETCH_RECT_WIDTH / 2, bottomRight.y() - STRETCH_RECT_HEIGHT / 2, STRETCH_RECT_WIDTH, STRETCH_RECT_HEIGHT);
m_leftCenterRect = QRect(leftCenter.x() - STRETCH_RECT_WIDTH / 2, leftCenter.y() - STRETCH_RECT_HEIGHT / 2, STRETCH_RECT_WIDTH, STRETCH_RECT_HEIGHT);
m_topCenterRect = QRect(topCenter.x() - STRETCH_RECT_WIDTH / 2, topCenter.y() - STRETCH_RECT_HEIGHT / 2, STRETCH_RECT_WIDTH, STRETCH_RECT_HEIGHT);
m_rightCenterRect = QRect(rightCenter.x() - STRETCH_RECT_WIDTH / 2, rightCenter.y() - STRETCH_RECT_HEIGHT / 2, STRETCH_RECT_WIDTH, STRETCH_RECT_HEIGHT);
m_bottomCenterRect = QRect(bottomCenter.x() - STRETCH_RECT_WIDTH / 2, bottomCenter.y() - STRETCH_RECT_HEIGHT / 2, STRETCH_RECT_WIDTH, STRETCH_RECT_HEIGHT);
m_painter.fillRect(m_topLeftRect, color);
m_painter.fillRect(m_topRightRect, color);
m_painter.fillRect(m_bottomLeftRect, color);
m_painter.fillRect(m_bottomRightRect, color);
m_painter.fillRect(m_leftCenterRect, color);
m_painter.fillRect(m_topCenterRect, color);
m_painter.fillRect(m_rightCenterRect, color);
m_painter.fillRect(m_bottomCenterRect, color);
}
void CaptureScreen::keyPressEvent(QKeyEvent *event)
{
// Esc 键退出截图;
if (event->key() == Qt::Key_Escape)
{
close();
}
// Eeter键完成截图;
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
{
signalCompleteCature(m_capturePixmap);
close();
}
}
// 根据beginPoint , endPoint 获取当前选中的矩形;
QRect CaptureScreen::getRect(const QPoint &beginPoint, const QPoint &endPoint)
{
int x, y, width, height;
width = qAbs(beginPoint.x() - endPoint.x());
height = qAbs(beginPoint.y() - endPoint.y());
x = beginPoint.x() < endPoint.x() ? beginPoint.x() : endPoint.x();
y = beginPoint.y() < endPoint.y() ? beginPoint.y() : endPoint.y();
QRect selectedRect = QRect(x, y, width, height);
// 避免宽或高为零时拷贝截图有误;
// 可以看QQ截图,当选取截图宽或高为零时默认为2;
if (selectedRect.width() == 0)
{
selectedRect.setWidth(1);
}
if (selectedRect.height() == 0)
{
selectedRect.setHeight(1);
}
return selectedRect;
}
// 获取移动后,当前选中的矩形;
QRect CaptureScreen::getMoveRect()
{
// 通过getMovePoint方法先检查当前是否移动超出屏幕;
QPoint movePoint = getMovePoint();
QPoint beginPoint = m_beginPoint + movePoint;
QPoint endPoint = m_endPoint + movePoint;
// 结束移动选区时更新当前m_beginPoint , m_endPoint,防止下一次操作时截取的图片有问题;
if (m_currentCaptureState == FinishMoveCaptureArea)
{
m_beginPoint = beginPoint;
m_endPoint = endPoint;
m_beginMovePoint = QPoint(0, 0);
m_endMovePoint = QPoint(0, 0);
}
return getRect(beginPoint, endPoint);
}
QPoint CaptureScreen::getMovePoint()
{
QPoint movePoint = m_endMovePoint - m_beginMovePoint;
QRect currentRect = getRect(m_beginPoint, m_endPoint);
// 检查当前是否移动超出屏幕;
//移动选区是否超出屏幕左边界;
if (currentRect.topLeft().x() + movePoint.x() < 0)
{
movePoint.setX(0 - currentRect.topLeft().x());
}
//移动选区是否超出屏幕上边界;
if (currentRect.topLeft().y() + movePoint.y() < 0)
{
movePoint.setY(0 - currentRect.topLeft().y());
}
//移动选区是否超出屏幕右边界;
if (currentRect.bottomRight().x() + movePoint.x() > m_screenwidth)
{
movePoint.setX(m_screenwidth - currentRect.bottomRight().x());
}
//移动选区是否超出屏幕下边界;
if (currentRect.bottomRight().y() + movePoint.y() > m_screenheight)
{
movePoint.setY(m_screenheight - currentRect.bottomRight().y());
}
return movePoint;
}
// 获取当前鼠标位于哪一个拖拽顶点;
StretchRectState CaptureScreen::getStrethRectState(QPoint point)
{
StretchRectState stretchRectState = NotSelect;
if (m_topLeftRect.contains(point))
{
stretchRectState = TopLeftRect;
}
else if (m_topCenterRect.contains(point))
{
stretchRectState = TopCenterRect;
}
else if (m_topRightRect.contains(point))
{
stretchRectState = TopRightRect;
}
else if (m_rightCenterRect.contains(point))
{
stretchRectState = RightCenterRect;
}
else if (m_bottomRightRect.contains(point))
{
stretchRectState = BottomRightRect;
}
else if (m_bottomCenterRect.contains(point))
{
stretchRectState = BottomCenterRect;
}
else if (m_bottomLeftRect.contains(point))
{
stretchRectState = BottomLeftRect;
}
else if (m_leftCenterRect.contains(point))
{
stretchRectState = LeftCenterRect;
}
return stretchRectState;
}
// 设置鼠标停在拖拽定点处的样式;
void CaptureScreen::setStretchCursorStyle(StretchRectState stretchRectState)
{
switch (stretchRectState)
{
case NotSelect:
setCursor(Qt::ArrowCursor);
break;
case TopLeftRect:
case BottomRightRect:
setCursor(Qt::SizeFDiagCursor);
break;
case TopRightRect:
case BottomLeftRect:
setCursor(Qt::SizeBDiagCursor);
break;
case LeftCenterRect:
case RightCenterRect:
setCursor(Qt::SizeHorCursor);
break;
case TopCenterRect:
case BottomCenterRect:
setCursor(Qt::SizeVerCursor);
break;
default:
break;
}
}
// 获取拖拽后的矩形选中区域;
QRect CaptureScreen::getStretchRect()
{
QRect stretchRect;
QRect currentRect = getRect(m_beginPoint, m_endPoint);
switch (m_stretchRectState)
{
case NotSelect:
stretchRect = getRect(m_beginPoint, m_endPoint);
break;
case TopLeftRect:
{
stretchRect = getRect(currentRect.bottomRight(), m_endMovePoint);
}
break;
case TopRightRect:
{
QPoint beginPoint = QPoint(currentRect.topLeft().x(), m_endMovePoint.y());
QPoint endPoint = QPoint(m_endMovePoint.x(), currentRect.bottomRight().y());
stretchRect = getRect(beginPoint, endPoint);
}
break;
case BottomLeftRect:
{
QPoint beginPoint = QPoint(m_endMovePoint.x() , currentRect.topLeft().y());
QPoint endPoint = QPoint(currentRect.bottomRight().x(), m_endMovePoint.y());
stretchRect = getRect(beginPoint, endPoint);
}
break;
case BottomRightRect:
{
stretchRect = getRect(currentRect.topLeft(), m_endMovePoint);
}
break;
case LeftCenterRect:
{
QPoint beginPoint = QPoint(m_endMovePoint.x(), currentRect.topLeft().y());
stretchRect = getRect(beginPoint, currentRect.bottomRight());
}
break;
case TopCenterRect:
{
QPoint beginPoint = QPoint(currentRect.topLeft().x(), m_endMovePoint.y());
stretchRect = getRect(beginPoint, currentRect.bottomRight());
}
break;
case RightCenterRect:
{
QPoint endPoint = QPoint(m_endMovePoint.x(), currentRect.bottomRight().y());
stretchRect = getRect(currentRect.topLeft(), endPoint);
}
break;
case BottomCenterRect:
{
QPoint endPoint = QPoint(currentRect.bottomRight().x(), m_endMovePoint.y());
stretchRect = getRect(currentRect.topLeft(), endPoint);
}
break;
default:
{
stretchRect = getRect(m_beginPoint , m_endPoint );
}
break;
}
// 拖动结束更新 m_beginPoint , m_endPoint;
if (m_currentCaptureState == FinishMoveStretchRect)
{
m_beginPoint = stretchRect.topLeft();
m_endPoint = stretchRect.bottomRight();
}
return stretchRect;
}
###测试代码
// 按下Ctrl + Alt + A键开始截图;
void TestWindow::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_A && event->modifiers() == (Qt::AltModifier | Qt::ControlModifier))
{
startCatureImage();
}
}
// 显示截图界面;
void TestWindow::startCatureImage()
{
// 点击截图按钮开始截图;
CaptureScreen* captureHelper = new CaptureScreen();
connect(captureHelper, SIGNAL(signalCompleteCature(QPixmap)), this, SLOT(onCompleteCature(QPixmap)));
captureHelper->show();
}
// 将截取的图片显示在TestWindow的label上;
void TestWindow::onCompleteCature(QPixmap captureImage)
{
ui.label->setPixmap(captureImage);
}
尾
Qt 之 实现简单截图功能(一)实现鼠标选中区域截图 、 Qt 之 实现简单截图功能(二)实现可移动选中区域 加这一篇完成了截图三步曲,完成了截图的基本应用,代码中可能会存在一些细节问题,后期会继续完善。在下一篇中将会增加截图信息的显示。如果代码中有什么疑问或者存在问题欢迎一起交流O(∩_∩)O!
Good Night !
代码下载
—— 更新于2017年6月28日