QT截图程序,可多屏幕截图二,增加调整截图区域功能

上一篇QT截图程序,可多屏幕截图只是实现了最基本的截图功能,虽然能用但是缺点也有,没办法更改选中的区域,这在实际使用时不太方便。这篇增加了这个功能。先看看效果。

实现代码为:

头文件

#ifndef MASKWIDGET_H
#define MASKWIDGET_H#include <QWidget>
#include "mainwindow.h"
namespace Ui {
class MaskWidget;
}
enum SnapState{NoSnap,Snapped,PreLeftDrag,LeftDrag,PreRightDrag,RightDrag,PreTopDrag,TopDrag,PreBottomDrag,BottomDrag
};class MaskWidget : public QWidget
{Q_OBJECTpublic:explicit MaskWidget(QWidget *parent = nullptr);~MaskWidget();
protected:void mousePressEvent(QMouseEvent *event)override;void mouseReleaseEvent(QMouseEvent *event)override;void mouseMoveEvent(QMouseEvent *event)override;void paintEvent(QPaintEvent *event)override;void keyPressEvent(QKeyEvent *event) override;void showEvent(QShowEvent *event) override;private slots:void ResetSnap();private:QPoint m_pressPos;QPoint m_newPos;QRect m_maskRect{0, 0, 0, 0};QPixmap m_image;bool isPressed{false};MainWindow m;SnapState snapstate{NoSnap};
private:Ui::MaskWidget *ui;};#endif // MASKWIDGET_H

源文件

