【MFC】繪制自定義控件-顯示圖片(支持放大操作)

目錄

  • 一、CDC類(二級緩存)
  • 二、計算視口
  • 三、放大操作
  • 代碼中初始化操作(方便以后cv)

一、CDC類(二級緩存)

CDC類是設備上下文的核心類,它的作用是抽象化對圖形輸出設備(像屏幕、打印機、內存位圖等)的訪問,借助CDC我們可以在屏幕上繪制圖像。

自定義控件中采用了雙緩沖技術,防止在繪制圖像時屏幕閃爍。其中用到了關鍵的幾個類和函數,如下。

//成員變量
CDC m_ImageDC;								//	源圖片DC
HBITMAP m_hImageBitmap;						//	位圖
BITMAPINFO* m_pBitmapInfo;
void* m_pBuffdata;							//	圖像數據CDC m_buffDC_image;							// 二級緩存
CBitmap m_cBitmap;

圖像放在控件上,圖像的大小和控件的大小可能不一樣,這時需要將圖像進行壓縮或放繪制到控件上(需要直接操作數據,調用Windows API),故在第一個CDC中使用了HBITMAP位圖。創建位圖調用Windows API接口函數 CreateDIBSection()函數。該函數直接綁定數據指針m_pBuffdata
,可以直接操作數據。

計算好壓縮因子、視口、窗口顯示區域,通過StretchBlt()函數進行壓縮到m_ImageDC中,再通過BitBlt()函數將m_ImageDC復制到m_buffDC_image,再將m_buffDC_image復制到屏幕上。

進行放大操作就是調節視口區域,再計算壓縮因子進而計算窗口顯示區域,再把圖像放到指定區域。

二、計算視口

//成員變量
CSize m_tSizeWnd;							//	控件顯示窗口的尺寸
CSize m_tSizeImg;							//	圖片的尺寸
int m_iImageSize;							//	圖片的字節數CRect m_reShowImage;						//	顯示圖像區域(視口)
CRect m_reShowWnd;							//	顯示窗口區域double m_dChangeNum;						//	壓縮因子(變化因子)

要求:將圖像顯示在控件上,并且保證在控件上居中。

計算縮放因子

圖像不一定是完美契合控件大小,要等比例縮放需計算縮放因子。
計算窗口的寬高和圖像寬高的比例,為了圖像全部顯示在控件上,我們選擇最小的比例當縮放因子。

//計算縮放因子
double dChangeX = (double)m_tSizeWnd.cx / m_tSizeImg.cx;
double dChangeY = (double)m_tSizeWnd.cy / m_tSizeImg.cy;m_dChangeNum = min(dChangeX, dChangeY);

計算視口(圖像全部顯示在空間上的視口大小)

圖像的顯示區域就是視口,圖像完全顯示到控件上,及視口就是整個圖像的區域。

//視口大小(相對于圖像的坐標)
m_reShowImage.left = 0;
m_reShowImage.top = 0;
m_reShowImage.right = m_reShowImage.left + m_tSizeImg.cx;
m_reShowImage.bottom = m_reShowImage.top + m_tSizeImg.cy;

計算控件顯示圖像的區域(居中)

第一步:通過壓縮因子計算壓縮后圖像的寬高
第二步:通過控件的寬高-壓縮后圖像的寬高再除以2,得到居中后的坐標

double dWid = static_cast<double>(m_reShowImage.right - m_reShowImage.left) * m_dChangeNum;
double dHit = static_cast<double>(m_reShowImage.bottom - m_reShowImage.top) * m_dChangeNum;int iWid = static_cast<int>(dWid + 0.5);  // 四舍五入
int iHit = static_cast<int>(dHit + 0.5);m_reShowWnd.left = (m_tSizeWnd.cx - iWid) >> 1;
m_reShowWnd.top = (m_tSizeWnd.cy - iHit) >> 1;
m_reShowWnd.right = m_reShowWnd.left + iWid;
m_reShowWnd.bottom = m_reShowWnd.top + iHit;

再調用第一節說的StretchBlt()函數將圖像縮放復制到二級緩存中

::StretchBlt(m_buffDC_image.GetSafeHdc(), m_reShowWnd.left,m_reShowWnd.top,m_reShowWnd.Width(),m_reShowWnd.Height(),m_ImageDC.GetSafeHdc(),m_reShowImage.left,m_reShowImage.top,m_reShowImage.Width(), m_reShowImage.Height(),SRCCOPY);

三、放大操作

放大操作:計算新視口

