QT框架实现自定义形状截图效果
文章目录
QT框架普通截图运行效果
截图软件一般在后台运行,当用户按下快捷键CTRL+SHIFT+X时进入截图状态,整个屏幕颜色变得暗淡了一些。此时用户可以按下鼠标左键进行拉框操作,拉框区域即为截图区域。当用户释放鼠标左键时,截图完成,图像已存储到了剪切板中。用户如果认为效果不好可以重新拉框选取截图区域。用户可以按ESC键或者点击鼠标右键恢复到初始状态。用户也可以点击Save按钮保存所截取的图像到图片文件中。最后用户可以选择双击鼠标左键退出截图状态,屏幕恢复正常状态。

普通矩形截图效果
QT框架系统级热键的原理
怎么实现用户在任意时刻按下快捷键都可以进入截图状态呢?这就是所谓的系统级的热键的作用。QT框架本身没有热键功能,在Windows系统中使用Windows API来实现热键功能。
热键功能包含注册热键、反注册热键以及处理热键消息这几个步骤。
注册热键的例子如下:
int ButianyunHotKey::registerHotkey(const QKeySequence& ks)
{
QString str = QString("ButianyunHotKey%1").arg(ks.toString());
int id = GlobalAddAtomA(str.toUtf8().constData());
if (hotkeys_id_to_ks.contains(id))
{
return -1;
}
uint vk = 0;
uint modifiers = 0;
for (int i = 0; i < ks.count(); i++)
{
int key = ks[i];
if (key & Qt::KeyboardModifierMask)
{
if (key & Qt::ControlModifier)
{
modifiers |= MOD_CONTROL;
}
if (key & Qt::AltModifier)
{
modifiers |= MOD_ALT;
}
if (key & Qt::ShiftModifier)
{
modifiers |= MOD_SHIFT;
}
}
vk = key & 0xffU;
break;
}
int ret = RegisterHotKey(0, id, modifiers, vk);
if (ret)
{
hotkeys_id_to_ks.insert(id, ks);
hotkeys_vk_modifiers_to_id.insert(butianyun_vk_modifiers(vk, modifiers), id);
return id;
}
else
{
qDebug() << "Failed to register hotkey";
GlobalDeleteAtom((ATOM)id);
}
return -1;
}
具体调用注册的例子:
ButianyunHotKey* hotkey = ButianyunHotKey::instance();
hotkey_id = hotkey->registerHotkey(QKeySequence("CTRL+SHIFT+X"));
connect(hotkey, &ButianyunHotKey::sig_hotkey, this, &ButianyunSnapWidget::slot_hotkey);
注册热键
热键必须注册后才能生效。
int RegisterHotKey(HWND hWnd,int id,UINT fsModifiers,UINT vk);
hWnd:窗口句柄,Windows应用程序特有的概念,这里可以使用0作为参数。
id:注册热键时应该使用OS范围内唯一的一个整数ID。这个ID可以使用另外一个Windows API来获取到,稍后介绍。
fsModifiers: 修饰符。表示热键是否包含CTRL、ALT、SHIFT等修饰键,分别用MOD_CONTROL、MOD_ALT、MOD_SHIFT表示,可以组合修饰符。
vk:虚拟键盘码,就是表示键盘上某一个键的代码。比如F1的虚拟键盘码可以用VK_F1表示,字母X的键盘码可以用’X’表示。
返回值
TRUE:成功。FALSE:失败。
反注册热键
一个热键被某一个应用程序注册之后,其它应用程序就无法重复注册了。因此热键资源是十分稀缺的资源。对于同一个热键,如果跟先注册的应用程序产生热键冲突那么后注册的应用程序就注册不了。
int UnregisterHotKey(HWND hWnd,int id);
hWnd:窗口句柄。
id:热键ID。
获取系统级唯一的整数ID
可以通过一个字符串来产生一个唯一ID。
ATOM GlobalAddAtomA (LPCSTR lpString);
LPCSTR: const char*。
返回值:
ATOM类型实际就是unsigned short类型。返回值就是产生的系统级别唯一整数ID。
删除系统级唯一整数ID
系统级别唯一整数ID也是一种系统资源,不再使用之后应该予以删除。
ATOM GlobalDeleteAtom (ATOM nAtom);
nAtom:待删除的ID
怎么处理热键事件?
在用户按下热键之后,Windows系统会向注册了这个热键的应用程序发送WM_HOTKEY热键消息。在QT应用程序中怎么处理这个热键消息呢?
QT应用程序可以使用原生事件过滤器来处理Windows消息,包括WM_HOTKEY。
原生事件过滤器
QAbstractNativeEventFilter这个类型提供了虚函数
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *);
一个原生事件过滤器的例子如下:
struct ButianyunNativeEventFilter: public QAbstractNativeEventFilter
{
ButianyunNativeEventFilter(ButianyunHotKey* hk)
: hotkey(hk)
{
}
ButianyunHotKey* hotkey;
bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override
{
if (eventType == "windows_generic_MSG")
{
MSG* msg = reinterpret_cast<MSG*>(message);
if (WM_HOTKEY == msg->message)
{
uint modifiers = (uint)LOWORD(msg->lParam);
uint vk = (uint)HIWORD(msg->lParam);
uint wp = msg->wParam;
return hotkey->handleHotKey(wp, vk, modifiers);
}
}
return false;
}
};
安装原生事件过滤器的例子如下:
filter = new ButianyunNativeEventFilter(this);
qApp->installNativeEventFilter(filter);
QT框架截图的原理
截图窗口
截图实际上是先将整个屏幕画面保存到像素图中,然后将截图窗口调整到跟屏幕同样大小,并将像素图绘制到截图窗口中。所以在截图状态下用户看到的屏幕画面是截图窗口显示的图片而已,并不是原始的屏幕画面。
拉框操作
QT框架中提供了橡皮框类型QRubberBand。这个类型可以用于实现拉框操作。
在用户按下鼠标左键时启动拉框操作,鼠标移动过程中改变橡皮框大小,鼠标左键释放时完成拉框操作并以橡皮框区域作为截图区域。此时从屏幕画面的像素图中截取部分图像作为截图结果。
系统剪切板操作
QT框架提供了QClipboard类型用于实现剪切板操作,支持将文字、图像等数据保存到剪切板中。之后别的应用程序就可以从剪切板中读取放进去的截图图像。
QT框架高级截图功能
椭圆截图原理
对截取结果像素图设置一个椭圆裁剪区域即可实现椭圆区域截图。

