Qt 实现自定义截图工具

🏷️ 约彩365ios下载 📅 2025-10-01 15:30:56 👤 admin 👁️ 6251 ❤️ 611
Qt 实现自定义截图工具

目录

Qt 实现自定义截图工具实现效果图PrintScreen 类介绍PrintScreen 类的主要特性

逐步实现第一步:类定义第二步:初始化截图窗口第三步:处理鼠标事件第四步:计算截图区域第五步:捕获和保存图像

完整代码PrintScreen.hPrintScreen.cppMainWindow.hMainWindow.cppmain.cpp

Qt 实现自定义截图工具

本文使用Qt框架从头开始创建一个简单的屏幕截图工具。

实现效果图

截图按钮: 选取截图初始状态: 选取截图区域: 截图保存界面:

PrintScreen 类介绍

PrintScreen 类是一个自定义的 QWidget,允许用户捕捉屏幕上的任意区域。本教程将展示如何利用 Qt 的多功能库来实现这一功能。

PrintScreen 类的主要特性

全屏覆盖,用于选择要捕捉的屏幕区域。通过鼠标互动选择定义捕捉区域。拖放调整选定区域。将捕获的区域保存为图片文件。

逐步实现

第一步:类定义

首先定义继承自 QWidget 的 PrintScreen 类。包含必要的 Qt 头文件,并声明我们的函数和成员变量。

#include

#include

/**

* @brief The PrintScreen class

* @param 区域截屏功能

*/

class PrintScreen : public QWidget

{

Q_OBJECT

public:

PrintScreen(QWidget *parent = nullptr);

~PrintScreen();

private:

/**

* @brief 初始化截图窗口的背景和尺寸

*/

void InitWindow();

/**

* @brief 根据起始点和终止点计算矩形区域

* @param beginPoint 矩形区域的起始点

* @param endPoint 矩形区域的终止点

* @return 返回根据两点计算出的 QRect 对象

*/

QRect GetRect(const QPoint &beginPoint, const QPoint &endPoint);

protected:

// 事件处理方法

void mousePressEvent(QMouseEvent *event);

void mouseMoveEvent(QMouseEvent* event);

void mouseReleaseEvent(QMouseEvent *event);

void keyPressEvent(QKeyEvent *event);

void paintEvent(QPaintEvent *event);

private:

// 成员变量

bool m_isMousePress = false; // 是否按下鼠标

bool m_captureComplete = false; // 截图是否完成

bool m_isDragging = false; // 是否正在拖动截图区域

QPixmap m_loadPixmap; // 加载的屏幕截图

QPixmap m_capturePixmap; // 截取的屏幕区域

int m_screenWidth; // 屏幕宽度

int m_screenHeight; // 屏幕高度

QPoint m_beginPoint; // 截图开始点

QPoint m_endPoint; // 截图结束点

QPoint m_originalBegin; // 原始截图开始点

QPoint m_originalEnd; // 原始截图结束点

QPoint m_dragPosition; // 拖动时的鼠标位置

QPainter m_painter; // 绘图器对象

};

第二步:初始化截图窗口

InitWindow 方法设置窗口属性,如全屏模式、无边框窗口提示和鼠标跟踪。它还捕获整个屏幕并存储在 m_loadPixmap 中。

void PrintScreen::InitWindow()

{

// 启用鼠标跟踪

this->setMouseTracking(true);

// 设置无边框窗口

this->setWindowFlags(Qt::FramelessWindowHint);

// 设置窗口为激活状态和全屏模式

setWindowState(Qt::WindowActive | Qt::WindowFullScreen);

// 确保关闭时自动删除

setAttribute(Qt::WA_DeleteOnClose);

// 获取主屏幕

QScreen *screen = QApplication::primaryScreen();

// 抓取整个屏幕内容

m_loadPixmap = screen->grabWindow(QApplication::desktop()->winId());

// 设置屏幕宽度、高度

m_screenWidth = m_loadPixmap.width();

m_screenHeight = m_loadPixmap.height();

}

第三步:处理鼠标事件

鼠标事件对于定义捕获区域至关重要。mousePressEvent、mouseMoveEvent 和 mouseReleaseEvent 处理捕获区域的开始、调整和最终确定。

void PrintScreen::mousePressEvent(QMouseEvent *event)

