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


    前言

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

    widget.h文件

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    widget.cpp文件

    #include "widget.h"
    #include "ui_widget.h"
    #include "fullscreenwindow.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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, "警告", "当前没有截图可保存");
               }
           }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127

    fullscreenwindow.h文件

    #ifndef FULLSCREENWINDOW_H
    #define FULLSCREENWINDOW_H
    
    #include 
    #include 
    #include 
    #include 
    
    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    fullscreenwindow.cpp文件

    #include "fullscreenwindow.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    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();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
  • 相关阅读:
    kubernetes集群kubeadm方式安装
    【Python】模拟windows文件名排序
    PHP GC回收机制详解
    Element--生成不定列的表格
    el-table表格变更前后根据数据值改变背景颜色
    使用Python自动发送邮件
    基于ssm框架的(非maven)学生选课管理系统
    Spring Boot 中使用 Poi-tl 渲染数据并生成 Word 文档
    毕设 连锁酒店
    矢量场的旋度和散度
  • 原文地址:https://blog.csdn.net/qq_51214753/article/details/133818286