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

news2024/11/15 1:34:27

上一篇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_OBJECT

public:
    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.coloradmin.cn/o/1715062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IEEE Latex模版踩雷避坑指南

参考文献 原Latex模版 \begin{thebibliography}{1} \bibliographystyle{IEEEtran}\bibitem{ref1} {\it{Mathematics Into Type}}. American Mathematical Society. [Online]. Available: https://www.ams.org/arc/styleguide/mit-2.pdf\bibitem{ref2} T. W. Chaundy, P. R. Ba…

价值飙升30%,AI PC拉动半导体出货潮

由于处理器和DRAM的升级&#xff0c;大摩预测每台AI PC的半导体价值将增长20%-30%&#xff0c;PC平均售价也将提高7%。 台北国际电脑展即将于6月2日隆重开幕。 随着展会的临近&#xff0c;各种现象级的AI PC也蓄势待发。 就在上周&#xff0c;联想在业绩会上&#xff0c;首次…

2024 五月份国内外CTF 散装re 部分wp

cr3CTF warmup 附件拖入ida main函数无法反汇编&#xff0c;仔细看&#xff0c;有花指令&#xff0c;jnz实际上必定跳转。有非常多处&#xff0c;可以写脚本patch程序去掉花指令&#xff0c;只要匹配指令&#xff0c;再获取跳转地址&#xff0c;nop掉中间的代码就行。但…

HAL库使用FreeRTOS实时操作系统时配置时基源(TimeBase Source)

需要另外的定时器&#xff0c;用systic的时候生成项目会有警告 https://blog.51cto.com/u_16213579/10967728

车载客流统计设备:双目3D还原智能统计算法的应用与优势

随着城市交通的日益繁忙和公共交通系统的不断完善&#xff0c;对公交车等交通工具的客流统计和分析变得越来越重要。传统的客流统计方法往往存在效率低下、精度不足等问题&#xff0c;难以满足现代城市交通管理的需求。而基于双目3D还原智能统计算法的车载客流统计设备&#xf…

开源一个工厂常用的LIMS系统

Senaite是一款强大且可靠的基于Web的LIMS/LIS系统&#xff0c;采用Python编写&#xff0c;构建在Plone CMS基础架构之上。该系统处于积极开发阶段&#xff0c;在灵活的定制空间中为开发人员提供了丰富的功能。其中&#xff0c;Senaite在处理REST的JSON API上做得出色&#xff0…

【busybox记录】【shell指令】readlink

目录 内容来源&#xff1a; 【GUN】【readlink】指令介绍 【busybox】【readlink】指令介绍 【linux】【readlink】指令介绍 使用示例&#xff1a; 打印符号链接或规范文件名的值 - 默认输出 打印符号链接或规范文件名的值 - 打印规范文件的全路径 打印符号链接或规范文…

如何更改SSH服务器端口以减少蛮力攻击

本周有一个客户&#xff0c;购买Hostease的独立服务器&#xff0c;询问我们的在线客服&#xff0c;如何更改SSH服务器端口以减少蛮力攻击&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可以对…

Element-UI 入门指南:从安装到自定义主题的详细教程

Element-UI 是一个基于 Vue.js 的前端组件库&#xff0c;它提供了丰富的 UI 组件&#xff0c;可以帮助开发者快速构建高质量的用户界面。以下是使用 Element-UI 的快速入门指南&#xff1a; 安装 Element-UI Element-UI 是一个基于 Vue.js 的组件库&#xff0c;它提供了丰富的…

opencv进阶 ——(七)图像处理之寸照换背景

寸照换背景&#xff0c;通常指的是将个人证件照片的背景色更换为另一种颜色&#xff0c;如白色、蓝色或红色等&#xff0c;以满足不同用途的要求。例如&#xff0c;护照照片通常要求白色背景&#xff0c;而身份证照片可能需要蓝色背景。这个过程通常涉及到图像处理技术&#xf…

网工内推 | 国企信息安全工程师,CISP认证优先

