一、前言
qt实现截屏功能,基于自己做的自定义面板程序,自定义面板是根据个人需求专属定制,提醒自己用了多久电脑,什么时候该休息一会了,有一些辅助工具,截屏,用到什么控件了也可参考历史的控件,这样就算没联网没有登录qq和微信也可实现截屏功能。
二、环境
qt5.7mingw
windows8
三、正文
首先上一下效果图
正文正式开始,实现这个截图功能看视乎简单,实际还是涉及到挺多问题的
1.首先截屏不可能是在写的程序聚焦情况下执行,必须支持程序在后台,随时按下快捷键即可截屏,这就需要实现全局快捷按键获取了。
2.截屏时得有效果,否者不清楚截屏的位置是在哪里,这样自己看不方便,别人更是看不明白了,所以需要实现全局遮罩,就是截屏时的灰色背景。
3.有了遮罩还得实现截屏区域的显示,否则也不是很明确具体截屏在哪里,这就需要用到mouseevent和paintevent这两个函数组合使用了。
*实现了以上三点,才能达到截屏刚刚够看,否则真的是一塌糊涂,和qq微信自带的ctrl+alt+a 和alt+a比起来,着实差远了,但是我把它放在我的自定义控件面板中,在电脑单机工作时,或者没有上qq微信时也可以实现截屏功能。
正文真正的开始了:
首先是实现全局按键函数,这里我一开始是用一个钩子函数的单独按键获取,但是只能获取到一个键值,所以在GitHub上面查到了一个dalao写的pri库,于是就调用了,发现有一些问题,还不是很完美。
dalao的库我也放在本资源下载链接里了,还有我写的截屏功能代码都在里面, 有需要的可以下载。
添加上如下的pri即可
include(D:/QT57/workspace/My/MyCustomWidget/CustomWidget/QHotkey-master/qhotkey.pri)
头文件包含#include <QHotkey>
mainwindow.cpp包含
//qhotkey.pri引用于GitHub,实现在widget以外获取全局键盘函数
QHotkey *hotkey=new QHotkey(QKeySequence("Ctrl+Shift+A"),true);
//QHotkey *hotkey=new QHotkey(Qt::Key_L,Qt::ControlModifier,true);
//连接热键被按下的信号与槽
QObject::connect(hotkey,&QHotkey::activated,[=](){
//热键被按下的处理代码段
qDebug()<<"QString::number(key)";
qApp->beep();//蹦的一声
basewidget->setGeometry(0, 0,1920,1080);//遮罩窗口位置
});
我是用的ctrl+shift+a实现截屏,也可自行更改快捷键
他这里有一个bug就是在connect内不能执行QMessageBox或者其他的打开界面函数,这一切异常都是在我的窗口呗隐藏时发送的,窗口不隐藏怎么使用也没有问题,但是那就失去了他在后台可执行的意义,所以我将里面的遮罩背景一直显示出来,不用的时候放在0,0位置,1,1像素,用的是后在满屏显示遮罩。
其次就是遮罩的实现了,这里遮罩实现需要新建一个ui界面,或者也可以新建一个类不建立ui界面都可以。
我的遮罩代码也放在本博的资源内了,可以下载参考,核心代码都在里面。
在mainwindow.h中添加
#include "shadewidget.h" Shadewidget *basewidget; //半透明遮罩
在mainwindow。cpp中
//初始化半透明遮罩
basewidget=new Shadewidget;
basewidget->setParent(this,Qt::FramelessWindowHint|Qt::Window);
basewidget->setWindowFlags(basewidget->windowFlags() | Qt::WindowStaysOnTopHint);
basewidget->setGeometry(0, 0, 1,1); //遮罩窗口位置
basewidget->show();
basewidget->raise();
//获取截屏标志
//qhotkey.pri引用于GitHub,实现在widget以外获取全局键盘函数
QHotkey *hotkey=new QHotkey(QKeySequence("Ctrl+Shift+A"),true);
//QHotkey *hotkey=new QHotkey(Qt::Key_L,Qt::ControlModifier,true);
//连接热键被按下的信号与槽
QObject::connect(hotkey,&QHotkey::activated,[=](){
//热键被按下的处理代码段
qDebug()<<"QString::number(key)";
qApp->beep();//蹦的一声
basewidget->setGeometry(0, 0,1920,1080);//遮罩窗口位置
});
下面代码有一半是上面那个,让人看懂一下吧
本段代码意思就是初始化遮罩界面和按下快捷键将遮罩界面放大到全屏显示,这里的1920.1080可以改成自动获取屏幕大小,不一定所有的屏幕全是我这个分辨率的。
在然后就是遮罩界面了。这个界面首先头文件需要引用一些包含库,还有定义
#include <QWidget>
#include <QCloseEvent>
#include <QtDebug>
#include <QApplication>
#include <QPixmap>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QClipboard>
#include <QPainter>
private slots:
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void closeEvent(QCloseEvent *event);
void paintEvent(QPaintEvent */*event*/);
private:
Ui::Shadewidget *ui;
QPixmap screen; //截屏图片
QPoint start_point;
QPoint end_point;
int x,y,w,h;
在此界面第一个重要的关键点是失能界面的强制关闭功能,否则主界面在后台时调用出来遮罩界面,遮罩界面被强制关闭时主程序就会挂掉
Shadewidget::Shadewidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Shadewidget)
{
ui->setupUi(this);
QPalette palette=this->palette();
palette.setBrush(QPalette::Background,QColor(0,0,0));
this->setPalette(palette);
this->setWindowOpacity(0.4);//设置窗口透明度
this->setWindowFlags(Qt::FramelessWindowHint|windowFlags());//去掉标题栏
}
Shadewidget::~Shadewidget()
{
delete ui;
}
void Shadewidget::closeEvent(QCloseEvent *event)
{
event->ignore();
}
在之后就是鼠标事件的配置,去获取起始坐标,鼠标移动时的坐标作为结束坐标,这两个坐标不一定谁前谁后谁高谁低,所以定义了xywh去计算出区域的起始点和长宽。
我的逻辑是在按下鼠标时候记录一个起始坐标,然后鼠标move,过程中一直记录结束坐标,然后一直有新的xywh,通过这些纸刷新paint出需要截屏的区域,鼠标抬起后再次点击是否要这个截图,点击必须在绘制出的区域内,才算是我想要这张截图,否则截图被视为无效,(新增)绘制完区域之后点击区域外面,区域被复位清空,这块是写博客时发现一个细节小问题,资源已经上传了,这里详细看帖子的人自己改一下,在鼠标释放事件上面的else里加了两行代码。
继续刚才,点击区域内保存保存该区域截图和退出截屏。
完毕!
附上代码
//实现窗口移动
void Shadewidget::mouseMoveEvent(QMouseEvent *event)
{
end_point=event->globalPos()-this->pos();//获取点击的坐标
if(end_point.x()>start_point.x()){
x=start_point.x();//比较起始坐标
w=end_point.x()-start_point.x();
}
else {
x=end_point.x();
w=start_point.x()-end_point.x();
}
if(end_point.y()>start_point.y()){
y=start_point.y();//比较起始坐标
h=end_point.y()-start_point.y();
}
else {
y=end_point.y();
h=start_point.y()-end_point.y();
}
update();
//qDebug()<<start_point<<end_point<<event->globalPos()-this->pos();//获取点击的坐标
}
//鼠标点击事件
void Shadewidget::mousePressEvent(QMouseEvent *event)
{
if(event->button()==Qt::RightButton){//右键退出截屏
this->setGeometry(0, 0, 1,1); //遮罩窗口位置
//关闭之后清空
x=y=w=h=0;
update();
}
if(event->x()>x&&event->x()<(x+w)&&event->y()>y&&event->y()<(y+h)){//画完范围确定截图
//截屏
this->setWindowOpacity(0);//设置窗口透明度
screen=QPixmap::grabWindow(QApplication::desktop()->winId(),x,y,w,h);
this->setWindowOpacity(0.4);//设置窗口透明度
//保存到粘贴板
QClipboard *pic=QApplication::clipboard();
pic->setPixmap(screen);
this->setGeometry(0, 0, 1,1); //遮罩窗口位置
//关闭之后清空
x=y=w=h=0;
update();
}
else{
x=y=w=h=0;
update();
start_point=event->globalPos()-this->pos();//获取点击的坐标
}
//qDebug()<<start_point;//获取点击的坐标
}
//鼠标释放事件
void Shadewidget::mouseReleaseEvent(QMouseEvent *event)
{
}
void Shadewidget::paintEvent(QPaintEvent */*event*/)
{
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.save();
painter.setPen(Qt::green);
QPointF topLeftPot(x, y);
QPointF bottomRightPot(x+w, y+h);//右上角
QRectF barRect = QRectF(topLeftPot, bottomRightPot);
painter.setBrush(Qt::white);
painter.drawRect(barRect);
painter.restore();
}
20240513升级功能
增加截图右键弹出菜单选项,增加截图取消快捷键ESC
初始化代码如下:
///截图
//获取截屏标志
basewidget=new Shadewidget;
basewidget->setParent(this,Qt::FramelessWindowHint|Qt::Window);
basewidget->setWindowFlags(basewidget->windowFlags() | Qt::WindowStaysOnTopHint);
basewidget->setGeometry(0, 0, 1,1); //遮罩窗口位置
basewidget->hide();
basewidget->raise();
//qhotkey.pri引用于GitHub,实现在widget以外获取全局键盘函数
QHotkey *hotkey=new QHotkey(QKeySequence("Ctrl+Shift+A"),true);
//QHotkey *hotkey=new QHotkey(Qt::Key_L,Qt::ControlModifier,true);
//连接热键被按下的信号与槽
QObject::connect(hotkey,&QHotkey::activated,[=](){
//热键被按下的处理代码段
ui->btn_menu_1->click();//执行截图功能
});
调用代码
this->hide();
qApp->beep();//蹦的一声
basewidget->show();//调用前显示,使用完毕之后在隐藏,否则按alt+tab能看到截图任务
basewidget->setGeometry(0, 0,QApplication::desktop()->width(),QApplication::desktop()->height());//遮罩窗口位置
核心代码,都在这里了,不用找下载链接了
#include "shadewidget.h"
#include "ui_shadewidget.h"
Shadewidget::Shadewidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Shadewidget)
{
ui->setupUi(this);
QPalette palette=this->palette();
palette.setBrush(QPalette::Background,QColor(0,0,0));
this->setPalette(palette);
this->setWindowOpacity(0.4);//设置窗口透明度
this->setWindowFlags(Qt::FramelessWindowHint|windowFlags());//去掉标题栏
this->setWindowTitle("screen");
menu = new QMenu(this);//创建右键菜单
menu->addAction("复制选中到粘贴板", this, [=](){copy(true);});
menu->addAction("选中图像另存为", this, [=](){save();});
menu->addAction("复制全屏到粘贴板", this, [=](){
x=0;y=0;w=QApplication::desktop()->width();h=QApplication::desktop()->height();
copy(true);
});
menu->addAction("全屏图像另存为", this, [=](){
x=0;y=0;w=QApplication::desktop()->width();h=QApplication::desktop()->height();
save();
});
menu->addAction("退出截图", this, [=](){
this->setGeometry(0, 0, 1,1); //遮罩窗口位置
x=y=w=h=0;//关闭之后清空
update();
this->hide();
});
menu->setStyleSheet("background-color: rgb(30, 30, 30, 100);color: rgb(255, 255, 255);"
"border-right:2px solid #aaaaaa; "
"border-bottom:2px solid #aaaaaa;"
"border-left:2px solid #aaaaaa;"
"border-top:2px solid #aaaaaa; "
"border-radius:5px;"
"font: 16pt ""黑体"";"
"selection-background-color: rgb(100, 40, 40);");
}
Shadewidget::~Shadewidget()
{
delete menu;
delete ui;
}
void Shadewidget::closeEvent(QCloseEvent *event)
{
event->ignore();
}
//实现窗口移动
void Shadewidget::mouseMoveEvent(QMouseEvent *event)
{
end_point=event->globalPos()-this->pos();//获取点击的坐标
if(end_point.x()>start_point.x()){
x=start_point.x();//比较起始坐标
w=end_point.x()-start_point.x();
}
else {
x=end_point.x();
w=start_point.x()-end_point.x();
}
if(end_point.y()>start_point.y()){
y=start_point.y();//比较起始坐标
h=end_point.y()-start_point.y();
}
else {
y=end_point.y();
h=start_point.y()-end_point.y();
}
update();
// qDebug()<<start_point<<end_point<<event->globalPos()-this->pos();//获取点击的坐标
}
//鼠标点击事件
void Shadewidget::mousePressEvent(QMouseEvent *event)
{
if(event->button()==Qt::RightButton){//右键弹出菜单
menu->exec(cursor().pos());//菜单显示的位置跟随鼠标
}
if(event->x()>x&&event->x()<(x+w)&&event->y()>y&&event->y()<(y+h)){//鼠标点击在 画完范围内 确定截图
copy(true);//将截图复制到粘贴板
}
else{
x=y=w=h=0;
update();
start_point=event->globalPos()-this->pos();//获取点击的坐标
}
// qDebug()<<start_point;//获取点击的坐标
}
//鼠标释放事件
void Shadewidget::mouseReleaseEvent(QMouseEvent *event)
{
}
// 键盘按下事件
void Shadewidget::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Escape){ // 是否按下Esc键
this->setGeometry(0, 0, 1,1); //遮罩窗口位置
x=y=w=h=0;//关闭之后清空
update();
this->hide();
}
else QWidget::keyPressEvent(event);
}
//绘制
void Shadewidget::paintEvent(QPaintEvent */*event*/)
{
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
painter.save();
painter.setPen(Qt::green);
QPointF topLeftPot(x, y);
QPointF bottomRightPot(x+w, y+h);//右上角
QRectF barRect = QRectF(topLeftPot, bottomRightPot);
painter.setBrush(Qt::white);
painter.drawRect(barRect);
painter.restore();
}
//将截图复制到粘贴板
void Shadewidget::copy(bool hideflag)
{
//截屏
this->setWindowOpacity(0);//设置窗口透明度
screen=QPixmap::grabWindow(QApplication::desktop()->winId(),x,y,w,h);
this->setWindowOpacity(0.4);//设置窗口透明度
//保存到粘贴板
QClipboard *pic=QApplication::clipboard();
pic->setPixmap(screen);
this->setGeometry(0, 0, 1,1); //遮罩窗口位置
//关闭之后清空
x=y=w=h=0;
update();
if(hideflag)
this->hide();
}
//截图另存为
void Shadewidget::save()
{
copy(false);//将截图复制到粘贴板
QString savename=QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)+"/截图.png";//默认路径:桌面 //默认格式:png
QString fileName = QFileDialog::getSaveFileName(this,"截图另存为",savename,"PNG (*.png);;BMP (*.bmp);;JPEG (*.jpg *.jpeg)");
if (!fileName.isEmpty()){
screen.save(fileName);
}
screen.save(fileName);
this->hide();
}
#ifndef SHADEWIDGET_H
#define SHADEWIDGET_H
#include <QWidget>
#include <QCloseEvent>
#include <QtDebug>
#include <QApplication>
#include <QPixmap>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QClipboard>
#include <QMainWindow>
#include <QMenu>//右键菜单
#include <QMouseEvent>
#include <QPainter>//画笔
#include <QDebug>
#include <QFileDialog>
#include <QShowEvent>
#include <QMessageBox>
namespace Ui {
class Shadewidget;
}
class Shadewidget : public QWidget
{
Q_OBJECT
public:
explicit Shadewidget(QWidget *parent = 0);
~Shadewidget();
private slots:
void closeEvent(QCloseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void keyPressEvent(QKeyEvent *event);
void paintEvent(QPaintEvent */*event*/);
void copy(bool hideflag);//将截图复制到粘贴板
void save();//截图另存为
private:
Ui::Shadewidget *ui;
QPixmap screen; //截屏图片
QPoint start_point;
QPoint end_point;
int x,y,w,h;
QMenu *menu;
};
#endif // SHADEWIDGET_H
最终效果图
四、结语
完毕,开心!