#include "maskwidget.h"
#include "ui_maskwidget.h"
#include <QMouseEvent>
#include <QRegion>
#include <QScreen>
#include <QPainter>
#include <QGuiApplication>
#include <QPixmap>
#include <QDebug>
#include <QtMath>
#include <QCursor>const int MINSIZE = 10;MaskWidget::MaskWidget(QWidget *parent) :QWidget(parent),ui(new Ui::MaskWidget)
{ui->setupUi(this);setMouseTracking(true);setWindowFlags(Qt::FramelessWindowHint);setWindowOpacity(0.8);QList<QScreen*> screens = QGuiApplication::screens();int width = 0;int height = 0;for (QScreen *screen : screens){width += screen->geometry().width();if (height < screen->geometry().height()){height = screen->geometry().height();}qDebug()<<screen->geometry();}this->setFixedSize(width, height);m.hide();connect(&m, SIGNAL(resetSnap()), this, SLOT(ResetSnap()));
}MaskWidget::~MaskWidget()
{delete ui;
}void MaskWidget::mousePressEvent(QMouseEvent *event)
{if (event->button() == Qt::LeftButton){if (m_maskRect.width() == 0 && m_maskRect.width() == 0){m_pressPos = event->pos();this->setCursor(Qt::CrossCursor);isPressed = true;update();}if (snapstate == PreLeftDrag){snapstate = LeftDrag;}else if (snapstate == PreRightDrag){snapstate = RightDrag;}else if (snapstate == PreTopDrag){snapstate = TopDrag;}else if (snapstate == PreBottomDrag){snapstate = BottomDrag;}}if (event->button() == Qt::RightButton){if (m_maskRect.width() > 0){isPressed = false;QRegion all(0, 0, width(), height());QRegion sub(m_maskRect);setMask(all.subtracted(sub));QPixmap combined(this->width(), this->height());combined.fill(Qt::transparent);QPainter painter(&combined);QList<QScreen*> screens = QGuiApplication::screens();for (QScreen *screen : screens){m_image = screen->grabWindow(0);painter.drawPixmap(screen->geometry().x(), 0, screen->geometry().width(), screen->geometry().height(), m_image);}//            auto gpos = mapToGlobal(event->pos());
//            auto gposStart = mapToGlobal(m_pressPos);
//            qDebug()<<gpos<<gposStart;//m_image = combined.copy(qMin(gpos.x(), gposStart.x()), qMin(gpos.y(), gposStart.y()),//                        qFabs(gpos.x() - gposStart.x()), qFabs(gpos.y() - gposStart.y()));m_image = combined.copy(m_maskRect);this->hide();m.SetImage(m_image);update();m.show();}}QWidget::mousePressEvent(event);
}void MaskWidget::mouseReleaseEvent(QMouseEvent *event)
{qDebug()<<__func__<<" "<<snapstate;if (isPressed){isPressed = false;snapstate = Snapped;this->setCursor(Qt::ArrowCursor);}switch(snapstate){case LeftDrag:{snapstate = Snapped;this->setCursor(Qt::ArrowCursor);}break;case RightDrag:{snapstate = Snapped;this->setCursor(Qt::ArrowCursor);}break;case TopDrag:{snapstate = Snapped;this->setCursor(Qt::ArrowCursor);}break;case BottomDrag:{snapstate = Snapped;this->setCursor(Qt::ArrowCursor);}break;default:break;}return QWidget::mouseReleaseEvent(event);
}void MaskWidget::mouseMoveEvent(QMouseEvent* event)
{if (isPressed){m_newPos = event->pos();QRegion all(0, 0, width(), height());m_maskRect = QRect(qMin(m_pressPos.x(), m_newPos.x()),qMin(m_pressPos.y(), m_newPos.y()),qAbs(m_newPos.x() - m_pressPos.x()),qAbs(m_newPos.y() - m_pressPos.y()));QRegion sub(m_maskRect);setMask(all.subtracted(sub));update();}else{switch(snapstate){case Snapped:{if (m_maskRect.bottom() > event->pos().y() && m_maskRect.top() < event->pos().y()){if (qFabs(m_maskRect.left() - event->pos().x()) < 5){this->setCursor(Qt::SizeHorCursor);this->snapstate = PreLeftDrag;}else if (qFabs(m_maskRect.right() - event->pos().x()) < 5){this->setCursor(Qt::SizeHorCursor);this->snapstate = PreRightDrag;}}else if (m_maskRect.left() < event->pos().x() && m_maskRect.right() > event->pos().y()){if (qFabs(m_maskRect.top() - event->pos().y()) < 5){this->setCursor(Qt::SizeVerCursor);this->snapstate = PreTopDrag;}else if (qFabs(m_maskRect.bottom() - event->pos().y()) < 5){this->setCursor(Qt::SizeVerCursor);this->snapstate = PreBottomDrag;}}}break;case LeftDrag:{if (event->pos().x() + MINSIZE >= m_maskRect.right()){m_maskRect.setLeft(m_maskRect.right() - MINSIZE);}else{m_maskRect.setLeft(event->pos().x() + 2);}QRegion sub(m_maskRect);QRegion all(0, 0, width(), height());setMask(all.subtracted(sub));qDebug()<<m_maskRect;update();}break;case PreLeftDrag:{if (qFabs(m_maskRect.left() - event->pos().x()) >= 5 || event->pos().y() > m_maskRect.bottom() || event->pos().y() < m_maskRect.top()){this->setCursor(Qt::ArrowCursor);this->snapstate = Snapped;}}break;case PreRightDrag:{if (qFabs(event->pos().x() - m_maskRect.right()) >= 5 || event->pos().y() > m_maskRect.bottom() || event->pos().y() < m_maskRect.top()){this->setCursor(Qt::ArrowCursor);this->snapstate = Snapped;}}break;case RightDrag:{if (event->pos().x() - MINSIZE <= m_maskRect.left()){m_maskRect.setRight(m_maskRect.left() + MINSIZE);}else{m_maskRect.setRight(event->pos().x() - 2);}QRegion sub(m_maskRect);QRegion all(0, 0, width(), height());setMask(all.subtracted(sub));qDebug()<<m_maskRect;update();}break;case PreTopDrag:{if (qFabs(event->pos().y() - m_maskRect.top()) >= 5 || event->pos().x() < m_maskRect.left() || event->pos().x() > m_maskRect.right()){this->setCursor(Qt::ArrowCursor);this->snapstate = Snapped;}}break;case TopDrag:{if (event->pos().y() + MINSIZE >= m_maskRect.bottom()){m_maskRect.setTop(m_maskRect.bottom() - MINSIZE);}else{m_maskRect.setTop(event->pos().y() + 2);}QRegion sub(m_maskRect);QRegion all(0, 0, width(), height());setMask(all.subtracted(sub));update();}break;case PreBottomDrag:{if (qFabs(event->pos().y() - m_maskRect.bottom()) >= 5 || event->pos().x() < m_maskRect.left() || event->pos().x() > m_maskRect.right()){this->setCursor(Qt::ArrowCursor);this->snapstate = Snapped;}}break;case BottomDrag:{if (event->pos().y() - MINSIZE <= m_maskRect.top()){m_maskRect.setBottom(m_maskRect.top() + MINSIZE);}else{m_maskRect.setBottom(event->pos().y() - 2);}QRegion sub(m_maskRect);QRegion all(0, 0, width(), height());setMask(all.subtracted(sub));update();}break;default:break;}}return QWidget::mouseMoveEvent(event);
}void MaskWidget::paintEvent(QPaintEvent *)
{QPainter painter(this);painter.setPen(Qt::red);painter.drawRect(m_maskRect.x()-1, m_maskRect.y()-1, m_maskRect.width()+1, m_maskRect.height() + 1);}void MaskWidget::keyPressEvent(QKeyEvent *event)
{if (event->key() == Qt::Key_Escape){close();}else if (event->key() == Qt::Key_Enter){if (isPressed){isPressed = false;snapstate = Snapped;this->setCursor(Qt::ArrowCursor);}}QWidget::keyPressEvent(event);
}void MaskWidget::showEvent(QShowEvent *event)
{QWidget::showEvent(event);
}void MaskWidget::ResetSnap()
{QRegion all(0, 0, width(), height());setMask(all);m_maskRect.setRect(0,0,0,0);snapstate = NoSnap;this->show();
}

思路:

第一,要保留住选中的框,选中后停留下来不自动跳转。实现方式为在mouseRelease函数里面不再进行隐藏和跳转,跳转改称点击鼠标右键。

第二,当鼠标移动到边框附近时,鼠标的形状要进行变化,表示可以拖动了。左右边对应的是双向横箭头,上下边对应的是双向竖箭头。这里取值距离5作为触发区域,当距离小于5时可进行拖动。类似途中的红色区域。

第三,为了配合形状变化,用一个枚举来表示不同的状态。

enum SnapState{NoSnap,Snapped,PreLeftDrag,LeftDrag,PreRightDrag,RightDrag,PreTopDrag,TopDrag,PreBottomDrag,BottomDrag
};

NoSnap表示初始状态,没有开始截图的时候。

Snapped表示已经截图了,此时会显示一个矩形方框。

PreLeftDrag表示进入左侧边框可拖动状态,此时鼠标形状变化成左右箭头。

        PreLeftDrag----按下鼠标左键--->LeftDrag(可移动鼠标来拖动边框)

        PreLeftDrag----鼠标距离左边框的距离大于5--->Snapped(鼠标状态恢复正常)

LeftDrag表示进入可拖动状态,可拖动鼠标更改左边框位置。此时松开鼠标则回到PreLeftDrag状态

其他几个状态类似。

根据鼠标的位置和动作,变化不同的状态。这里由于逻辑简单,没有使用状态机。

为了有更好的显示效果,这里限制了拖动区域,不会出现一条边覆盖另一条的情况,可在动图里看出来。

这样修改后,截图工具好用了很多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/336517.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NTLite深度Windows系统镜像文件修改定制

计算机爱好者和技术宅的圈子里,NTLite是一个广受欢迎的名字,一款强大的Windows系统定制工具,允许用户对Windows安装镜像进行深度修改,从而打造出一个更加个性化、高效且精简的操作系统。无论是为了优化系统性能、移除不必要的组件,还是集成最新的更新和驱动,NTLite都能成…

2024 最新版 Navicat 17 下载与安装步骤及演示 (图文版)

Navicat 是一款专业的数据库管理工具&#xff0c;支持多种数据库类型&#xff0c;包括 MySQL、Oracle、SQL Server、PostgreSQL、MariaDB、Redis、MongoDB 和 SQLite。Navicat17包含的版本如下Navicat Premium 17, Navicat 17 for MySQL, Navicat 17 for Oracle, Navicat 17 fo…

React中 将UI 视为树

当 React 应用程序逐渐成形时&#xff0c;许多组件会出现嵌套。那么 React 是如何跟踪应用程序组件结构的&#xff1f; React 以及许多其他 UI 库&#xff0c;将 UI 建模为树。将应用程序视为树对于理解组件之间的关系以及调试性能和状态管理等未来将会遇到的一些概念非常有用。…

网络故障与排除(一)

一、Router-ID冲突导致OSPF路由环路 路由器收到相同Router-ID的两台设备发送的LSA&#xff0c;所以查看路由表看到的OSPF缺省路由信息就会不断变动。而当C1的缺省路由从C2中学到&#xff0c;C2的缺省路由又从C1中学到时&#xff0c;就形成了路由环路&#xff0c;因此出现路由不…

cocos creator 3.x 手搓背包拖拽装备

项目背景&#xff1a; 游戏背包 需要手动 拖拽游戏装备到 装备卡槽中&#xff0c;看了下网上资料很少。手搓了一个下午搞定&#xff0c;现在来记录下实现步骤&#xff1b; 功能拆分&#xff1a; 一个完整需求&#xff0c;我们一般会把它拆分成 几个小步骤分别造零件。等都造好了…

MGR集群模拟故障切换

说明&#xff1a; 1、MGR集群搭建起来&#xff0c;但不知道是否能进行启动切换&#xff0c;故要手动模拟故障并且验证 2、停止主库master服务&#xff0c;登录mysql查看MGR是否进行自动切换。 3、主库切换完成以后&#xff0c;手动将宕机的服务器添加到MGR集群中。 一、模拟故障…

【Unity AR开发插件】五、运行示例程序

专栏 本专栏将介绍如何使用这个支持热更的AR开发插件&#xff0c;快速地开发AR应用。 链接&#xff1a; Unity开发AR系列 热更数据制作&#xff1a;制作热更数据-AR图片识别场景 插件简介 通过热更技术实现动态地加载AR场景&#xff0c;简化了AR开发流程&#xff0c;让用户可…

Java整合ELK实现日志收集 之 Elasticsearch、Logstash、Kibana

简介 Logstash&#xff1a;用于收集并处理日志&#xff0c;将日志信息存储到Elasticsearch里面 Elasticsearch&#xff1a;用于存储收集到的日志信息 Kibana&#xff1a;通过Web端的可视化界面来查看日志&#xff08;数据可视化&#xff09; Logstash 是免费且开放的服务器端数…

视频智能分析平台LntonAIServer视频监控管理平台裸土检测算法的重要性与应用

随着科技的飞速发展&#xff0c;人工智能技术在各个领域的应用越来越广泛。其中&#xff0c;LntonAIServer裸土检测算法作为一种先进的技术手段&#xff0c;已经在农业、环境保护等领域取得了显著的成果。本文将探讨LntonAIServer裸土检测算法的重要性及其在实际应用中的优势。…

鸿蒙应用模型:【Stage模型开发】概述

Stage模型开发概述 基本概念 下图展示了Stage模型中的基本概念。 图1 Stage模型概念图 [AbilityStage] 每个Entry类型或者Feature类型的HAP在运行期都有一个AbilityStage类实例&#xff0c;当HAP中的代码首次被加载到进程中的时候&#xff0c;系统会先创建AbilityStage实例…

【NumPy】全面解析subtract函数:高效数组减法指南

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

推荐系统学习笔记(三)

swing召回通道 Q&#xff1a;假如重合的用户是一个小圈子&#xff1a;在一个群里&#xff0c;毫无关联的笔记也会被同时交互 solve&#xff1a;降低小圈子权重--------------swing的主要目的------------给用户加权 相似度&#xff1a; a是人工参数&#xff0c;overlap降低小…

零基础小白本地部署大疆上云api(个人记录供参考)

文章目录 运行前准备前后端项目运行1.前端项目&#xff1a; 后端项目运行必须先依靠emqx运行必须先依靠redis运行修改后端项目的application.yml文件 运行前准备 1.保证电脑又node.js环境&#xff0c;可以正常使用npm 2.Java的jdk必须是11及以上版本否则无效 3.下载好emqx,red…

神经网络与深度学习——第14章 深度强化学习

本文讨论的内容参考自《神经网络与深度学习》https://nndl.github.io/ 第14章 深度强化学习 深度强化学习 强化学习&#xff08;Reinforcement Learning&#xff0c;RL&#xff09;&#xff0c;也叫增强学习&#xff0c;是指一类从与环境交互中不断学习的问题以及解决这类问题…

工程项目管理系统的Java实现:高效协同与信息共享

在当今的工程领域&#xff0c;项目管理的高效协同和信息共享是提升工作效率、降低成本的关键。本文将向您介绍一款基于Java技术构建的工程项目管理系统&#xff0c;该系统采用前后端分离的先进技术框架&#xff0c;功能全面&#xff0c;能够满足不同角色的需求&#xff0c;从项…

linux的磁盘分区与管理

磁盘分区与管理 识别磁盘 一块硬盘的“艺术”之旅&#xff08;硬盘空间使用&#xff0c;经历的步骤&#xff09; •识别硬盘 > 分区规划 > 格式化 > 挂载使用 Unix/Linux的基本哲学理念&#xff1a;一切皆文件 /dev:存放设备&#xff08;键盘、鼠标、光驱、硬盘……

攀爬二叉树,发现新的美

二叉树 什么是二叉树? 二叉树的基础概念? 性质? 问题? 文章目录 二叉树一、二叉树的概念(一)认识二叉树(二)二叉树的性质 二、遍历二叉树1.前序遍历2.中序遍历3.后序遍历4.层序遍历 三丶创建二叉树总结 一、二叉树的概念 (一)认识二叉树 二叉树是一种非线性的数据结构,…

SFOS2:组件介绍

一、前言 在sailfish os application的开发过程中&#xff0c;几乎是困难重重&#xff0c;因为我暂未找到具有完整性、指导性、易懂性的开发文档&#xff0c;特别是组件的使用&#xff0c;现决定将自己的探究结果记录下来。因此&#xff0c;这篇文章只会具有参考价值&#xff0…

UI自动化测试最佳设计模式POM

当使用Selenium进行UI自动化测试时&#xff0c;Page Object Model&#xff08;POM&#xff09;是一种最佳实践的设计模式。POM的核心思想是通过将页面封装成对象&#xff0c;使得测试代码更加清晰、可维护和可重用。 POM的主要组成部分包括页面对象类、元素定位方式和操作方法…

从 0 开始实现一个博客系统 (SSM 项目)

相关技术 Spring Spring Boot Spring MVC MyBatis Html Css JS pom 文件我就不放出来了, 之前用的 jdk8 做的, MySQL 用的 5.7, 都有点老了, 你们自己看着配版本就好 实现功能 用户注册 - 密码加盐加密 (md5 加密)前后端用户信息存储 - 令牌技术用户登录 - (使用 拦截…