01 浙江省公众信息产业有限公司 &#x1f537;招聘岗位&#xff1a;安全运营工程师 &#x1f537;职责描述&#xff1a; 1. 负责公司内部安全运营平台及其子系统的安全事件管理、事件发现分析、应急响应和系统维护等&#xff1b; 2. 负责风险和漏洞管理&#xff0c;包括漏洞预…

数据结构 | 详解二叉树——堆与堆排序

&#x1f95d;堆 堆总是一棵完全二叉树。 大堆&#xff1a;父节点总是大于子节点。 小堆&#xff1a;父节点总是小于子节点。 注意&#xff1a;1.同一个节点下的两个子节点并无要求先后顺序。 2.堆可以是无序的。 &#x1f349;堆的实现 &#x1f334;深度剖析 1.父节点和子…

社会网络,生态网络,贸易网络,复杂网络边介数蓄意和随机攻击

​边介数&#xff08;Edge Betweenness&#xff09; # ” 边介数&#xff08;Edge Betweenness&#xff09; 1 边介数&#xff08;Edge Betweenness&#xff09; Summer IS HERE 边介数&#xff08;Edge Betweenness&#xff09;是一种度量边在网络中重要性的指标。它定义为…

安卓手机玩Switch-YUZU模拟器

不需要傻乎乎地去买Switch了&#xff01; 不是Switch不好&#xff0c;等什么时候任天堂升级硬件&#xff0c;出了Switch2之后我再来支持吧&#xff01; Yuzu Yuzu 按照官网给的教程下载

OrangePi AIpro测评

文章目录 1、外观部分2、系统初探3、AI性能体验4、总结 首先非常感谢csdn以及香橙派能够提供这样一个平台&#xff0c;可以测试OrangePi AIpro这样一块开发板&#xff0c;这块板子给我的感觉还是非常不错的&#xff0c;非常适合用来作为嵌入式学习的板子&#xff0c;性能也达到…

OpenMV学习笔记2——颜色识别

目录 一、打开单颜色识别实例代码 二、代码基础部分 三、阈值选择 四、给识别到的颜色画框 五、多颜色识别 一、打开单颜色识别实例代码 如图&#xff0c;双击打开对应文件即可进入实例代码。 二、代码基础部分 # Single Color RGB565 Blob Tracking Example # # This e…

JavaWeb基础(一)-IO操作

Java I/O工作机制&#xff1a; 注&#xff1a;简要笔记&#xff0c;示例代码可能较少&#xff0c;甚至没有。 1、Java 的 I/O 类库的基本架构。 ​ Java 的 I/O 操作类在包 java.io 下&#xff0c;大概有将近80个类&#xff0c;这些类大概可以分为如下四组。 基于字节操作的…

mysql中InnoDB的统计数据

大家好。我们知道&#xff0c;mysql中存在许多的统计数据&#xff0c;比如通过SHOW TABLE STATUS 可以看到关于表的统计数据&#xff0c;通过SHOW INDEX可以看到关于索引的统计数据&#xff0c;那么这些统计数据是怎么来的呢&#xff1f;它们是以什么方式收集的呢&#xff1f;今…

LLAMA3==shenzhi-wang/Llama3-8B-Chinese-Chat。windows安装不使用ollama

创建环境&#xff1a; conda create -n llama3_env python3.10 conda activate llama3_env conda install pytorch torchvision torchaudio cudatoolkit11.7 -c pytorch 安装Hugging Face的Transformers库&#xff1a; pip install transformers sentencepiece 下载模型 ht…

海尔智家牵手罗兰-加洛斯,看全球创牌再升级

晚春的巴黎西郊&#xff0c;古典建筑群与七叶树林荫交相掩映&#xff0c;坐落于此的罗兰加洛斯球场内座无虚席。 来自全球各地的数万观众&#xff0c;正与场外街道上的驻足者们一起&#xff0c;等待着全世界最美好的网球声响起…… 当地时间5月26日&#xff0c;全球四大职业网…