QT实现的截屏工具与录像功能

news2024/11/18 18:21:46

前言

目前实现了高仿微信的截屏工具,alt+x截屏,用户选取区域进行截屏确认,截屏完成后复制到了粘贴板,用全局按键监听按键,程序在最小化时也可以对按键进行监听,有截屏预览与保存按键。
大致流程:main->widget->按下截屏按键->takeScreenshot()合并主屏幕和副屏的截图->创建FullScreenWindow类->用户选择区域->确认->发送确认信号->QGraphicsScene预览。
注释写的还算较为全,最近在找工作没有太多的时间写博客,这里单纯记录一下,后续准备通过ffmpeg库来实现录像功能,有问题欢迎留言。
部分功能预览图:
在这里插入图片描述

widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMouseEvent>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QShortcut>
#include <QHotkey>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

protected:
    //void paintEvent(QPaintEvent *event) override;
//    void mousePressEvent(QMouseEvent *event) override;
//    void mouseMoveEvent(QMouseEvent *event) override;
//    void mouseReleaseEvent(QMouseEvent *event) override;
private slots:
    void on_screenshotButton_clicked();

    void on_saveButton_clicked();

private:
    Ui::Widget *ui;
    QPoint startPos;
    QPoint endPos;
    QGraphicsScene *scene;
    QShortcut *shortcut;
    QHotkey* hotkey;
    QPixmap scaledScreenshot;
    bool screenshotCompleted; // 标志位,表示截图是否已完成
    void handleScreenshotSelected(const QPixmap& selectedScreenshot);
    void handleScreenshotCancelled();
    void takeScreenshot();
};
#endif // WIDGET_H

