軟件實現拖動截屏並頂置截屏結果,將最後截圖復制到剪切板。可用於數據對比或其它場合。
軟件運行流程為:快捷鍵-》抓屏-》截圖-》頂置-》復制結果。
開始時沒注意內存,截屏耗費大量內存,後優化後空閒時內存使用在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>[email protected]</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=\'#\'" //當前狀態設置為初始化 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=\'#\'" 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=\'#\'" QString styleSheet) { if(styleSheet=="default") { this->setStyleSheet("AboutDialog{background=\'#\'" 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