QT框架椭圆截图原理
圆角矩形截图原理
对截取结果像素图设置一个圆角矩形裁剪区域即可实现圆角矩形截图。由于QRegion类型无法直接设置圆角矩形裁剪区域,可以先创建一个圆角矩形绘图路径然后再设置裁剪区域为这个绘图路径,间接实现了圆角矩形截图。

QT框架圆角矩形截图原理
圆角矩形截图源代码
差别是在生成截图结果时对像素图做了裁剪处理,将裁剪区域之外的像素全部设置为透明色。
QImage img(target_pixmap.size(), QImage::Format_ARGB32);
img.fill(QColor(0, 0, 0, 0));
QPainter p(&img);
QPainterPath path;
path.addRoundRect(img.rect(), 30, 30);
p.setClipPath(path);
p.drawPixmap(img.rect(), target_pixmap, target_pixmap.rect());
target_pixmap = QPixmap::fromImage(img);
多边形截图原理
用户拖动鼠标选择多边形的顶点,然后将多边形加入绘图路径作为裁剪区域即可实现自定义形状截图。

QT框架拖变形截图效果
多边形截图源代码
生成截图结果
QImage img(target_pixmap.size(), QImage::Format_ARGB32);
img.fill(QColor(0, 0, 0, 0));
QPainter p(&img);
if (polygon.size() > 2)
{
int mx = source_pixmap.width();
int my = source_pixmap.height();
for (int i = 0; i < polygon.size(); i++)
{
if (polygon.point(i).x() < mx)
{
mx = polygon.point(i).x();
}
if (polygon.point(i).y() < my)
{
my = polygon.point(i).y();
}
}
QPolygon temp;
for (int i = 0; i < polygon.size(); i++)
{
temp.append(QPoint(polygon.point(i).x() - mx,
polygon.point(i).y() - my));
}
QPainterPath path;
path.addPolygon(temp);
p.setClipPath(path);
}
p.drawPixmap(img.rect(), target_pixmap, target_pixmap.rect());
target_pixmap = QPixmap::fromImage(img);
任意形状截图原理
实际上仍然是采用多边形裁剪区域进行图像截取,只是让用户通过拖动鼠标来选择多边形的顶点,所以效果上看就是任意形状的截图区域。