{

// 按下右键 关闭截图窗口

if (event->button() == Qt::RightButton)

{

close();

}

// 按下左键

else if (event->button() == Qt::LeftButton)

{

if (m_captureComplete && QRect(m_beginPoint, m_endPoint).contains(event->pos()))

{

m_isDragging = true; // 开始拖动

m_dragPosition = event->pos() - m_beginPoint; // 计算开始拖动位置

}

else

{

m_isMousePress = true; // 鼠标被按下

m_isDragging = false;

m_beginPoint = event->pos(); // 记录开始点

m_originalBegin = m_beginPoint;

}

}

}

void PrintScreen::mouseMoveEvent(QMouseEvent *event)

{

// 获取屏幕尺寸

QRect screenRect = QGuiApplication::primaryScreen()->geometry();

// 鼠标按下且截图未完成

if (m_isMousePress && !m_captureComplete)

{

// 确保终点坐标不超过屏幕范围

int x = qBound(screenRect.left(), event->pos().x(), screenRect.right());

int y = qBound(screenRect.top(), event->pos().y(), screenRect.bottom());

m_endPoint = QPoint(x, y);

}

// 正在拖动

else if (m_isDragging)

{

QPoint newTopLeft = event->pos() - m_dragPosition;

// 确保新的顶点坐标不超过屏幕范围

int x = qBound(screenRect.left(), newTopLeft.x(), screenRect.right() - m_dragPosition.x());

int y = qBound(screenRect.top(), newTopLeft.y(), screenRect.bottom() - m_dragPosition.y());

newTopLeft = QPoint(x, y);

QPoint offset = newTopLeft - m_beginPoint;

m_beginPoint += offset;

m_endPoint += offset;

}

update();

return QWidget::mouseMoveEvent(event);

}

void PrintScreen::mouseReleaseEvent(QMouseEvent *event)

{

// 鼠标释放且截图未完成

if (m_isMousePress && !m_captureComplete)

{

m_endPoint = event->pos(); // 设置结束点

m_isMousePress = false; // 重置鼠标按下状态

m_captureComplete = true; // 标记截图完成

update();

}

// 释放时正在拖动

else if (m_isDragging)

{

m_isDragging = false;

}

update();

}

第四步:计算截图区域

GetRect 方法接收两个参数:beginPoint 和 endPoint,这两个点是用户通过鼠标操作定义的截图区域的开始和结束位置。此方法用于计算并返回一个 QRect 对象,该对象表示屏幕上要截取的矩形区域。

QRect PrintScreen::GetRect(const QPoint &beginPoint, const QPoint &endPoint)

{

int x = std::min(beginPoint.x(), endPoint.x());

int y = std::min(beginPoint.y(), endPoint.y());

int width = std::abs(beginPoint.x() - endPoint.x());

int height = std::abs(beginPoint.y() - endPoint.y());

if (width == 0) width = 1; // 确保宽度至少为1像素

if (height == 0) height = 1; // 确保高度至少为1像素

return QRect(x, y, width, height);

}

解释:

计算 x 和 y 坐标:使用 std::min 函数确定矩形的左上角 x 和 y 坐标,这保证了无论用户如何拖动鼠标(从左到右或从右到左),都能正确计算出矩形的位置。计算宽度和高度:使用 std::abs 函数计算宽度和高度,确保值总是正数。如果计算结果为0(即起点和终点在同一直线上),则将宽度或高度设为1像素,确保矩形至少有最小的可见尺寸。

第五步:捕获和保存图像

paintEvent 方法在屏幕上绘制捕获的区域。keyPressEvent 监听回车键以触发保存捕获的图像。

void PrintScreen::paintEvent(QPaintEvent *event)

{

Q_UNUSED(event)

m_painter.begin(this); // 开始绘制

QColor shadowColor(0, 0, 0, 100); // 半透明遮罩颜色

m_painter.setPen(QPen(Qt::blue, 1, Qt::SolidLine, Qt::FlatCap)); // 设置画笔

m_painter.drawPixmap(0, 0, m_loadPixmap); // 绘制加载的屏幕截图

m_painter.fillRect(m_loadPixmap.rect(), shadowColor); // 绘制半透明遮罩

QRect selectedRect = GetRect(m_beginPoint, m_endPoint); // 获取选择区域

m_capturePixmap = m_loadPixmap.copy(selectedRect); // 截取选择区域的屏幕截图

m_painter.drawPixmap(selectedRect.topLeft(), m_capturePixmap); // 绘制截取的区域

m_painter.drawRect(selectedRect); // 绘制选择区域的边框

m_painter.end(); // 结束绘制

}

void PrintScreen::keyPressEvent(QKeyEvent *event)

{

// 按下回车键

if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)