當鼠標點擊圖像時,圖像放大。鼠標指向的區域是相對圖像坐標是不變的,通過這個坐標計算新的視口。

補充:當圖像需要放大兩倍時,就是視口區域縮小兩倍,再顯示控件上就是放大兩倍的效果。

在這里插入圖片描述
重寫鼠標點擊事件,我們可以得到鼠標點擊的坐標(x,y)。因為是等比例縮放,通過縮放因子計算可以得到W2和H2。及可以算出坐標到新視口邊的距離。

再計算之前需要將坐標轉換為圖像坐標系上的坐標。(圖上畫的兩個矩形都是圖像)

坐標轉換(控件上的坐標轉換成圖像上的坐標)

//將窗口的坐標轉化為圖像上的坐標
//因為圖像是通過縮放因子等比例縮放顯示在控件上的,故可以通過這層關系
//計算相對于圖像上的坐標
void MyImageView::OnLButtonDblClk(UINT nFlags, CPoint point)
{point.x /= m_dChangeNum;point.y /= m_dChangeNum;

計算新的縮放因子、計算新的視口大小

double dOldChangeNum = m_dChangeNum;
double newScale = 2 * m_dChangeNum;
newScale = max(m_dMinScale, min(m_dMaxScale, newScale));
double scaleRatio = dOldChangeNum / newScale;  //	1/2//通過新的縮放因子得出新視口的寬高
int iWid = m_reShowImage.Width() * scaleRatio;
int iHit = m_reShowImage.Height() * scaleRatio;//通過比例關系 計算出視口的區域坐標
m_reShowImage.left = point.x - (point.x * iWid / m_tSizeImg.cx);
m_reShowImage.top = point.y - (point.y * iHit / m_tSizeImg.cy);
m_reShowImage.right = m_reShowImage.left + iWid;
m_reShowImage.bottom = m_reShowImage.top + iHit;

至此計算出新視口的區域,再進行計算新顯示窗口區域就可以完成放大操作。

代碼中初始化操作(方便以后cv)

	CDC* pDC = pWnd->GetDC();m_pBitmapInfo = (BITMAPINFO*)malloc(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 255);if (NULL != m_pBitmapInfo){for (int i = 0; i < 256; i++){m_pBitmapInfo->bmiColors[i].rgbRed = i;m_pBitmapInfo->bmiColors[i].rgbGreen = i;m_pBitmapInfo->bmiColors[i].rgbBlue = i;}m_pBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);m_pBitmapInfo->bmiHeader.biBitCount = (model == false) ? 8 : 24;m_pBitmapInfo->bmiHeader.biPlanes = 1;m_pBitmapInfo->bmiHeader.biCompression = 0;m_pBitmapInfo->bmiHeader.biXPelsPerMeter = 0;m_pBitmapInfo->bmiHeader.biYPelsPerMeter = 0;m_pBitmapInfo->bmiHeader.biClrImportant = 0;m_pBitmapInfo->bmiHeader.biClrUsed = 0;m_pBitmapInfo->bmiHeader.biHeight = tSizeImg.cy;m_pBitmapInfo->bmiHeader.biWidth = tSizeImg.cx;int bitCount = (model == false) ? 8 : 24;m_iImageWidthStep = ((tSizeImg.cx * bitCount / 8) + 3) & ~3;m_pBitmapInfo->bmiHeader.biSizeImage = m_iImageWidthStep * tSizeImg.cy;m_ImageDC.CreateCompatibleDC(pDC);m_ImageDC.SetStretchBltMode(HALFTONE); //( COLORONCOLOR ); //(HALFTONE);m_ImageDC.SetBkMode(TRANSPARENT);if (m_hImageBitmap){DeleteObject(m_hImageBitmap);m_hImageBitmap = NULL;}m_hImageBitmap = CreateDIBSection(m_ImageDC.m_hDC, m_pBitmapInfo, DIB_RGB_COLORS, &m_pBuffdata, NULL, 0);m_iImageSize = m_iImageWidthStep * tSizeImg.cy * sizeof(unsigned char);memset(m_pBuffdata, 0, m_iImageSize);m_ImageDC.SelectObject(m_hImageBitmap);}//二級緩存初始化m_cBitmap.CreateCompatibleBitmap(pDC, m_tSizeWnd.cx, m_tSizeWnd.cy);m_buffDC_image.CreateCompatibleDC(pDC);m_buffDC_image.SetStretchBltMode(HALFTONE); //( COLORONCOLOR ); //(HALFTONE);m_buffDC_image.SetBkMode(TRANSPARENT);m_buffDC_image.SelectObject(&m_cBitmap);

注:需要重寫這兩個函數

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);//這個函數中 設置格式SS_OWNERDRAW 之后 ,調用Invalidate(false)
//才會去執行DrawItem()函數
virtual void PreSubclassWindow()
{ModifyStyle(SS_TYPEMASK,SS_OWNERDRAW | SS_NOTIFY, SWP_FRAMECHANGED);CStatic::PreSubclassWindow();

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

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

相關文章

在Proteus新工程中放置基本元器件

視頻教程&#xff1a; [最詳細]Proteus新建第一個工程與快捷鍵設置 操作步驟 1選擇這個黃色的三角&#xff0c;然后點擊旁邊的P,開始找元件。 2點開P后&#xff0c;呈現如下圖界面&#xff0c;我們在Keyword欄中&#xff0c;輸入stm32&#xff0c;然后他會自動出現對應的元件&…

PRUD幣推動健康數據資產化,開啟Web3隱私金融新時代

在全球健康科技與數據主權浪潮下&#xff0c;PRUD幣&#xff08;Prudential Utility & Data Token&#xff09;正成為Web3健康金融領域中的重要通證。項目通過鏈上身份綁定、健康行為證明、隱私計算與NFT機制&#xff0c;為用戶打造了“健康數據資產化”的創新路徑&#xf…

Mac 安裝 finalshell

1.下載 地址&#xff1a;FinalShell官網 第一個進入選擇對應的 mac 版本下載。 下一步下一步完成安裝。 2.鏈接虛擬機&#xff0c;點擊圖示文件夾 點擊新建鏈接&#xff0c;新建 SSH 鏈接 3.去 vmware 中查詢 Linux 系統的 IP,使用 ip addr 命令或者 ifconfig 命令皆可。 ip…

Javaweb - 2 HTML

目錄 HTML 入門 1. HTML & CSS & JavaScript 的作用 2. 什么是 HTML 3. 什么是超文本 4. 什么是標記語言 5. HTML 基本結構 6. HTML 概念詞匯解釋 7. HTML 的一些語法規則 8. 開發工具 VsCode 安裝插件&#xff1a; 常見設置&#xff1a; HTML 常見標簽 …

CWGAN-GP 增強型 CAE 在非 IID 數據集中用于 5G-NR 干擾檢測

抽象 在不斷擴大的 5G-NR 無線蜂窩網絡領域中&#xff0c;無線干擾攻擊作為安全攻擊普遍存在&#xff0c;損害了接收信號的質量。我們通過將加性高斯白噪聲 &#xff08;AWGN&#xff09; 合并到真實世界的同相和正交 &#xff08;I/Q&#xff09; OFDM 數據集中來模擬干擾環境…

JavaEE-Spring-Web-Mvc

Spring Web MVC 是基于 Servlet API 構建的原始 Web 框架&#xff0c;從?開始就包含在 Spring 框架中。它的正式名稱“Spring Web MVC”來?其源模塊的名稱(Spring-webmvc)&#xff0c;但它通常被稱為"Spring MVC". Servlet 是?種實現動態??的技術. 準確來講Serv…

Linux從入門到入門

系統教程學習類 Ubuntu 從入門到精通 系統頁面/基本操作類 Ubuntu20.04終端固定終端到左邊的導航欄_ubuntu20.04設置菜單固定-CSDN博客Ubuntu 20.04 系統5分鐘后老是自動鎖屏_修改鎖屏時間-CSDN博客 命令類 拷貝&#xff1a;將 下載 文件夾里的.sh文件 復制到opt目錄下 sudo cp…

AI自動生成Git提交信息-git AI Commit

在現代軟件開發中&#xff0c;編寫清晰且一致的Git提交信息對于維護項目歷史和促進團隊協作至關重要。然而&#xff0c;為每次變更手動撰寫描述性提交信息可能耗時&#xff0c;尤其是處理復雜差異或大型項目時。AI Commit 是一個利用AI分析Git差異并生成符合Conventional Commi…

【三大前端語言之一】樣式:CSS詳解

【三大前端語言之一】樣式&#xff1a;CSS詳解 在了解完HTML的有關知識后&#xff0c;我們應該知道&#xff0c;一個網頁光有框架還不行&#xff0c;必須還得有裝飾它的樣式。就好比房子的結構搭好了&#xff0c;但如果沒有油漆、沒有窗簾、沒有家具&#xff0c;就無法真正展現…

Spring AI 聊天記憶功能實戰(一):從接口設計到生產實踐

Spring AI 聊天記憶功能實戰&#xff08;一&#xff09;&#xff1a;從接口設計到生產實踐 在構建AI對話應用時&#xff0c;聊天記憶管理及存儲是實現連貫上下文交互的關鍵組件。而大模型&#xff08;LLM&#xff09;本質上是無狀態的&#xff0c;這意味著它們不會保留歷史交互…

Element Plus 對話框 el-dialog 和 抽屜 el-drawer 的使用注意項(使用 div 包裹)

總結&#xff1a;使用 div 包裹&#xff01;&#xff01;&#xff01; 詳細說明&#xff1a; 對話框 el-dialog 或 抽屜 el-drawer 樣式的設置說明&#xff1a; 要想有效設置 el-dialog 或 el-drawer 的樣式&#xff0c;需確保 el-dialog 或 el-drawer 的上層不是template&am…

【python】簡單演示 gateway、service、client的工作原理

gateway 看起來主要是做協議轉換的A gateway is a network node that acts as an entrance and exit point, connecting two networks that use different protocols. It allows data to flow between these networks, essentially acting as a translator between different c…

數據倉庫面試題合集⑥

實時指標體系設計 + Flink 優化實戰:面試高頻問題 + 項目答題模板 面試中不僅會問“你做過實時處理嗎?”,更會追問:“實時指標體系是怎么搭建的?”、“你們的 Flink 穩定性怎么保證?” 本篇聚焦實時指標體系設計與 Flink 優化場景,幫你答出架構設計力,也答出調優實戰感…

Vue + AbortController 請求取消彈窗 hook 封裝

背景 實際業務開發場景中&#xff0c;往往存在有些大數據請求的需求&#xff0c;一旦請求發起加載遮罩后用戶就無法操作了&#xff0c;直接尬住&#xff0c;所以提供一個支持取消查詢的功能還是很有必要的&#xff0c;為了在全業務接口都能使用封裝一個hook。 ?為什么要用 A…

數據結構相關

1 問題 如何辨析數據對象和數據結構&#xff1f;如何設計多種儲存結構以及他們特性有什么&#xff1f;內存條和硬盤的區別&#xff1f; 2 方法 明晰倆者的定義數據對象是性質相同的有限個數據元素的集合&#xff0c;他是數據的一個子集。數據結構是指所涉及的數據元素的集合以及…

MacOS內存管理-刪除冗余系統數據System Data

文章目錄 一、問題復現二、解決思路三、解決流程四、附錄 一、問題復現 以題主的的 Mac 為例&#xff0c;我們可以看到System Data所占數據高達77.08GB&#xff0c;遠遠超出系統所占內存 二、解決思路 占據大量空間的是分散在系統中各個位置Cache數據&#xff1b; 其中容量最…

純視覺SOTA!華科小米推出ReCogDrive:結合VLM和強化學習的端到端自動駕駛框架

摘要 端到端自動駕駛的研究目前越來越火熱&#xff0c;現有方法通過視覺語言模型&#xff08;VLM&#xff09;來解決其在長尾場景中性能降低的問題&#xff0c;但是仍然存在一些局限性。本文提出了ReCogDrive&#xff0c;它將VLM與基于擴散的軌跡規劃器相結合&#xff0c;并且采…

MySQL慢SQL優化全攻略:從診斷到調優

目錄 慢SQL日志分析與診斷 開啟慢查詢日志 慢查詢日志分析工具 慢SQL優化策略 1. 避免SELECT * 查詢 2. 創建高效索引 索引選擇原則 索引使用注意事項 3. 使用EXPLAIN分析執行計劃 4. 優化排序操作 5. 解決深分頁問題 6. 避免全表掃描 7. 優化JOIN操作 8. 合理使用…

OPENPPP2 VMUX 技術探秘(高級指南)

&#x1f680; VMUX技術分析&#xff1a;OPENPPP2中的虛擬多路復用技術 &#x1f31f; 一、技術目標 &#x1f517; 連接多路復用 通過單個或多個物理鏈路&#xff0c;承載多個邏輯TCP連接。 &#x1f680; 高性能傳輸 支持數據包亂序重組實現動態流量控制&#xff08;擁塞檢測…

Linux系統時間不對導致mysql初始化失敗:Data Dictionary initialization failed.(數據字典版本驗證失敗)

文章目錄 問題描述分析**問題原因分析****解決方案****1. 修正系統時間****2. 檢查數據目錄完整性****3. 重新初始化數據目錄****4. 調整 MySQL 配置** **驗證與后續步驟****注意事項** 其他說明 問題描述 mysql數據初始化失敗&#xff0c;發現系統時間是1970年&#xff0c;我…