軟件實現拖動截屏並頂置截屏結果,將最後截圖復制到剪切板。可用於數據對比或其它場合。
軟件運行流程為:快捷鍵-》抓屏-》截圖-》頂置-》復制結果。
開始時沒注意內存,截屏耗費大量內存,後優化後空閒時內存使用在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.txtmainwindow.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_Hmainwindow.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_Hctoplabel.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_Haboutdialog.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