{

// 保存图片

QString filePath = QFileDialog::getSaveFileName(nullptr, "保存图片",QString(),"Images (*.png *.jpg)");

if(!filePath.isEmpty())

{

m_capturePixmap.save(filePath); // 保存截图到文件

}

close();

}

}

完整代码

PrintScreen.h

#ifndef PRINTSCREEN_H

#define PRINTSCREEN_H

#include

#include

/**

* @brief The PrintScreen class

* @param 区域截屏功能

*/

class PrintScreen : public QWidget

{

Q_OBJECT

public:

PrintScreen(QWidget *parent = nullptr);

~PrintScreen();

private:

/**

* @brief 初始化截图窗口的背景和尺寸

*/

void InitWindow();

/**

* @brief 根据起始点和终止点计算矩形区域

* @param beginPoint 矩形区域的起始点

* @param endPoint 矩形区域的终止点

* @return 返回根据两点计算出的 QRect 对象

*/

QRect GetRect(const QPoint &beginPoint, const QPoint &endPoint);

protected:

// 事件处理方法

void mousePressEvent(QMouseEvent *event);

void mouseMoveEvent(QMouseEvent* event);

void mouseReleaseEvent(QMouseEvent *event);

void keyPressEvent(QKeyEvent *event);

void paintEvent(QPaintEvent *event);

private:

// 成员变量

bool m_isMousePress = false; // 是否按下鼠标

bool m_captureComplete = false; // 截图是否完成

bool m_isDragging = false; // 是否正在拖动截图区域

QPixmap m_loadPixmap; // 加载的屏幕截图

QPixmap m_capturePixmap; // 截取的屏幕区域

int m_screenWidth; // 屏幕宽度

int m_screenHeight; // 屏幕高度

QPoint m_beginPoint; // 截图开始点

QPoint m_endPoint; // 截图结束点

QPoint m_originalBegin; // 原始截图开始点

QPoint m_originalEnd; // 原始截图结束点

QPoint m_dragPosition; // 拖动时的鼠标位置

QPainter m_painter; // 绘图器对象

};

#endif // PRINTSCREEN_H

PrintScreen.cpp

#include "PrintScreen.h"

#include

#include

#include

#include

#include

PrintScreen::PrintScreen(QWidget *parent)

: QWidget{parent}

{

InitWindow();

}

PrintScreen::~PrintScreen(){}

void PrintScreen::InitWindow()

{

// 启用鼠标跟踪

this->setMouseTracking(true);

// 设置无边框窗口

this->setWindowFlags(Qt::FramelessWindowHint);

// 设置窗口为激活状态和全屏模式

setWindowState(Qt::WindowActive | Qt::WindowFullScreen);

// 确保关闭时自动删除

setAttribute(Qt::WA_DeleteOnClose);

// 获取主屏幕

QScreen *screen = QApplication::primaryScreen();

// 抓取整个屏幕内容

m_loadPixmap = screen->grabWindow(QApplication::desktop()->winId());

// 设置屏幕宽度、高度

m_screenWidth = m_loadPixmap.width();

m_screenHeight = m_loadPixmap.height();

}

QRect PrintScreen::GetRect(const QPoint &beginPoint, const QPoint &endPoint)

{

int x = std::min(beginPoint.x(), endPoint.x());

int y = std::min(beginPoint.y(), endPoint.y());

int width = std::abs(beginPoint.x() - endPoint.x());

int height = std::abs(beginPoint.y() - endPoint.y());

if (width == 0) width = 1; // 确保宽度至少为1像素

if (height == 0) height = 1; // 确保高度至少为1像素

return QRect(x, y, width, height);

}

void PrintScreen::mousePressEvent(QMouseEvent *event)

{

// 按下右键 关闭截图窗口

if (event->button() == Qt::RightButton)

{

close();

}

// 按下左键

else if (event->button() == Qt::LeftButton)

{

if (m_captureComplete && QRect(m_beginPoint, m_endPoint).contains(event->pos()))

{

m_isDragging = true; // 开始拖动

m_dragPosition = event->pos() - m_beginPoint; // 计算开始拖动位置

}

else

{

m_isMousePress = true; // 鼠标被按下

m_isDragging = false;

m_beginPoint = event->pos(); // 记录开始点

m_originalBegin = m_beginPoint;

}

}

}

void PrintScreen::mouseMoveEvent(QMouseEvent *event)

