Qt中截图功能的实现
来源:互联网 发布:思科通过mac地址查询ip 编辑:程序博客网 时间:2024/06/02 05:15
Qt中截图功能的实现
需求:加载一张图片并显示,可以放大缩小,可以截取图片的某个矩形并保存。
原以为蛮简单的一个功能,其实还是有点小复杂。
最简单Qt图片浏览器可以参考Qt自带的Demo:Image Viewer Example
看一下最终的实现效果:
图片的加载显示
这里需要实现一个QImageViewer的类,继承自QWidget。
图片用QPixmap来加载和显示,还有三个成员分别是图片的缩放因子,图片是否已经加载,viewer是否已经初始化,是否处于裁剪状态。
- private:
- QPixmap m_pixmap;
- float scalling;
- bool isLoaded;
- bool isIntialised;
- bool isCropping;
scalling值是用于记录图片的缩放比例。
显示图片只要重新定义paintEvent,在里面绘制m_pixmap就可以了。
- void QImageViewer::paintEvent(QPaintEvent *event)
- {
- QWidget::paintEvent(event);
- if (m_pixmap.isNull())
- {
- return;
- }
- QPainter painter(this);
- if (isLoaded)
- {
- painter.setRenderHint(QPainter::SmoothPixmapTransform);
- QSize pixSize = m_pixmap.size();
- //For canvas's size not change when window's size change.
- if (!isInitialised)
- {
- QSize initialSize = event->rect().size();
- scaling = 1.0 * initialSize.width() / pixSize.width();
- isInitialised = true;
- }
- pixSize.scale(scaling * pixSize, Qt::KeepAspectRatio);
- this->setMinimumSize(pixSize);
- QPoint topleft;
- topleft.setX((this->width() - pixSize.width()) / 2);
- topleft.setY((this->height() - pixSize.height()) / 2);
- painter.drawPixmap(topleft, m_pixmap.scaled(pixSize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
- }
- }
截图
思路很简单,首先选择进入裁剪模式(可以在menu中添加一个action或者用快捷键),然后在图片上拖出一个矩形,最后按回车,截取完成,Ctrl + s 保存。
主要用到的是 QPixmap::copy(QRect rect) 方法。
首先要实现一个CropRect类,用于记录截取的矩形。
- #ifndef CROPRECT_H
- #define CROPRECT_H
- #include <QPoint>
- #include <QPainter>
- class CropRect
- {
- public:
- CropRect(){}
- ~CropRect(){}
- void setStart(QPoint s)
- {
- start = s;
- }
- void setEnd(QPoint e)
- {
- end = e;
- }
- QPoint startPoint() const
- {
- return start;
- }
- QPoint endPoint() const
- {
- return end;
- }
- void reset()
- {
- QPoint P(0,0);
- start = P;
- end = P;
- }
- QSize& size() const
- {
- return QSize(width(), height());
- }
- int height() const
- {
- return qAbs(startPoint().y() - endPoint().y());
- }
- int width() const
- {
- return qAbs(startPoint().x() - endPoint().x());
- }
- private:
- QPoint start;
- QPoint end;
- };
- #endif // CROPRECT_H
注意这里的start和end都是相对于当前要截取的图片的位置,也就是图片的左上角的坐标是CropRect的原点。
接下来再QImageviewer中实现两个辅助的方法。
由于图片并不是恰好完全充满窗体,所以在设定裁剪框的时候,鼠标如果没有点在图片上,就应该不裁剪,所以首先应该判断屏幕中的某个点是否在图片上。
- bool QImageViewer::isContainPoint(QPoint &p)
- {
- QSize s = m_pixmap.size();
- s.scale(scaling * s, Qt::KeepAspectRatio);
- //If pixmap bigger than current window.
- if ((s.height() > this->rect().height()) && (s.width() > this->rect().width()))
- {
- return true;
- }
- QPoint topleft;
- topleft.setX((this->width() - s.width()) / 2);
- topleft.setY((this->height() - s.height()) / 2);
- QRect rect(topleft, s);
- return rect.contains(p);
- }
第二个方法就是将鼠标的位置映射到图片上的位置,因为截图主要是对图片进行操作。
图片的大小和窗口大小有四种情况,第一种是图片高度和宽度都大于窗体。
逻辑就是将红色和绿色部分相加,得到点对于当前图片(已缩放)的位置,最后除以scalling就可以了。
还有一种是图片完全在窗口里面
这种情况将红色减去绿色部分,得到点对于当前图片(已缩放)的位置,最后除以scalling就可以了。还有两种简单的情况就不展开了,具体代码如下:
- QPoint QImageViewer::mapToPixmap(QPoint &screenPoint)
- {
- QSize pixmapSize = m_pixmap.size();
- pixmapSize.scale(scaling * pixmapSize, Qt::KeepAspectRatio);
- //Get the position of screenPoint to the pixmap in show.
- QPoint tmpPos;
- if (pixmapSize.width() > this->width() && pixmapSize.height() > this->height())
- {
- tmpPos.setX(pixmapSize.width() - (this->width() - screenPoint.x()));
- tmpPos.setY(pixmapSize.height() - (this->height() - screenPoint.y()));
- }
- else if (pixmapSize.width() < this->width() && pixmapSize.height() > this->height())
- {
- tmpPos.setX(screenPoint.x() - (this->width() - pixmapSize.width()) / 2);
- tmpPos.setY(pixmapSize.height() - (this->height() - screenPoint.y()));
- }
- else if (pixmapSize.width() > this->width() && pixmapSize.height() < this->height())
- {
- tmpPos.setX(pixmapSize.width() - (this->width() - screenPoint.x()));
- tmpPos.setY(screenPoint.y() - (this->height() - pixmapSize.height()) / 2);
- }
- else{
- QPoint topleft;
- topleft.setX((this->width() - pixmapSize.width()) / 2);
- topleft.setY((this->height() - pixmapSize.height()) / 2);
- tmpPos.setX(screenPoint.x() - topleft.x());
- tmpPos.setY(screenPoint.y() - topleft.y());
- }
- //return the position to the real pixmap.*/
- return QPoint(tmpPos.x() / scaling, tmpPos.y() / scaling);
- }
这里采取了一个投机取巧的办法,就是利用了QPoint.setX() 和 QPoint.setY()方法如果传进去的是负值,那么就等于传进去0,所以少了一些小于0的判断。
接下来就是对应的鼠标事件,用于确定裁剪框的大小
- void QImageViewer::mousePressEvent(QMouseEvent *event)
- {
- if ((event->buttons() == Qt::LeftButton) && isContainPoint(event->pos()) && isCropping)
- {
- cropRect.setStart(mapToPixmap(event->pos()));
- cropRect.setEnd(mapToPixmap(event->pos()));
- isStartingCrop = true;
- }
- }
- void QImageViewer::mouseMoveEvent(QMouseEvent *event)
- {
- if ((event->buttons() == Qt::LeftButton) && isStartingCrop)
- {
- if (isContainPoint(event->pos()))
- {
- cropRect.setEnd(mapToPixmap(event->pos()));
- update();
- }
- }
- }
- void QImageViewer::mouseReleaseEvent(QMouseEvent *e)
- {
- QRect rect(cropRect.startPoint(), cropRect.endPoint());
- isStartingCrop = false;
- }
裁剪框绘制的相关代码,这里也根据startpoint 和endpoint的相对位置,也有几种情况需要注意一下。更炫酷的动态蚂蚁线可以参考:Qt中绘制蚂蚁线
- if (isCropping)
- {
- qDebug() << cropRect.width() << cropRect.height();
- //painter.setPen(Qt::darkGreen);
- QPen pen;
- pen.setBrush(Qt::red);
- pen.setStyle(Qt::DashLine);
- pen.setWidth(1);
- painter.setPen(pen);
- //start point in the left to the end point.
- if (cropRect.startPoint().x() < cropRect.endPoint().x())
- {
- if (cropRect.startPoint().y() < cropRect.endPoint().y())
- {
- //start point in the top to the end point.
- painter.drawRect(topleft.x() + cropRect.startPoint().x() * scaling, topleft.y() + cropRect.startPoint().y() * scaling, cropRect.width() * scaling, cropRect.height() * scaling);
- }
- else{
- //start point in the bottom to the end point.
- painter.drawRect(topleft.x() + cropRect.startPoint().x() * scaling, topleft.y() + cropRect.endPoint().y() * scaling, cropRect.width() * scaling, cropRect.height() * scaling);
- }
- }
- else
- {
- if (cropRect.startPoint().y() > cropRect.endPoint().y())
- {
- painter.drawRect(topleft.x() + cropRect.endPoint().x() * scaling, topleft.y() + cropRect.endPoint().y() * scaling, cropRect.width() * scaling, cropRect.height() * scaling);
- }
- else{
- painter.drawRect(topleft.x() + cropRect.endPoint().x() * scaling, topleft.y() + cropRect.startPoint().y() * scaling, cropRect.width() * scaling, cropRect.height() * scaling);
- }
- }
- }
最后就是裁剪了
- void QImageViewer::cropFinished()
- {
- QRect crop(cropRect.startPoint(), QSize(cropRect.width(), cropRect.height()));
- QPixmap cropped = m_pixmap.copy(crop);
- m_pixmap = cropped;
- cropRect.reset();
- isCropping = false;
- this->update();
- }
打完收工。
- 顶
- 0
- 踩
- 0
- 上一篇Qt中绘制蚂蚁线
- 下一篇Qt中显示复杂列表
- • Qt 之 简单截图功能(三)实现可拖拽选中区域
- • QT实现类似QQ的截图功能
- • Qt4简单截图功能的实现
- • Qt 之 简单截图功能(二)实现可移动选中区域
- • Qt中截图功能的实现
- • QT做类似QQ截图功能(带图片编辑功能)
- • Qt 实现 QQ 截图工具(开源OEasyScreenshot)
- • Qt学习(九) 截图程序的实现
- • 通过Qt截图工具讲注册热键的实现
- • 【Qt】Qt 导出 PDF,Android和Qt截图功能实现
- Qt中截图功能的实现
- Qt中截图功能的实现
- Qt中截图功能的实现
- Qt5:Qt中屏幕或窗口截图功能的实现
- QT实现类似QQ的截图功能
- iOS中截图功能的实现
- 截图功能的实现
- COCOS2D中实现截图功能
- 【Qt】Qt 导出 PDF,Android和Qt截图功能实现
- 截图功能的简单实现
- 截图保存功能的实现
- 在Qt 中实现Sleep的功能
- 在Android中实现截图功能
- 在unity中实现截图功能
- 在unity中实现截图功能
- QT实现类似QQ截图功能(二):画箭头
- 基于Qt的截图工具,实现截图后进行编辑
- MATLAB实现截图功能,返回屏幕截图的RGB数组
- 每日一学(一)android图形验证码的实现
- Python之ReportLab绘制条形码和二维码
- 水池数目
- 2017年6月9日,周结(十六),一些简单的算法题(二)
- JS实用命令积累
- Qt中截图功能的实现
- 费科长的首秀
- HDU 4873 题解
- iOS开发生存技能:学会正确阅读Xcode文档
- iOS-多线程编程之GCD
- C++中string和int的互相转化方式
- java.lang.RuntimeException: Invalid action class configuration that references an unknown class name
- 初识JavaScript(基础篇)
- Android高级控件系列之ListView的用法