ScreenCap---Version:001
說明
從0到1,手把手帶你開發windows端的截屏軟件ScreenCap
當前版本:ScreenCap---001
支持全屏截圖
支持鼠標拖動截圖區域
支持拖拽截圖
支持保存全屏截圖
支持另存截圖到其他位置
GitHub
倉庫master下的ScreenCap項目
若您無法正常訪問,每次項目的資源會隨文章一同發布,下載壓縮包即可,永久免費
壓縮包可能較GitHub更新不及時,請諒解
開發環境
win10系統
編譯器qtcreator4.11.1
QT版本:5.14.2
C++11
問題解決
需求
提供開始截圖的按鈕,點擊開始截圖
在截圖界面提供右鍵菜單選擇
菜單實現保存當前的截圖
保存全屏截圖
截圖另存為
全屏截圖另存為
退出截圖
鼠標可以拖拽截屏區域
圖片屬性實時計算
結構
思路
screencapwidget
首先需要創建頁面ScreenCapWidget,提供開始截屏,按鍵設置,默認位置的按鈕
首先實現開始截屏的功能,這里不能直接在窗口線程實現,需要單獨創建一個screenwidget類實現截屏的主要操作
獲取到screenwidget的實例后,應該處理截屏的邏輯了,創建實例的時候直接調用screenwidget父類widget的showFullScreen函數,將screenwidget以全屏的方式顯示出來,整個屏幕是當前截屏的操作區域,遮擋其他操作,這里我們重寫一下screenwidget的showEvent事件
screenwidget
而這個screenwidget類不應該一直存在,應該是調用開始截屏的時候才開始創建,這里為了保證同一時刻只有一個screenwidget類創建,應該使用單例模式,確保只有一個實例
screenwidget創建的時候不需要ui文件,這里我們只需要使用widget里的繪圖事件和菜單功能,自己使用代碼實現
在頭文件里首先維持一個靜態的QScopedPointer對象self,用于實現單例模式
定義一個公共的靜態接口Instance以實現其他類來生成screenwidget對象
下面來實現類的默認構造函數,提供菜單功能,實現保存當前的截圖,保存全屏截圖,截圖另存為,全屏截圖另存為,退出截圖的功能
因為screencapwidget調用其fullShowScreen函數,這里重寫showEvent函數
showEvent函數中,直接獲取當前主屏幕的全屏圖像保存在fullScreen中,為提示用戶截屏開始了,這里獲取到全屏對象后,模糊處理全屏,維持一個背景值bgScreen實現背景處理
截屏界面的交互邏輯等會再實現,先處理關鍵的部分,創建一個myscreen類,實現截屏實現的數據主要邏輯
重寫完showEvent后,已經獲取到全屏圖像了,需要開始處理部分截圖了,即處理鼠標事件,首先處理鼠標按下press事件,第一次按下的位置就是起始位置,再根據此時myscreen的STATUS處理對應的事件
處理鼠標移動的事件,如果還在myscreen還在選擇狀態,那么移動完的位置就是截屏的結束位置,myscreen在移動狀態,那么計算偏移量減去移動開始時候的起始位置movPos即可,將偏移量傳入myscreen的move函數中,計算move后的截屏區域
主要的鼠標事件處理完了,下面處理release和右鍵事件
鼠標事件處理完了之后,要截屏的圖像的區域我們已經知道了,下面重寫paint事件
myscreen
該類主要實現對截屏的數據計算,來給screenwidget重寫事件提供詳細的數據
這里的類不需要窗口文件,創建純粹的cpp類即可
需要獲得從screenwidget類傳入的qsize參數,這里使用帶qsize參數的構造函數
首先截屏需要維護屏幕長和寬的值,maxHeight和maxWidth,這里的數據應該是誰調用誰能獲取,全部設置為私有屬性,還需要設置其getWidth和getHeight方法
還需要維持截屏區域的左上角和右下角的point值leftUpPos和rightDownPos,并設置getLeftUp和getRightDown方法
處理鼠標事件的時候,需要判斷當前截圖的狀態,維持枚舉值STATUS,保存選擇截屏區域,拖拽截屏,
這里需要實現判斷鼠標是否在現有的截屏區域內isInArea和計算移動后的截屏位置的move函數
其他功能
關鍵代碼
注:關鍵代碼只負責解釋各部分的邏輯關系,詳解看代碼注釋
screencapwidget處理開始截屏的功能,創建screenwidget的唯一實例,并顯示全屏窗口
//ScreenWidget全屏顯示ScreenWidget::Instance()->showFullScreen();
與showFullScreen相關的screenwidget的重寫showEvent事件
//重寫窗口被顯示的事件
void ScreenWidget::showEvent(QShowEvent *)
{//設置初始位置QPoint point(-1,-1);myscreen->setStart(point);myscreen->setEnd(point);//獲取當前屏幕對象QScreen* pscreen = QApplication::primaryScreen();//調用QScreen的grabwindow進行全屏截圖*fullScreen = pscreen->grabWindow(0,0,0,myscreen->getWidth(),myscreen->getHeight());//設置透明度實現模糊背景QPixmap pix(myscreen->getWidth(),myscreen->getHeight());pix.fill((QColor(160,160,160,200)));bgScreen = new QPixmap(*fullScreen);QPainter p(bgScreen);p.drawPixmap(0,0,pix);
}
screenwidget實現單例模式的主要代碼
//定義單例模式,確保截屏的時候只能有一個
ScreenWidget* ScreenWidget::Instance()
{//還沒有創建實例if(self.isNull()){//加把鎖,只能有一個線程訪問static QMutex mutex;//自動加解鎖QMutexLocker locker(&mutex);//再次判斷有沒有實例,防止等待的時間中有線程獲取到實例了if(self.isNull()){self.reset(new ScreenWidget);}}return self.data();}
creenwidget提供的菜單功能
//創建一個菜單文件menu = new QMenu(this);//添加菜單的功能menu->addAction("保存當前的截圖",this,SLOT(saveScreen()));menu->addAction("保存全屏截圖",this,SLOT(saveFullScreen()));menu->addAction("截圖另存為",this,SLOT(saveScreenOther()));menu->addAction("全屏截圖另存為",this,SLOT(saveFullOther()));menu->addAction("退出截圖",this,SLOT(hide()));
screenwidget維持myscreen的類,并在screenwidget的構造函數中實例化myscreen類,傳入當前屏幕的大小,二者同步生成
myScreen* myscreen;
//獲取屏幕大小myscreen = new myScreen(deskGeometry.size());
獲取到當前屏幕的qrect對象,調用size函數獲取屏幕的size值,使用宏展開式,不單獨處理了,需要的時候直接綻開計算
#define deskGeometry qApp->primaryScreen()->geometry()
處理圖片移動
void myScreen::move(QPoint p)
{//計算move后的四個點坐標int lx = leftUpPos.x() + p.x();int ly = leftUpPos.y() + p.y();int rx = rightDownPos.x() + p.x();int ry = rightDownPos.y() + p.y();//確保移動后的截屏不會超出屏幕范圍if(lx < 0){lx = 0;rx -= p.x();}if(ly < 0){ly = 0;ry -= p.y();}if(rx > maxWidth){rx = maxWidth;lx -= p.x();}if(ry > maxHeight){ry = maxHeight;ly -= p.y();}//更新移動后的值leftUpPos = QPoint(lx,ly);rightDownPos = QPoint(rx,ry);startPos = leftUpPos;endPos = rightDownPos;
}
處理鼠標press
void ScreenWidget::mousePressEvent(QMouseEvent *e)
{int status = myscreen->getStatus();//選擇區域的狀態if(status == myScreen::SELECT){//把鼠標按下的位置設置為開始位置myscreen->setStart(e->pos());}//拖拽截屏else if(status == myScreen::MOV){//鼠標不在截屏的區域內,是要重新選擇截屏區域if(myscreen->isInArea(e->pos()) == false){//新按下的位置設置為開始位置,并重置狀態為選擇myscreen->setStart(e->pos());myscreen->setStatus(myScreen::SELECT);}//在截屏區域內,是要拖拽截屏else{//開始移動的起始位置就是現在鼠標按下的位置movPos = e->pos();this->setCursor(Qt::SizeAllCursor);}}this->update();
}
處理鼠標move
void ScreenWidget::mouseMoveEvent(QMouseEvent *e)
{//在選擇狀態if(myscreen->getStatus() == myScreen::SELECT){myscreen->setEnd(e->pos());}//在移動狀態else if(myscreen->getStatus() == myScreen::MOV){//計算鼠標偏移量QPoint p(e->x() - movPos.x(),e->y() - movPos.y());myscreen->move(p);movPos = e->pos();//保存上一次鼠標的位置}//觸發窗口的更新,重新繪制屏幕截圖和矩形框this->update();
}
文章轉載自:KanHai1024
原文鏈接:https://www.cnblogs.com/kanhai1024/p/17883714.html