软件实现拖动截屏并顶置截屏结果,将最后截图复制到剪切板。可用于数据对比或其它场合。
软件运行流程为:快捷键-》抓屏-》截图-》顶置-》复制结果。
开始时没注意内存,截屏耗费大量内存,后优化后空闲时内存使用在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#include #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 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#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 (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()< setText(":/icon/readme.txt",true); aboutDialog->setWindowTitle(tr("关于截图置顶 v1.0.1")); aboutDialog->setLogo(":/icon/resource/about-logo.png"); aboutDialog->setInfo(" "); aboutDialog->show(); }
截图置顶 v1.0.1 查看源代码 by pansinm [email protected]
ctoplabel.h
//截屏窗口 #ifndef CTOPLABEL_H #define CTOPLABEL_H #includeclass 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()<globalPos()-this->pos(); } } } void CTopLabel::mouseMoveEvent(QMouseEvent *ev) { if(isPressed) { if(isShot) { currentState=beginShot; //截屏拖动时 //qDebug()<<"isShot"; endPoint=ev->pos(); //根据拖动位置,计算截图区域 //左上->右下 if(beginPoint.x() 右上 else if(beginPoint.x() endPoint.y()) { shotRect=QRect(beginPoint.x(),endPoint.y(),endPoint.x()-beginPoint.x(),beginPoint.y()-endPoint.y()); } //右上->左下 else if(beginPoint.x()>endPoint.x()&&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()< 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#include #include #include #include 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#include #include #include #include #include #include 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" #includeint main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; //w.show(); return a.exec(); }
resource.qrc
resource/icon.png readme.txt resource/about-logo.png
以下为运行效果:
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