widget.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include "fullscreenwindow.h"
#include <QClipboard>
#include <QPainter>
#include <QScreen>
#include <QDesktopWidget>
#include <QWidget>
#include <QFileDialog>
#include <QMessageBox>
#include <QTime>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget),screenshotCompleted(true)
{
    ui->setupUi(this);
    //移除最大化按钮并限制更改大小
    setWindowFlags(windowFlags()&~Qt::WindowMaximizeButtonHint); setFixedSize(this->width(), this->height());
    // 创建场景和图像项
    scene = new QGraphicsScene(this);
    ui->graphicsView->setScene(scene);
//    // 按键
//    shortcut = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_X), this);
//    connect(shortcut, &QShortcut::activated, this, &Widget::takeScreenshot);
    // 创建全局快捷键监听
    hotkey = new QHotkey(QKeySequence(Qt::ALT + Qt::Key_X), true, this);
    connect(hotkey, &QHotkey::activated, this, &Widget::takeScreenshot);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::takeScreenshot()
{
    // 获取主屏幕和副屏的截图
    QScreen *primaryScreen = QGuiApplication::primaryScreen();
    QScreen *secondaryScreen = nullptr; 

    QList<QScreen*> screens = QGuiApplication::screens();
    if (screens.size() > 1) {
        secondaryScreen = screens.at(1); // 假设第二个屏幕是副屏
    }

    QPixmap primaryScreenshot = primaryScreen->grabWindow(0);
    QPixmap secondaryScreenshot = secondaryScreen ? secondaryScreen->grabWindow(0) : QPixmap(); // 如果没有副屏,使用空的 QPixmap

    // 合并主屏幕和副屏的截图
    QPixmap combinedScreenshot(primaryScreenshot.width() + secondaryScreenshot.width(), std::max(primaryScreenshot.height(), secondaryScreenshot.height()));
    QPainter painter(&combinedScreenshot);
    painter.drawPixmap(0, 0, primaryScreenshot);
    painter.drawPixmap(primaryScreenshot.width(), 0, secondaryScreenshot);

    // 创建全屏窗口并传递合并后的截图
    FullScreenWindow *fullscreenWindow = new FullScreenWindow(combinedScreenshot);
    connect(fullscreenWindow, &FullScreenWindow::screenshotSelected, this, &Widget::handleScreenshotSelected);
    connect(fullscreenWindow, &FullScreenWindow::screenshotCancelled, this, &Widget::handleScreenshotCancelled);


}


void Widget::on_screenshotButton_clicked()
{
    if (screenshotCompleted) {
        screenshotCompleted = false; // 设置标志位为false,表示截图进行中
        hide(); // 隐藏主界面
        // 添加一个等待操作以确保主界面完全隐藏
        QTime dieTime = QTime::currentTime().addMSecs(100); // 100毫秒的等待时间
        while (QTime::currentTime() < dieTime)
        {
            QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
        }
        takeScreenshot();
    }
}

void Widget::handleScreenshotSelected(const QPixmap& selectedScreenshot)
{
    QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem();
    // 处理截图完成后的操作
    screenshotCompleted = true; // 设置标志位为true,表示截图已完成
    //将屏幕截图复制到剪贴板
    QClipboard *clipboard = QGuiApplication::clipboard();
    clipboard->setPixmap(selectedScreenshot);
    // 缩放截图适应窗体大小
    scaledScreenshot = selectedScreenshot.scaled(ui->graphicsView->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
    pixmapItem->setPixmap(scaledScreenshot);
    scene->clear();
    scene->addItem(pixmapItem);
    show(); // 显示主界面

}

void Widget::handleScreenshotCancelled()
{
    screenshotCompleted = true; // 设置标志位为true,表示截图已完成
    show(); // 显示主界面
}


void Widget::on_saveButton_clicked()
{
    if (screenshotCompleted) {
           screenshotCompleted = false; // 设置标志位为false,表示保存截图进行中

           if (!scaledScreenshot.isNull()) {
               // 打开文件对话框以获取保存路径和文件名
               QString filePath = QFileDialog::getSaveFileName(this, "保存截图", QDir::homePath(), "Images (*.png *.jpg *.bmp)");

               if (!filePath.isEmpty()) {
                   // 保存截图到指定路径
                   scaledScreenshot.save(filePath);
                   screenshotCompleted = true; // 设置标志位为true,表示保存截图已完成
                   QMessageBox::information(this, "保存成功", "截图已成功保存");
               }
           } else {
               // 如果截图为空,弹出警告
               screenshotCompleted = true; // 设置标志位为true,表示保存截图已完成
               QMessageBox::warning(this, "警告", "当前没有截图可保存");
           }
       }
}


fullscreenwindow.h文件

#ifndef FULLSCREENWINDOW_H
#define FULLSCREENWINDOW_H

#include <QWidget>
#include <QPixmap>
#include <QRect>
#include <QPushButton>

class FullScreenWindow : public QWidget
{
    Q_OBJECT
public:
    FullScreenWindow(QPixmap screenshot);

protected:
    // 函数声明
    void paintEvent(QPaintEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void keyPressEvent(QKeyEvent *event) override;


private:
    QPushButton *confirmButton;
    QPushButton *cancelButton;
    QPixmap screenshot;
    QRect selectionRect;
    QPoint startPos;
    QPoint endPos;
    QRect selectedRegion;
    QPixmap fullScreenScreenshot;
    void closeWindow();
    void confirmSelection();
    void cancelSelection();


signals:
    void screenshotSelected(const QPixmap& screenshot);
    void screenshotCancelled();
};

#endif // FULLSCREENWINDOW_H

fullscreenwindow.cpp文件

#include "fullscreenwindow.h"
#include <QPainter>
#include <QMouseEvent>
#include <QApplication>
#include <QDesktopWidget>
#include <QVBoxLayout>
#include <QScreen>


FullScreenWindow::FullScreenWindow(QPixmap screenshot) : screenshot(screenshot)
{
    setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
    setCursor(QCursor(Qt::CrossCursor));
    // 设置窗口位置和大小以适应图像大小
    setGeometry(0, 0, screenshot.width(), screenshot.height());

    // 在构造函数中创建按钮并设置属性
    confirmButton = new QPushButton("确定", this);
    confirmButton->setMinimumSize(80, 30);
    confirmButton->setMaximumSize(80, 30);
    confirmButton->hide();
    cancelButton = new QPushButton("取消", this);
    cancelButton->setMinimumSize(80, 30);
    cancelButton->setMaximumSize(80, 30);
    cancelButton->hide();
    connect(confirmButton, &QPushButton::clicked, this, &FullScreenWindow::confirmSelection);
    connect(cancelButton, &QPushButton::clicked, this, &FullScreenWindow::cancelSelection);
    show();
}

void FullScreenWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.drawPixmap(0, 0, screenshot);
    painter.setPen(QPen(Qt::red, 1, Qt::DashLine));

    QRect selectionRect(startPos, endPos);
    painter.drawRect(selectionRect);
}



void FullScreenWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        startPos = event->pos();
        //selectingScreenshot = true;
    }
}

void FullScreenWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton)
    {
        endPos = event->pos();
        update();
    }
}

void FullScreenWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        selectedRegion = QRect(startPos, endPos);
        // 处理用户选择的区域
        // 在用户选择区域的正下方放置按钮
        int buttonX = selectedRegion.center().x() - confirmButton->width() / 2;
        int buttonY = selectedRegion.bottom() + 10; // 10 是按钮与选择区域的间距

        // 设置按钮的位置
        confirmButton->move(buttonX, buttonY);
        cancelButton->move(buttonX + confirmButton->width() + 10, buttonY);
        // 显示按钮
        confirmButton->show();
        cancelButton->show();
//        // 创建布局管理器,并将按钮放置在适当的位置
//        QVBoxLayout *layout = new QVBoxLayout(this);
//        layout->addWidget(confirmButton);
//        layout->addWidget(cancelButton);
//        // 设置布局的边框和背景颜色

//        // 设置布局的位置
//        int layoutTop = selectionRect.bottom() + 10;  // 10 是布局距离矩形框底部的垂直偏移量
//        //layout->setGeometry(QRect(10, layoutTop, layout->sizeHint().width(), layout->sizeHint().height()));
        //setLayout(layout);
    }
}

void FullScreenWindow::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Escape) {
            // 如果用户按下 ESC 键,关闭窗口
            close();
            emit screenshotCancelled();
        }
}
void FullScreenWindow::confirmSelection()
{
    if (!selectedRegion.isEmpty())
    {
        // 裁剪整个屏幕截图为所选区域
        QPixmap croppedScreenshot = screenshot.copy(selectedRegion);
        // 发送裁剪后的截图给主页面
        emit screenshotSelected(croppedScreenshot);

        // 关闭窗口
        close();
    }
}

void FullScreenWindow::cancelSelection()
{
    emit screenshotCancelled();
    // 关闭窗口
    close();
}

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

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

相关文章

统计学中箱型图的理解

一、箱形图的介绍 箱形图又称为盒须图、盒式图、盒状图或箱线图&#xff0c;是一种用作显示一组数据分散情况的统计图&#xff0c;因型状如箱子而得名。它是利用数据中的五个统计量&#xff1a;最小值、上四分位数、中位数、下四分位数与最大值来描述数据的一种统计图。 箱形图…

【MySQL入门到精通-黑马程序员】MySQL基础篇-函数

文章目录 前言一、字符串函数二、数值函数三、日期函数四、流程控制函数总结 前言 本专栏文章为观看黑马程序员《MySQL入门到精通》所做笔记&#xff0c;课程地址在这。如有侵权&#xff0c;立即删除。 函数 是指一段可以直接被另一段程序调用的程序或代码。 一、字符串函数 格…

C# AnimeGANv2 人像动漫化

效果 项目 下载 可执行程序exe下载 源码下载 其他 C# 人像卡通化 Onnx photo2cartoon-CSDN博客 C# AnimeGAN 漫画风格迁移 动漫风格迁移 图像卡通化 图像动漫化_天天代码码天天的博客-CSDN博客

复数的三角形式与指数形式

See https://blog.csdn.net/u011089570/article/details/102685877

C++ wpf自制软件打包安装更新源码实例

程序示例精选 C wpf自制软件打包安装更新源码实例 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《C wpf自制软件打包安装更新源码实例》编写代码&#xff0c;代码整洁&#xff0c;规则&…

JAVA设计模式-工厂模式(Factory Pattern)

一.概念 我们在创建对象时不会对客户端直接暴露创建逻辑&#xff0c;而是 通过使用一个共同的接口根据不同的条件来指向具体想要创建的对象。 二.工厂模式优点 1.解耦 &#xff1a;把对象的创建和使用的过程分开 2.降低代码重复&#xff1a; 如果创建某个对象的过程都很复杂…

HTML基础入门02

目录 1.格式化标签 2.图片标签: img 3.超链接标签: a 4.综合案例: 展示博客2 5.表格标签 5.1基本使用 5.2合并单元格 6.列表标签 1.格式化标签 加粗&#xff1a;strong标签和b标签 倾斜&#xff1a;em标签和i标签 删除线&#xff1a;del标签和s标签 下划线&#xff1a;i…

结构体,位段!

目录 1.什么是位段&#xff1f; 别急&#xff01;在下面第二点我和大家介绍。 2.位段的内存怎么分配&#xff1f; 还有一种情况就是两种类型夹杂在一起的位段 3.位段的跨平台问题 4.位段能干嘛&#xff1f;&#xff08;应用&#xff09; 5.位段的注意事项 1.什么是位段&…

