前言
目前实现了高仿微信的截屏工具,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();
}