QT框架任意形状截图效果
任意形状截图源代码
生成截图结果的源代码
void ButianyunSnapWidget::updateSnap()
{
if (polygon.size() < 2)
{
return;
}
target_rect = polygon.boundingRect();
if (target_rect.width() < 1 || target_rect.height() < 1)
{
return;
}
target_pixmap = source_pixmap.copy(target_rect);
if (target_pixmap.isNull())
{
return;
}
QImage img(target_pixmap.size(), QImage::Format_ARGB32);
img.fill(QColor(0, 0, 0, 0));
QPainter p(&img);
if (polygon.size() > 2)
{
int mx = source_pixmap.width();
int my = source_pixmap.height();
for (int i = 0; i < polygon.size(); i++)
{
if (polygon.point(i).x() < mx)
{
mx = polygon.point(i).x();
}
if (polygon.point(i).y() < my)
{
my = polygon.point(i).y();
}
}
QPolygon temp;
for (int i = 0; i < polygon.size(); i++)
{
temp.append(QPoint(polygon.point(i).x() - mx,
polygon.point(i).y() - my));
}
QPainterPath path;
path.addPolygon(temp);
p.setClipPath(path);
}
p.drawPixmap(img.rect(), target_pixmap, target_pixmap.rect());
target_pixmap = QPixmap::fromImage(img);
}
完整源代码就不贴在这里了,有兴趣的朋友可以免费索取哈。
如果读者对如何快速全面了解QT框架感兴趣,可以看一下这篇文章:
如果读者对如何学习QT框架有兴趣,可以看一下这篇文章:
如果您认为这篇文章对您有所帮助,请您一定立即点赞+喜欢+收藏,本文作者将能从您的点赞+喜欢+收藏中获取到创作新的好文章的动力。如果您认为作者写的文章还有一些参考价值,您也可以关注这篇文章的作者。
QT框架实现自定义形状截图效果的更多相关文章
- 制作自定义背景Button按钮、自定义形状Button的全攻略(转)
在Android开发应用中,默认的Button是由系统渲染和管理大小的.而我们看到的成功的移动应用,都是有着酷炫的外观和使用体验的.因此,我们在开发产品的时候,需要对默认按钮进行美化.在本篇里,笔者结 ...
- Qt框架及模块认识
小白自工作就接触Qt,一直都在使用Qt5.3.1版本,所以没有经历过大牛们把项目从Qt4程序到Qt5的烦恼,没准以后会碰到.对Qt所有的丰富的API表示惊叹,对于Qt的框架及模块认识也是极为模糊的,文 ...
- Qt计算器开发(三):执行效果及项目总结
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/guodongxiaren/article/details/26046543 执行效果 project ...
- Photoshop如何自定义形状
Photoshop如何自定义形状,自定义形状定义一次,可以随便使用,而且形状无大小,填充后不会有像素问题,普通人可把常用的自定义成形状,很方便.PS中有一些自定义的形状,自己可以随便使用,但是不是很全 ...
- Qt 框架 开发HTTP 服务器 开发记录
最近需求需要开发一款 HTTP ,然后由于先前接触过Qt,就直接用Qt写HTTP服务器了,也是为了当作练手,要不然是直接上HTTP框架的. 后端用C++ Qt框架 前端为了练手 当然是纯生的 js h ...
- QT笔记之自定义窗口拖拽移动
1.QT自定义标题栏,拖拽标题栏移动窗口(只能拖拽标题,其他位置无法拖拽) 方法一: 转载:http://blog.sina.com.cn/s/blog_4ba5b45e0102e83h.html . ...
- 【iOS】7.4 定位服务->2.1.4 定位 - 官方框架CoreLocation 案例:指南针效果
本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正. 本文相关目录: ================== 所属文集:[iOS]07 设备工具 === ...
- 使用Qt框架开发http服务器问题的记录
最近需求需要开发一款 HTTP ,然后由于先前接触过Qt,就直接用Qt写HTTP服务器了,也是为了当作练手,要不然是直接上HTTP框架的. 后端用C++ Qt框架 前端为了练手 当然是纯生的 js h ...
- Three.js基础探寻六——文字形状与自定义形状
1.文字形状 说起3d文字想起了早年word里的一些艺术字: 时间真快. 那么TextGeometry可以用来创建三维的文字形状. 使用文字形状需要下载和引用额外的字体库.这里,我们以 helveti ...
- IDA Pro 6.0使用Qt 框架实现了跨平台的UI
IDA Pro 6.0使用Qt 框架实现了跨平台的UI.它的好处是插件编写者还可以直接使用 Qt 开发跨平台 UI.但是编剧呢? 在这篇博文中,我们将说明如何使用PySide使用IDAPython为 ...
随机推荐
- oeasy教您玩转vim - 76 - # 组合键映射map
会话session 回忆组合键映射的细节 上次我们定义了一系列的复合键 主要是和ctrl键一起 快速跳转window窗口 map <c-j> <c-w>j map < ...
- 第五节 JMeter基础-初级登录【断言的好处】
声明:本文所记录的仅本次操作学习到的知识点,其中商城IP错误,请自行更改. 1.认识JMeter (1)断言 预期结果和实际结果的比较,如果不一样,断言失败. 2.注册 (1)直接复制[登录]粘贴一下 ...
- Django Template层之Template概述
Django Template层之Template概述 by:授客 QQ:1033553122 实践环境 Python版本:python-3.4.0.amd64 下载地址:https://www.py ...
- 2024NOI联合省选游记
人生当中成功只是一时的,而失败却是主旋律. 不太好的的阅读体验 本文作者:xxxalq 所谓游记,顾名思义就是指游玩所记,所以重点在玩而不在省选. 由于没有参加 \(\text{NOIP}\),导致我 ...
- layui表格列添加超链接并传参
1.表格渲染中对列添加templet属性 addlink为方法名 tableIns = table.render({ elem: '#Test' ...
- 我用Awesome-Graphs看论文:解读Naiad
Naiad论文:<Naiad: A Timely Dataflow System> 前面通过文章<论文图谱当如是:Awesome-Graphs用200篇图系统论文打个样>向大家 ...
- 【微信小程序】03 配置项
全局配置项: https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html 属性 类型 必填 描述 ...
- 图解Java设计模式
待补充 设计模式介绍 设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案. 设计模式使用的位置 功能模块+框架上. 设计模式在软件中哪里?面向对象( ...
- 告别手动调度,海豚调度器 3.1.x 集群部署让你轻松管理多机!
转载自第一片心意 1 前言 由于海豚调度器官网的集群部署文档写的较乱,安装过程中需要跳转到很多地方进行操作,所以自己总结了一篇可以直接跟着从头到尾进行操作的文档,以方便后续的部署.升级.新增节点.减少 ...
- 暑假Java自学进度总结05
一.今日所学: 1.if的第一个表达式: if(关系表达式){ 语句: } 执行流程: 1>首先执行关系表达式的值 2>如果关系表达式的值为true则执行语句,否则不执行 3>继续执 ...