Qt实现截屏
来源:互联网 发布:微商拍小视频软件 编辑:程序博客网 时间:2024/05/29 15:38
转载自:http://cpp51.blog.51cto.com/5346598/1331326
软件实现拖动截屏并顶置截屏结果,将最后截图复制到剪切板。可用于数据对比或其它场合。
软件运行流程为:快捷键-》抓屏-》截图-》顶置-》复制结果。
开始时没注意内存,截屏耗费大量内存,后优化后空闲时内存使用在4M左右。
以下为代码:
#-------------------------------------------------# Ssot.pro# Project created by QtCreator 2013-11-24T11:01:06##-------------------------------------------------QT += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = SsotTEMPLATE = appSOURCES += main.cpp\ mainwindow.cpp \ ctoplabel.cpp \ aboutdialog.cppHEADERS += mainwindow.h \ ctoplabel.h \ aboutdialog.hRESOURCES += \ resource.qrcRC_FILE += \ info.rcOTHER_FILES += \ info.rc \ readme.txt
mainwindow.h
#ifndef MAINWINDOW_H#define MAINWINDOW_H#include<QtWidgets>#include<QVector>#include"aboutdialog.h"#include"ctoplabel.h"class MainWindow : public QMainWindow{ Q_OBJECTpublic: MainWindow(QWidget *parent = 0); ~MainWindow(); struct IDStruct { WId id; CTopLabel* pTopLabel; };private: //托盘图标 //注册热键 void registerGlobalKey(); //开始截图热键ID int hotkeyShotBgId; QVector<IDStruct> topLabelList; //初始化托盘; void initTray(); //是否正在截图 bool isShotting; //本地事件 bool nativeEvent(const QByteArray &eventType, void *message, long *result); AboutDialog* aboutDialog; QSystemTrayIcon* trayIcon;private slots: //开始截图 void hotkeyShotBgReceived(); void clearShots();public slots: //关闭 void clearShot(WId i); //设置isShotting为false,允许再次截屏 void allowShot(); //关于 void doAboutAction();signals: //开始截屏热键按下 void hotkeyShotBgPressed();};#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"#include<QDebug>#include"aboutdialog.h"MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){ topLabelList.clear(); isShotting=false; registerGlobalKey(); initTray(); aboutDialog =new AboutDialog; connect(this,SIGNAL(hotkeyShotBgPressed()),SLOT(hotkeyShotBgReceived())); trayIcon->showMessage(tr("截图置顶 v1.0.1"),"程序已启动,按\"Shift+Z\"后拖动鼠标!"); trayIcon->setToolTip(tr("按\"Shift+Z\"后拖动鼠标"));}MainWindow::~MainWindow(){ if(UnregisterHotKey(HWND(this->winId()), hotkeyShotBgId)) { qDebug("SHIFT+Z IS UNREGISTED"); } clearShots();}void MainWindow::registerGlobalKey(){ hotkeyShotBgId =GlobalAddAtom(L"hotkeyShotBg") - 0xC000; if(RegisterHotKey((HWND(this->winId())), hotkeyShotBgId,MOD_SHIFT,0x5A)) { qDebug("SHIFT+Z IS REGISTERED"); }}bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result){ if(eventType=="windows_generic_MSG") { //qDebug("This is windows MSG"); MSG* msg=static_cast<MSG*>(message); if(msg->message==WM_HOTKEY) { UINT fuModifiers = (UINT) LOWORD(msg->lParam); // 模式 UINT uVirtKey = (UINT) HIWORD(msg->lParam); // 键值 // qDebug("This is HotKey!"); if(fuModifiers==MOD_SHIFT&&uVirtKey==0x5A) { emit hotkeyShotBgPressed(); qDebug("SHIFT+Z is Pressed"); } return true; } } return false;}void MainWindow::hotkeyShotBgReceived(){ //如果正在截图,则不处理 if(!isShotting) { CTopLabel* fullScreenLabel=new CTopLabel; //用于传递窗口指针及WId IDStruct idStruct; idStruct.id=fullScreenLabel->winId(); idStruct.pTopLabel=fullScreenLabel; topLabelList.append(idStruct); //窗口发出关闭信号 connect(fullScreenLabel,SIGNAL(meClosed(WId)),this,SLOT(clearShot(WId))); connect(fullScreenLabel,SIGNAL(shotted()),this,SLOT(allowShot())); fullScreenLabel->showFullScreen(); } isShotting=true;}void MainWindow::initTray(){ trayIcon=new QSystemTrayIcon(this); trayIcon->setIcon(QIcon(":/icon/resource/icon.png")); QMenu* trayMenu=new QMenu; QAction* exitAction=new QAction(tr("退出 (&X)"),trayMenu); QAction* aboutAciton=new QAction(tr("关于 (&A)"),trayMenu); QAction* clearAciton=new QAction(tr("清除 (&C)"),trayMenu); trayMenu->addAction(clearAciton); connect(clearAciton,SIGNAL(triggered()),this,SLOT(clearShots())); trayMenu->addSeparator(); trayMenu->addAction(aboutAciton); connect(aboutAciton,SIGNAL(triggered()),this,SLOT(doAboutAction())); trayMenu->addAction(exitAction); connect(exitAction,SIGNAL(triggered()),this,SLOT(close())); trayIcon->setContextMenu(trayMenu); trayIcon->show();}void MainWindow::clearShots(){ while(topLabelList.count()>0) { delete topLabelList.first().pTopLabel; topLabelList.first().pTopLabel=NULL; topLabelList.removeFirst(); }}void MainWindow::clearShot(WId id){ qDebug()<<id; if(!topLabelList.empty()); { for(int i=0;i<topLabelList.count();i++) { if(id==topLabelList[i].id) { //释放内存 delete topLabelList[i].pTopLabel; qDebug()<<"is deleted!"; //防止野指针 topLabelList[i].pTopLabel=NULL; } } } allowShot();}void MainWindow::allowShot(){ isShotting=false;}//关于对话框void MainWindow::doAboutAction(){ qDebug()<<"about"; aboutDialog->setText(":/icon/readme.txt",true); aboutDialog->setWindowTitle(tr("关于截图置顶 v1.0.1")); aboutDialog->setLogo(":/icon/resource/about-logo.png"); aboutDialog->setInfo ( "<table border=\"0\"> <tr height=\"22\"> <td width=270 valign=\"middle\" > <b>截图置顶 v1.0.1</b> </td><td> <a href=\"https://github.com/pansinm/Ssot/\">查看源代码</a> </td></tr> <tr height=\"22\"> <td width=300 valign=\"middle\">by pansinm</td> <td>pansinm@163.com</td></tr></table>" ); aboutDialog->show();}
ctoplabel.h
//截屏窗口#ifndef CTOPLABEL_H#define CTOPLABEL_H#include <QtWidgets>class CTopLabel : public QLabel{ Q_OBJECTpublic: explicit CTopLabel(QWidget *parent = 0); //截图状态 enum shotState{initShot,beginShot,finishShot}; //winId void setLabelId(WId id){labelId=id;} ~CTopLabel();signals: //发送关闭信号 void meClosed(WId); //完成截屏信号 void shotted();private: int labelId; //全屏Pixmap QPixmap fullScreenPixmap; //截图pixmap QPixmap resultPixmap; //截图状态 shotState currentState; //鼠标起始点 QPoint beginPoint; //终点 QPoint endPoint; //鼠标拖动矩形 QRect shotRect; //是否正在截图 bool isShot; //左键是否按下 bool isPressed; //拖动点 QPoint dragPosition; void paintEvent(QPaintEvent *); void mousePressEvent(QMouseEvent *ev); void mouseMoveEvent(QMouseEvent *ev); void mouseReleaseEvent(QMouseEvent *ev); void mouseDoubleClickEvent(QMouseEvent *);};#endif // CTOPLABEL_H
ctoplabel.cpp
#include "ctoplabel.h"CTopLabel::CTopLabel(QWidget *parent) : QLabel(parent){ setLabelId(this->winId()); setAutoFillBackground(true); //当前状态设置为初始化 currentState=initShot; //设置为正在截图 isShot=true; //初始化 beginPoint=QPoint(0,0); endPoint=QPoint(0,0); shotRect=QRect(0,0,0,0); //左键按下状态 isPressed=false; //初始化窗口拖动点 dragPosition=QPoint(-1,-1); //设置无边框,任务栏无图标,顶置 setWindowFlags(Qt::FramelessWindowHint|Qt::Tool|Qt::WindowStaysOnTopHint); //抓取屏幕 fullScreenPixmap = QPixmap::grabWindow(QApplication::desktop()->winId());}CTopLabel::~CTopLabel(){}void CTopLabel::mousePressEvent(QMouseEvent *ev){ if(ev->button()==Qt::LeftButton) { isPressed=true; if(isShot) { //正在截图时,改变状态及beginPoint beginPoint=ev->pos(); qDebug()<<beginPoint.x(); } else { //截图完毕时 dragPosition=ev->globalPos()-this->pos(); } }}void CTopLabel::mouseMoveEvent(QMouseEvent *ev){ if(isPressed) { if(isShot) { currentState=beginShot; //截屏拖动时 //qDebug()<<"isShot"; endPoint=ev->pos(); //根据拖动位置,计算截图区域 //左上->右下 if(beginPoint.x()<endPoint.x()&&beginPoint.y()<endPoint.y()) { shotRect=QRect(beginPoint,endPoint); } //左下->右上 else if(beginPoint.x()<endPoint.x()&&beginPoint.y()>endPoint.y()) { shotRect=QRect(beginPoint.x(),endPoint.y(),endPoint.x()-beginPoint.x(),beginPoint.y()-endPoint.y()); } //右上->左下 else if(beginPoint.x()>endPoint.x()&&beginPoint.y()<endPoint.y()) { shotRect=QRect(endPoint.x(),beginPoint.y(),beginPoint.x()-endPoint.x(),endPoint.y()-beginPoint.y()); } //右下->左上 else { shotRect=QRect(endPoint,beginPoint); } update(); } else { //窗口移动 move(ev->globalPos()-dragPosition); } }}void CTopLabel::mouseReleaseEvent(QMouseEvent *ev){ if(ev->button()==Qt::LeftButton) { endPoint=ev->pos(); //qDebug()<<beginPoint.x()<<endPoint.x(); if(isShot) { if(currentState==beginShot) { isShot=false; //改变状态 currentState=finishShot; //截图区域图像 resultPixmap=fullScreenPixmap.copy(shotRect); fullScreenPixmap.loadFromData(NULL); this->repaint(); setGeometry(shotRect); emit shotted(); //结果复制到剪切板 QClipboard *clipboard=QApplication::clipboard(); clipboard->setPixmap(resultPixmap); } } else { move(ev->globalPos()-dragPosition); } } isPressed=false;}void CTopLabel::mouseDoubleClickEvent(QMouseEvent *e){ if(e->button()==Qt::LeftButton) { //关闭当前 emit meClosed(labelId); }}void CTopLabel::paintEvent(QPaintEvent *){ QPainter painter(this); painter.setFont(QFont("simsun",20)); switch(currentState) { case initShot: painter.drawPixmap(0,0,fullScreenPixmap); painter.setPen(QPen(Qt::blue,1,Qt::SolidLine,Qt::FlatCap));//设置画笔 break; case beginShot: painter.drawPixmap(0,0,fullScreenPixmap); painter.setPen(QPen(Qt::blue,1,Qt::SolidLine,Qt::FlatCap));//设置画笔 painter.drawRect(shotRect); break; case finishShot: painter.drawPixmap(0,0,resultPixmap); painter.setPen(QPen(Qt::gray,1,Qt::SolidLine,Qt::FlatCap));//设置画笔 painter.drawRect(0,0,resultPixmap.size().width()-1,resultPixmap.size().height()-1); //截图结果窗口 break; }}
aboutdialog.h
//这个是我原来做的关于对话框的一个模板,直接拿来用了#ifndef ABOUTDIALOG_H#define ABOUTDIALOG_H#include <QDialog>#include<QLabel>#include<QTextEdit>#include<QString>#include<QPushButton>class AboutDialog : public QDialog{ Q_OBJECTpublic: explicit AboutDialog(QWidget *parent = 0); //如果为true,则text为文件名,文本框中加载文件内容(文本文件) void setText(const QString str,bool isFileName=false); //370x45图片 void setLogo(const QString filename); void setInfo(const QString info); void setBackground(const QString styleSheet="default");private: QLabel* label_Logo; QLabel* label_Info; QTextEdit* textEdit; QPushButton* btn_confirm; void init();signals:public slots: void openUrl(QString);};#endif // ABOUTDIALOG_H
aboutdialog.cpp
#include "aboutdialog.h"#include<QHBoxLayout>#include<QVBoxLayout>#include<QPixmap>#include<QDesktopServices>#include<QUrl>#include<QFile>#include<QTextStream>AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent){ init();}void AboutDialog::init(){ //标题栏不要按钮 this->setWindowFlags(Qt::WindowTitleHint | Qt::CustomizeWindowHint); label_Logo=new QLabel; label_Logo->setMinimumSize(370,45); label_Info=new QLabel; label_Info->setMinimumSize(370,45); textEdit=new QTextEdit; textEdit->setMinimumSize(370,115); textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); textEdit->setReadOnly(true); btn_confirm=new QPushButton("确定"); btn_confirm->setMinimumSize(75,25); QHBoxLayout* hlayout=new QHBoxLayout; hlayout->addStretch(); hlayout->addWidget(btn_confirm); hlayout->setMargin(4); QVBoxLayout* vlayout=new QVBoxLayout; vlayout->addWidget(label_Logo); vlayout->addWidget(label_Info); vlayout->addWidget(textEdit); vlayout->addLayout(hlayout); vlayout->setMargin(0); setLayout(vlayout); this->setMinimumSize(370,254); this->setMaximumSize(370,254); setBackground(); connect(btn_confirm,SIGNAL(clicked()),this,SLOT(hide()));}void AboutDialog::setLogo(const QString filename){ QPixmap pixmap(filename); label_Logo->setPixmap(pixmap);}void AboutDialog::setInfo(const QString info){ label_Info->setText(info); connect(label_Info,SIGNAL(linkActivated(QString)),this,SLOT(openUrl(QString)));}void AboutDialog::setText(const QString str, bool isFileName){ if(isFileName==false) textEdit->setText(str); else if(isFileName==true) { QFile file(str); if(file.open(QIODevice::ReadOnly|QIODevice::Text)) { QTextStream in(&file); QString s; s=in.readAll(); textEdit->setText(s); file.close(); } }}void AboutDialog::setBackground(const QString styleSheet){ if(styleSheet=="default") { this->setStyleSheet("AboutDialog{background: rgb(238, 241, 255);}"); } else setStyleSheet(styleSheet);}void AboutDialog::openUrl(QString url){ QDesktopServices::openUrl(QUrl(url));}
main.cpp
#include "mainwindow.h"#include <QApplication>int main(int argc, char *argv[]){ QApplication a(argc, argv); MainWindow w; //w.show(); return a.exec();}
resource.qrc
<RCC> <qresource prefix="/icon"> <file>resource/icon.png</file> <file>readme.txt</file> <file>resource/about-logo.png</file> </qresource></RCC>
以下为运行效果:
- QPixmap::grabWindow(QApplication::desktop()->winId())//用于抓取整个屏幕
- 利用paintEve绘制拖动矩形,并将剪切结果绘制到窗口。
- 截图完调整窗口大小前用repaint重绘窗口,否则有可能闪烁。
- 关闭一个窗口时,用delete删除内存,否则内存会一直叠。
- 截图完毕后用fullScreenPixmap.loadFromData(NULL)删除全屏pixmap,可释放几M的内存。
// 可设置无边框,无任务栏图标,顶置窗口。setWindowFlags(Qt::FramelessWindowHint|Qt::Tool|Qt::WindowStaysOnTopHint);
源代码地址为:https://github.com/pansinm/Ssot
程序下载地址:http://url.cn/K89Rrn
0 0
- Qt实现截屏
- QT实现截屏功能
- QT实现截屏功能
- Qt实现桌面截屏
- QT实现截屏功能
- Qt——QT实现截屏功能
- Qt:截屏软件的实现
- C++实现截屏 使用Qt
- Qt之对应用实现截屏并保存
- 利用QT实现截屏的四种方法
- Qt学习: QPixmap实现的截屏程序代码示例
- 利用QT实现截屏的四种方法
- 【QT】:QT实现登录界面
- [Qt]Qt--拖拽实现
- qt截屏模块
- Qt屏幕截屏
- Qt屏幕截屏
- QT截屏功能
- 51nod没过的那题
- CPU核心数目 与 多线程
- Q
- Android打造自己的网络框架----RxJava的基础学习使用
- 第九章 内存模型和名称空间
- Qt实现截屏
- Evaluate Division
- SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID
- 面试
- 10w定时任务,如何高效触发超时(58沈剑)
- 荣耀Magic人工智能手机发布,买不到不如选择荣耀8
- C++ Primer 第5版--练习10.15
- 链队列简单实现
- git命令之git remote的用法详解