您的位置:首页 > 编程语言 > Qt开发

Qt实现截屏

2013-11-25 19:21 447 查看
软件实现拖动截屏并顶置截屏结果,将最后截图复制到剪切板。可用于数据对比或其它场合。软件运行流程为:快捷键-》抓屏-》截图-》顶置-》复制结果。开始时没注意内存,截屏耗费大量内存,后优化后空闲时内存使用在4M左右。以下为代码:
#-------------------------------------------------
# Ssot.pro
# Project created by QtCreator 2013-11-24T11:01:06
#
#-------------------------------------------------
QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Ssot
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp \
ctoplabel.cpp \
aboutdialog.cpp
HEADERS  += mainwindow.h \
ctoplabel.h \
aboutdialog.h
RESOURCES += \
resource.qrc
RC_FILE  += \
info.rc
OTHER_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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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
本文出自 “大耳” 博客,请务必保留此出处http://cpp51.blog.51cto.com/5346598/1331326
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: