從0到1,手把手帶你開發截圖工具ScreenCap------001實現基本的截圖功能

ScreenCap---Version:001

說明

image

  • 從0到1,手把手帶你開發windows端的截屏軟件ScreenCap

  • 當前版本:ScreenCap---001

  • 支持全屏截圖

  • 支持鼠標拖動截圖區域

  • 支持拖拽截圖

  • 支持保存全屏截圖

  • 支持另存截圖到其他位置

GitHub

  • 倉庫master下的ScreenCap項目

  • 若您無法正常訪問,每次項目的資源會隨文章一同發布,下載壓縮包即可,永久免費

  • 壓縮包可能較GitHub更新不及時,請諒解

開發環境

  • win10系統

  • 編譯器qtcreator4.11.1

  • QT版本:5.14.2

  • C++11

問題解決

需求

  • 提供開始截圖的按鈕,點擊開始截圖

  • 在截圖界面提供右鍵菜單選擇

  • 菜單實現保存當前的截圖

  • 保存全屏截圖

  • 截圖另存為

  • 全屏截圖另存為

  • 退出截圖

  • 鼠標可以拖拽截屏區域

  • 圖片屬性實時計算

結構

image

image

思路

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/206965.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/206965.shtml
英文地址,請注明出處:http://en.pswp.cn/news/206965.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

人工智能技術在數據治理中的一些思考

隨著企業信息化系統的快速建設&#xff0c;以及物聯網的規模化的應用&#xff0c;企業數據規模快速增長&#xff0c;與之同時企業數據的治理模式仍然以傳統的治理方式為主&#xff0c;ChatGPT等人工智能的崛起正深刻改變著數據治理的思路&#xff0c;如何將AI技術引入企業數據治…

C++新經典模板與泛型編程:用成員函數重載實現std::is_convertible

用成員函數重載實現is_convertible C標準庫中提供的可變參類模板std::is_convertible&#xff0c;這個類模板的主要能力是判斷能否從某個類型隱式地轉換到另一個類型&#xff0c;返回的是一個布爾值true或false。例如&#xff0c;一般的從int轉換成float或從float轉換成int&am…

使用Plex結合cpolar搭建本地私人媒體站并實現遠程訪問

文章目錄 1.前言2. Plex網站搭建2.1 Plex下載和安裝2.2 Plex網頁測試2.3 cpolar的安裝和注冊 3. 本地網頁發布3.1 Cpolar云端設置3.2 Cpolar本地設置 4. 公網訪問測試5. 結語 1.前言 用手機或者平板電腦看視頻&#xff0c;已經算是生活中稀松平常的場景了&#xff0c;特別是各…

劇本殺小程序搭建:打造線上劇本殺新體驗

劇本殺是一款以角色扮演為主的游戲&#xff0c;一度成為了年輕人的最喜愛的社交游戲。在劇本殺市場需求下&#xff0c;劇本殺規模也迅速上升。今年第一季度&#xff0c;劇本殺市場規模環比增長47%&#xff0c;市場整體消費水平逐漸呈上升趨勢。 隨著劇本殺的不斷發展&#xff…

echarts繪制一個環形圖2

其他echarts&#xff1a; echarts繪制一個環形圖 echarts繪制一個柱狀圖&#xff0c;柱狀折線圖 echarts繪制一個餅圖 效果&#xff1a; 組件代碼&#xff1a; <template><div class"wrapper"><div ref"doughnutChart2" id"dough…

ORACLE數據庫實驗總集 實驗六 SQL 語句應用

一、 實驗目的 &#xff08;1&#xff09; 掌握數據的插入&#xff08;INSERT&#xff09;、 修改&#xff08;UPDATE&#xff09; 和刪除&#xff08;DELETE&#xff09; 操作。 &#xff08;2&#xff09; 掌握不同類型的數據查詢&#xff08;SELECT&#xff09; 操作。 二、…

阿里滴滴之后,騰訊視頻也崩了!網友追問:下一個是誰?

繼滴滴“崩了”一夜后&#xff0c;剛過去不到一周時間&#xff0c;互聯網“崩了”連續劇又迎來了續集。 就在剛剛&#xff0c;也是晚間時分&#xff0c;網友曝出騰訊視頻崩了&#xff0c;不能追劇了。接著&#xff0c;騰訊視頻官方便現身回應&#xff0c;坐實了傳聞。 還是同…

JVM虛擬機:如何查看JVM初始和最終的參數?

本文重點 在前面的課程中&#xff0c;我們學習了如何查看當前程序所處于的xx參數&#xff0c;本文再介紹一種如何參看JVM的xx參數&#xff1f; 查看JVM的所有初始化參數 方式一&#xff1a;java -XX:PrintFlagsInitial 方式二&#xff1a;java -XX:PrintFlagsInitial -versio…

【自學篇】Python篇-第一天溫度轉換

1、規則 輸入 華氏度 轉換為 攝氏度 輸入 攝氏度 轉換為 華氏度 轉換公式&#xff1a; 華氏度 攝氏度 * 1.8 32 攝氏度 &#xff08;華氏度32 &#xff09;/1.8 2、python代碼 TempStr input() if TempStr[-1] in [F,f]:print("轉換后的溫度值&#xff1a;{:.2f}C&…

淺談Elasticsearch備份和恢復

Elasticsearch 備份和恢復功能 Elasticsearch 是一個分布式搜索和分析引擎&#xff0c;廣泛應用于各種場景&#xff0c;如日志分析、全文搜索和實時數據處理。在使用 Elasticsearch 時&#xff0c;數據的安全和可用性至關重要。本文將詳細講解 Elasticsearch 的備份和恢復功能…

Uncle Maker: (Time)Stamping Out The Competition in Ethereum

目錄 筆記后續的研究方向摘要引言貢獻攻擊的簡要概述 Uncle Maker: (Time)Stamping Out The Competition in Ethereum CCS 2023 筆記 本文對以太坊 1 的共識機制進行了攻擊&#xff0c;該機制允許礦工獲得比誠實同行更高的挖礦獎勵。這種名為“Uncle Maker”的攻擊操縱區塊時間…

mysql數據庫中int字段長度,即int(1)和int(10)的區別

1.起因 為什么想起來看這個問題&#xff0c;是最近有同事問mysql的init類型的字段長度的問題&#xff0c;他問int(1)和int(10)是什么意思&#xff0c;是字段長度越大&#xff0c;能存儲的數字越大么&#xff1f;咋一問&#xff0c;還有點懵&#xff0c;從慣性思維來看&#xf…

React 中虛擬DOM是什么,為什么需要它?

注意&#xff1a;本節主要講React中的虛擬DOM&#xff0c;但是虛擬DOM并不是React中特有的內容。 1. React 中虛擬 DOM是什么&#xff1f; 虛擬DOM是對真實DOM的描述&#xff0c;虛擬DOM是JS對象&#xff0c;實際上就是 JSX 通過 babel 轉換成 React.createElement()&#xff…

8.3 C++11對Unicode的支持

一、C11對Unicode的支持 在C98中&#xff0c;引入wchar_t對Unicode支持&#xff0c;但是后來由于不同平臺下wchar_t的寬度并不相同(8,16,32位)&#xff0c;導致可移植性受到影響。因此從C11開始引入了char16_t、char32_t以及原有的char&#xff0c;分別存儲utf16&#xff0c;u…

邊緣端部署的典型目標識別網絡

邊緣端&#xff08;Edge&#xff09;部署深度學習目標檢測網絡通常涉及到在資源受限的設備上執行模型推斷。這里有一些邊緣端部署深度學習目標檢測網絡的常見策略和技術&#xff1a; 輕量化模型&#xff1a; 選擇或設計輕量級的深度學習模型&#xff0c;例如MobileNet、Squeez…

來自OpenAI的官方解釋:ChatGPT中的GPTs與Assistants API的區別是什么?有什么差異?

本文原文來自DataLearnerAI的官方網站&#xff1a; 來自OpenAI的官方解釋&#xff1a;ChatGPT中的GPTs與Assistants API的區別是什么&#xff1f;有什么差異&#xff1f; | 數據學習者官方網站(Datalearner)https://www.datalearner.com/blog/1051701996595465 OpenAI發布的產…

圖解算法數據結構-LeetBook-查找01_第一個只出現一次的字符

某套連招動作記作僅由小寫字母組成的序列 arr&#xff0c;其中 arr[i] 第 i 個招式的名字。請返回第一個只出現一次的招式名稱&#xff0c;如不存在請返回空格。 示例 1&#xff1a; 輸入&#xff1a;arr “abbccdeff” 輸出&#xff1a;‘a’ 示例 2&#xff1a; 輸入&…

3D Web輕量引擎HOOPS Communicator如何實現對大模型的渲染支持?

除了讀取輕松外&#xff0c;HOOPS Communicator對超大模型的支持效果也非常好&#xff0c;它可以支持30GB的包含70萬個零件和3.5億個三角面的Catia裝配模型&#xff01; 那么它是如何來實現對大模型的支持呢&#xff1f; 我們將從以下幾個方面與大家分享&#xff1a;最低幀率…

python核心階段(五)—— 面向對象三大特性

1.封裝 概念&#xff1a;封裝主要是指將一些屬性和相關方法封裝在一個對象中&#xff0c;對外隱藏內部具體實現細節 作用&#xff1a;1&#xff09;使用起來更加方便&#xff0c;類似于提供了一個工具箱 2&#xff09;保證數據的安全&#xff08;設置私有屬性&#xff09; 3&am…

高精度加法,減法,乘法,除法(下)(C語言)

前言 上一篇博客我們分享了高精度加法&#xff0c;減法,這一期我將為大家講解高精度乘法和高精度除法。那讓我們開始吧&#xff01; 對加法和減法感興趣的話就點我 文章目錄 1&#xff0c;乘法2&#xff0c;除法3&#xff0c;尾聲 1&#xff0c;乘法 讓我們想想我們平時做數學…