MySQL 进阶笔记

&#x1f600;&#x1f600;&#x1f600;创作不易&#xff0c;各位看官点赞收藏&#xff0c;在这里隆重感谢尚硅谷宋红康老师。&#xff0c; 文章目录 MySQL 进阶笔记1、Centos 环境安装 MySQL2、MySQL常用设置2.1、字符集设置2.2、SQL 大小写2.3、sql_mode 模式2.4、MySQL 数…

【OJ比赛日历】快周末了,不来一场比赛吗? #10.14-10.20 #13场

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 2023-10-14&#xff08;周六&#xff09; #7场比赛2023-10-15…

分析Python爬虫设计

抖音作为一款火爆的短视频平台&#xff0c;每天都会产生大量的热传视频。想要了解这些热门内容背后的秘密吗&#xff1f;那么&#xff0c;你来对地方了&#xff01;在本文中&#xff0c;我将与大家分享一个用Python设计的抖音视频热传内容分析爬虫。通过这个爬虫&#xff0c;你…

MS9708数模转换器可pin对pin兼容AD9708

MS9708/MS9710/MS9714 是一个 8-Bit/10-Bit/14-Bit 高速、低功耗 D/A 转换器。可pin对pin兼容AD9708。当采样速率达到 125MSPS 时&#xff0c;MS9708/MS9710/MS9714 也能提供优越的 AC 和 DC 性能。 MS9708/MS9710/MS9714 正常工作电压范围为2.7V ~ 5.5V&#xff0c;功耗低能很…

接口测试项目实战,充值接口+取现接口,资深测试带你一文打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、充值接口 首先…

代理IP在保护跨境商家网络安全中的重要作用

在当前全球化的背景下&#xff0c;跨境电商成为一种重要的商业模式&#xff0c;越来越多的商家涌入国际市场&#xff0c;商家们通过互联网平台将商品远销国外&#xff0c;但网络安全风险随之而来。跨境商家因为需要处理大量的在线交易和产品数据&#xff0c;如果未能对这些敏感…

Spark中的Driver、Executor、Stage、TaskSet、DAGScheduler等介绍

工作流程&#xff1a; Driver 创建 SparkSession 并将应用程序转化为执行计划&#xff0c;将作业划分为多个 Stage&#xff0c;并创建相应的 TaskSet。Driver 将 TaskSet 发送给 TaskScheduler 进行调度和执行。TaskScheduler 根据资源情况将任务分发给可用的 Executor 进程执…

KubeVela跨地域的多集群管理方案

随着公司全球化战略的布局,业务呈点状分布在亚太、美东、欧洲等多个地域,云原生kubevela在跨地域多集群管控方面也遇到网络上的互通问题。 在公司网络规划上只允许一个区域的一个VPC跟另一个区域的一个VPC打通,同区域不同机房的网络都可以打通的网络架构基础上,由于一个区…

深度学习系列51:hugging face加速库optimum

1. 普通模型 Optimum是huggingface transformers库的一个扩展包&#xff0c;用来提升模型在指定硬件上的训练和推理性能。Optimum支持多种硬件&#xff0c;不同硬件下的安卓方式如下&#xff1a; 如果是国内安装的话&#xff0c;记得加上-i https://pypi.tuna.tsinghua.edu.c…

五笔字根查询接口,五笔输入法数据

一、接口介绍 可对五笔字根口诀及五笔编码查询,希望能为您学习五笔输入法提供帮助。 二、功能体验 三、产品特点 四、API文档 4.1 五笔字根查询查询 4.1.1接入点说明 查询五笔字根。 4.1.2接口地址 http[s]://route.showapi.com/1861-1?showapi_appid替换自己的值&…

基于springboot实现校园博客系统项目【项目源码+论文说明】

基于springboot实现校园博客系统演示 摘要 随着现在网络的快速发展&#xff0c;网上管理系统也逐渐快速发展起来&#xff0c;网上管理模式很快融入到了许多网站的之中&#xff0c;随之就产生了“校园博客系统”&#xff0c;这样就让校园博客系统更加方便简单。 对于本校园博客…

linux中使用ps查看进程的所有线程

在 Linux 系统中&#xff0c;可以使用 ps 命令和 ps H 命令结合来查看进程的线程信息。ps 命令用于显示系统中当前运行的进程信息&#xff0c;而 ps H 命令则可以显示进程中的所有线程。 使用以下命令可以查看指定进程的所有线程信息&#xff1a; ps H -T <PID>将 替换…