目录
mousePressEvent(QMouseEvent *event)
mouseMoveEvent(QMouseEvent *event)
mouseReleaseEvent(QMouseEvent *event)
paintEvent(QPaintEvent *event)
文章最下方有源码获取方式哦~
前言
最近在完善简易QQ项目的过程中,我在基本布局的基础上添加了一些新功能,其中截图功能是首要实现的功能之一。鉴于网上缺乏现成的开源截图软件,我决定自己开发,并在此分享我的源码。初期的实现较为简单,仅涵盖了截图的基本功能。未来若有时间,我会继续对其进行优化和扩展。接下来,直接进入正题。
主要使用的Qt库
- QWidget: 作为所有用户界面对象的基础类。
- QLabel: 用于显示文本或图像,这里用来展示截取的屏幕快照。
- QPushButton: 创建按钮,如确认、取消和保存按钮。
- QVBoxLayout 和 QHBoxLayout: 用于布局管理,组织窗口内的小部件。
- QMouseEvent: 处理鼠标事件(按下、移动、释放)。
- QFileDialog: 提供一个对话框让用户选择文件来保存截图。
- QPainter: 用于绘制图形和文本,这里用来绘制截图和选择区域。
- QPixmap: 用于表示和操作像素图,存储截图内容。
- QRegion: 用于定义和操作不规则形状的区域,用以创建遮罩效果。
- QScreen: 获取屏幕信息,并能够抓取整个屏幕的内容。
- QColor, QPen, QBrush: 分别用于定义颜色、设置画笔属性和填充形状的颜色或图案,用于绘制选择矩形的边框和阴影区域的颜色。
- Qt::Alignment 和其他 Qt::命名空间下的枚举:用于指定对齐方式和其他UI属性。
- QRect 和 QPoint: 用于几何计算,比如确定鼠标点击的位置和选择区域的大小。
- QtConcurrent::run: 用于异步执行函数,这里是异步保存文件,避免阻塞主线程。
业务逻辑层 (Business Logic Layer)
- takeScreenshot() 方法:使用
QScreen::grabWindow()
抓取屏幕快照,并将结果存储在screenshot
成员变量中。 - mousePressEvent(), mouseMoveEvent(), 和 mouseReleaseEvent():处理用户的鼠标交互,允许用户选择截图区域。
- paintEvent():负责重绘窗口,包括显示截图、绘制选择矩形和遮罩效果。
- updateButtonPositions():根据选择区域的位置动态调整按钮的位置,确保它们不会被遮挡并且始终可见。
- onConfirmButtonClicked(), onCancelButtonClicked(), 和 onSaveButtonClicked():分别处理确认、取消和保存截图的操作。保存操作通过
QtConcurrent::run
异步执行,以保持界面响应性。
思路描述
Qt 简单截图工具(一) 高仿QQ截屏 滑动截屏_qt qml 仿qq截图-CSDN博客
受到一篇CSDN博客文章的影响,我纠正了最初的错误思路。最初我计划将屏幕截图放置在一个 QLabel 上,然后尝试用 QPainter 进行截图操作,但发现 QLabel 是一个控件,不能直接在其上绘画。最终,我选择直接在 QPixmap 上进行操作,这使得问题得到了解决。
阴影与遮罩思路
-
screenshotPixmap 用于保存缩放后的屏幕截图。它首先被填充为透明色(
Qt::transparent
),然后使用 QPainter 将原始截图按照窗口大小进行缩放并绘制到这个 QPixmap 上。这样做是为了确保截图能够适配当前窗口的尺寸,同时保持原有的宽高比,并使用平滑变换来提高图像质量。 -
shadowPixmap 专门用于创建阴影效果或遮罩区域。它同样初始化为透明色,然后根据用户选择的矩形区域来绘制半透明的阴影。在 paintEvent() 方法中,当用户正在绘制选择矩形时,程序会计算出一个非选择区域(即除了用户选择的矩形之外的所有区域),并将这部分区域用半透明的颜色(如黑色,带有一些透明度)填充,以达到视觉上的“阴影”效果。如果没有选择矩形或者选择矩形为空,则整个窗口会被绘制上阴影,表示没有选中的区域。
-
在 paintEvent() 的最后,程序依次绘制 screenshotPixmap 和 shadowPixmap 到窗口上。先绘制 screenshotPixmap 展示截图内容,再绘制 shadowPixmap 显示阴影效果。如果用户正在绘制选择矩形,还会在最顶层绘制一个绿色边框的矩形,以清晰地标记出用户选择的区域。
关键点
- screenshotPixmap 专注于展示经过缩放处理后的屏幕截图。
- shadowPixmap 专注于创建遮罩效果,突出显示用户选择的区域。
绘制顺序为先绘制 screenshotPixmap,再绘制 shadowPixmap,最后如果有必要,绘制选择矩形的边框。shadowPixmap 使用半透明颜色来创建阴影效果,而不是完全不透明的颜色,这样可以保留背景图像的可见性,同时提供视觉上的区分。
程序运行后屏幕不会有任何改变。
截图时效果图:
关键函数讲解:
takeScreenshot()
这个方法用于获取屏幕的快照。它使用了QScreen::grabWindow()
方法来抓取整个屏幕(通过传递0作为窗口句柄参数),并将结果存储在成员变量screenshot
中。这为后续绘制和剪裁提供了基础图像。
void ScreenshotWidget::takeScreenshot()
{
QScreen *screen = QApplication::primaryScreen();
if (screen) {
screenshot = screen->grabWindow(0);
}
}
mousePressEvent(QMouseEvent *event)
当用户按下鼠标按钮时触发此事件处理器。在这里,我们检查是否是左键被按下,并初始化一个矩形选择操作。如果条件满足,我们将开始位置设置为当前鼠标位置,并将isDrawing
标志设为true
,以表示用户正在绘制选择区域。
void ScreenshotWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
qDebug() << "Mouse pressed at" << event->pos();
isDrawing = true;
startPos = event->pos();
endPos = startPos;
update();
}
}
mouseMoveEvent(QMouseEvent *event)
每当鼠标移动且左键被按住时,都会调用此事件处理器。它更新结束位置,并重新绘制窗口以反映新的选择区域。
void ScreenshotWidget::mouseMoveEvent(QMouseEvent *event)
{
if (isDrawing && (event->buttons() & Qt::LeftButton)) {
qDebug() << "Mouse moved to" << event->pos();
endPos = event->pos();
update();
}
}
mouseReleaseEvent(QMouseEvent *event)
当用户释放鼠标左键时触发。这里计算并规范化最终的选择矩形,并更新按钮的位置使其出现在选择区域下方。同时也会重新绘制窗口以显示最终的选择。
void ScreenshotWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && isDrawing) {
qDebug() << "Mouse released at" << event->pos();
endPos = event->pos();
selectionRect = QRect(startPos, endPos).normalized();
update();
updateButtonPositions();
}
}
paintEvent(QPaintEvent *event)
这是自定义绘图的关键所在。在这个函数中,我们创建了一个与窗口大小相同的QPixmap
,然后在其上绘制缩放后的截图。接着,我们根据是否正在绘制选择矩形来决定是否应用遮罩效果,并绘制出绿色边框的选择矩形。
void ScreenshotWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// 绘制截图
// ...
if (isDrawing) {
// 应用遮罩效果
// ...
// 绘制选择矩形
if (!selectRect.isEmpty()) {
QPen pen(Qt::green, 3);
pen.setStyle(Qt::SolidLine);
painter.setPen(pen);
painter.drawRect(selectRect);
}
}
}
onConfirmButtonClicked()
当用户点击确认按钮时,该槽函数会被调用。它会复制选中的截图部分,并携带图像发出screenshotCaptured
信号,方便其他组件获取此图片。之后,它隐藏所有按钮,重置状态,并关闭窗口。
void ScreenshotWidget::onConfirmButtonClicked()
{
QRect rect = QRect(startPos, endPos).normalized();
if (!rect.isEmpty()) {
QPixmap croppedPixmap = screenshot.copy(rect);
emit screenshotCaptured(croppedPixmap);
confirmButton->hide();
cancelButton->hide();
saveButton->hide();
isDrawing = false;
update();
this->close();
}
}
onSaveButtonClicked()
当用户点击保存按钮时,这个槽函数负责打开文件对话框让用户选择保存路径和格式,然后异步地将截图保存到磁盘。完成后,同样会隐藏按钮、重置状态并关闭窗口。
void ScreenshotWidget::onSaveButtonClicked()
{
QRect rect = QRect(startPos, endPos).normalized();
if (!rect.isEmpty()) {
QPixmap croppedPixmap = screenshot.copy(rect);
QString filePath = QFileDialog::getSaveFileName(
this,
tr("Save Screenshot"),
"untitled.png",
tr("PNG Files (*.png);;JPEG Files (*.jpg *.jpeg);;All Files (*)")
);
if (!filePath.isEmpty()) {
// 使用 QtConcurrent::run 异步保存文件
QtConcurrent::run([=]() {
croppedPixmap.save(filePath);
qDebug() << "Screenshot saved to" << filePath;
});
// 隐藏按钮
confirmButton->hide();
cancelButton->hide();
saveButton->hide();
isDrawing = false;
update();
this->close();
}
}
}
源码已经给小伙伴们整理好了,微信搜索 嵌入式工程之家 关注公众号回复 截图 即可获得源码和详细操作指示哦~