{

// 获取屏幕尺寸

QRect screenRect = QGuiApplication::primaryScreen()->geometry();

// 鼠标按下且截图未完成

if (m_isMousePress && !m_captureComplete)

{

// 确保终点坐标不超过屏幕范围

int x = qBound(screenRect.left(), event->pos().x(), screenRect.right());

int y = qBound(screenRect.top(), event->pos().y(), screenRect.bottom());

m_endPoint = QPoint(x, y);

}

// 正在拖动

else if (m_isDragging)

{

QPoint newTopLeft = event->pos() - m_dragPosition;

// 确保新的顶点坐标不超过屏幕范围

int x = qBound(screenRect.left(), newTopLeft.x(), screenRect.right() - m_dragPosition.x());

int y = qBound(screenRect.top(), newTopLeft.y(), screenRect.bottom() - m_dragPosition.y());

newTopLeft = QPoint(x, y);

QPoint offset = newTopLeft - m_beginPoint;

m_beginPoint += offset;

m_endPoint += offset;

}

update();

return QWidget::mouseMoveEvent(event);

}

void PrintScreen::mouseReleaseEvent(QMouseEvent *event)

{

// 鼠标释放且截图未完成

if (m_isMousePress && !m_captureComplete)

{

m_endPoint = event->pos(); // 设置结束点

m_isMousePress = false; // 重置鼠标按下状态

m_captureComplete = true; // 标记截图完成

update();

}

// 释放时正在拖动

else if (m_isDragging)

{

m_isDragging = false;

}

update();

}

void PrintScreen::keyPressEvent(QKeyEvent *event)

{

// 按下回车键

if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)

{

// 保存图片

QString filePath = QFileDialog::getSaveFileName(nullptr, "保存图片",QString(),"Images (*.png *.jpg)");

if(!filePath.isEmpty())

{

m_capturePixmap.save(filePath); // 保存截图到文件

}

close();

}

}

void PrintScreen::paintEvent(QPaintEvent *event)

{

Q_UNUSED(event)

m_painter.begin(this); // 开始绘制

QColor shadowColor(0, 0, 0, 100); // 半透明遮罩颜色

m_painter.setPen(QPen(Qt::blue, 1, Qt::SolidLine, Qt::FlatCap)); // 设置画笔

m_painter.drawPixmap(0, 0, m_loadPixmap); // 绘制加载的屏幕截图

m_painter.fillRect(m_loadPixmap.rect(), shadowColor); // 绘制半透明遮罩

QRect selectedRect = GetRect(m_beginPoint, m_endPoint); // 获取选择区域

m_capturePixmap = m_loadPixmap.copy(selectedRect); // 截取选择区域的屏幕截图

m_painter.drawPixmap(selectedRect.topLeft(), m_capturePixmap); // 绘制截取的区域

m_painter.drawRect(selectedRect); // 绘制选择区域的边框

m_painter.end(); // 结束绘制

}

MainWindow.h

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include

#include

#include "PrintScreen.h"

class MainWindow : public QMainWindow

{

Q_OBJECT

public:

MainWindow(QWidget *parent = nullptr);

~MainWindow();

private:

QPushButton *m_screenBtn;

PrintScreen *m_printScree;

// QObject interface

public:

bool eventFilter(QObject *watched, QEvent *event);

};

#endif // MAINWINDOW_H

MainWindow.cpp

#include "MainWindow.h"

#include

#include

MainWindow::MainWindow(QWidget *parent)

: QMainWindow(parent)

, m_screenBtn(new QPushButton("截图", this))

{

// 设置中心窗口

setCentralWidget(m_screenBtn);

// 安装事件过滤器

m_screenBtn->installEventFilter(this);

// 隐藏标题栏

setWindowFlags(Qt::FramelessWindowHint);

resize(150, 50);

}

MainWindow::~MainWindow() {}

bool MainWindow::eventFilter(QObject *watched, QEvent *event)

{

if (watched == m_screenBtn && event->type() == QEvent::MouseButtonPress)

{

QMouseEvent *mouseEvent = static_cast(event);

if (mouseEvent->button() == Qt::RightButton)

{

close();

return true;

}

else if (mouseEvent->button() == Qt::LeftButton)

{

m_printScree = new PrintScreen();

m_printScree->show();

return true;

}

}

return QMainWindow::eventFilter(watched, event);

}

main.cpp

#include "MainWindow.h"

#include

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

MainWindow w;

w.show();

return a.exec();

}

相关内容

淘宝推广大师
wwwBet365

淘宝推广大师

📅 07-03 👁️ 3030
中产合格标准曝光:4种家庭才达标,全国3300万户有你吗
App Store预览
365直播网网络电视台

App Store预览

📅 08-24 👁️ 8818