程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 《電子尺》V1.02程序開發實例

《電子尺》V1.02程序開發實例

編輯:關於VC++

程序功能

有時在制作網頁或一些多媒體時,需要插入一些自制的圖片和flash動畫,在制作之前一定需要先確定圖片的高和寬,用這個軟件就可以輕松的量出你所需要的高和寬。

總體介紹

程序在開始測量時要鎖定整個屏幕,包括任務欄等。原先計劃利用鉤子(Hook)來截取所有的鼠標消息,實現屏幕的鎖定。但是無論使用WH_MOUSE或WH_GETMESSGAE都無法完全截獲所有消息。所以我就利用了一個占據整個屏幕的透明窗口來實現。雖然是透明的窗口,但是一旦窗口創建以後,實際屏幕的更新就不會再對窗口中顯示的內容進行影響了。

在開始測量時,有一個跨這個屏幕的大十字隨著鼠標移動,來輔助定位。在單擊第一個點後,會出現一個小的紅十字來做標記,如下圖所示:

代碼分析

首先要創建一個透明的窗口,因此我從CWnd繼承了一個類Target。在Target類中自定義了一個創建透明窗口的方法:

void Target::CreateTarget(LPCTSTR lpTitle, CWnd* pWnd)
{
//取得屏幕的高和寬,用於創建跨整個屏幕的窗口
cxScreen=::GetSystemMetrics(SM_CXSCREEN);
cyScreen=::GetSystemMetrics(SM_CYSCREEN);
//用CWnd::CreateEx創建一個透明的窗口,WS_EX_TOPMOST使窗口總是在最頂層
CreateEx(WS_EX_TOPMOST,
AfxRegisterWndClass(0,AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
"Target", WS_POPUP, 0, 0, cxScreen, cyScreen,
NULL, NULL, NULL );
//pDC用於開始測量時繪制輔助標志
pDC=GetDC();
//bSecond用於標識是否已經點擊了一次
bSecond=FALSE;
//pWndParent保存父窗口的指針
pWndParent=pWnd;
//創建一個MemDC臨時存放整個屏幕的畫面,用於刷新屏幕
MemDC.CreateCompatibleDC(pDC);
CBitmap Bitmap;
Bitmap.CreateCompatibleBitmap(pDC,cxScreen,cyScreen);
//確定MemDC的大小
MemDC.SelectObject(&Bitmap);
//將這個屏幕的都存入MemDC
MemDC.BitBlt(0,0,cxScreen,cyScreen,pDC,0,0,SRCCOPY);
//將臨時圖片刪除
::DeleteObject(Bitmap.m_hObject);
}

重載Target類的鼠標移動的消息處理函數,使鼠標移動時,有一個十字跟隨移動,並且在已經點擊了第一個點以後,會有一條鏈接起點與終點的線。

void Target::OnMouseMove(UINT nFlags, CPoint point)
{
//首先將MemDC中的圖片復制到當前窗口,將原有的輔助線都掩蓋掉
pDC->BitBlt(0,0,cxScreen,cyScreen,&MemDC,0,0,SRCCOPY);
//畫一個新的十字
pDC->MoveTo(0,point.y);
pDC->LineTo(cxScreen,point.y);
pDC->MoveTo(point.x,0);
pDC->LineTo(point.x,cyScreen);
//如果已經點擊過一次,再畫一條從起點到終點的輔助線
if(bSecond)
{
pDC->MoveTo(startPos.x,startPos.y);
pDC->LineTo(point.x,point.y);
}
CWnd::OnMouseMove(nFlags, point);
}

重載鼠標左擊的消息處理函數,兩次單擊後向父窗口發送一個自定義的消息WM_ENDCLICK

void Target::OnLButtonDown(UINT nFlags, CPoint point)
{//如果第一次按左擊
if(bSecond==FALSE)
{
//記錄按下的坐標
startPos=point;
//改變標記
bSecond=TRUE;
//恢復原來的屏幕
pDC->BitBlt(0,0,cxScreen,cyScreen,&MemDC,0,0,SRCCOPY);
//定義一個紅色的筆
CPen pen(PS_SOLID,2,RGB(255,0,0));
CPen* pOldPen;
//選入紅色的筆,並且記錄原來的筆
pOldPen=pDC->SelectObject(&pen);
//畫一個紅色的標記
pDC->MoveTo(point.x-10,point.y);
pDC->LineTo(point.x+10,point.y);
pDC->MoveTo(point.x,point.y-10);
pDC->LineTo(point.x,point.y+10);
//裝入原來的筆,用於在其他輔助線
pDC->SelectObject(pOldPen);
//刪除紅色的筆
::DeleteObject(pen.m_hObject);
//將帶有紅色標記的屏幕圖片保存到MemDC中
MemDC.BitBlt(0,0,cxScreen,cyScreen,pDC,0,0,SRCCOPY);
}
else//如果第二次單擊
{
//記錄終點坐標
endPos=point;
//調用計算長度的函數
Calculate();
//將當前DC和臨時內存DC刪除
pDC->DeleteDC();
MemDC.DeleteDC();
//撤銷窗口
DestroyWindow();
//向父窗口發送一個自定義的WM_ENDCLICK
pWndParent->PostMessage(WM_ENDCLICK);
}
CWnd::OnLButtonDown(nFlags, point);
}

重載鼠標右擊的消息處理函數,測量時按下右鍵就取消測量,向父窗口發送WM_CANCELCLICK自定義消息。

void Target::OnRButtonUp(UINT nFlags, CPoint point)
{
CWnd::OnRButtonUp(nFlags, point);
//刪除不用的DC
pDC->DeleteDC();
MemDC.DeleteDC();
DestroyWindow();
pWndParent->PostMessage(WM_CANCELCLICK);
}

Target類中的Calculate方法用於計算不同單位的長度。不同的單位主要取決於SetMapMode的參數。

void Target::Calculate()
{
//x、y用於記錄兩點坐標差
double x,y;
x=endPos.x-startPos.x;
y=endPos.y-startPos.y;
//默認情況下,計算的是像素的單位
iLen_p=(int)sqrt(x*x + y*y);
CDC* pDC;
pDC=GetDC();
//將當前窗口的映射模式改為MM_LOMETRIC,這樣邏輯坐標的單位為0.1mm
pDC->SetMapMode(MM_LOMETRIC);
POINT tmpStart=startPos;
POINT tmpEnd=endPos;
//將設備坐標改為邏輯坐標
pDC->DPtoLP(&tmpStart);
pDC->DPtoLP(&tmpEnd);
x=tmpEnd.x-tmpStart.x;
y=tmpEnd.y-tmpStart.y;
dLen_m=sqrt(x*x + y*y);
//映射模式改為MM_LOENGLISH的話,邏輯坐標的單位為0.01inch
pDC->SetMapMode(MM_LOENGLISH);
tmpStart=startPos;
tmpEnd=endPos;
pDC->DPtoLP(&tmpStart);
pDC->DPtoLP(&tmpEnd);
x=tmpEnd.x-tmpStart.x;
y=tmpEnd.y-tmpStart.y;
dLen_i=sqrt(x*x + y*y);
ReleaseDC(pDC);
}

這樣整個Target類就定義完了,接著再主對話框中調用該類,首先將Target類的對象作為自己的一個成員變量。在主對話框類中最重要的就是接受兩個自定義的消息WM_ENDCLICK和WM_CANCELCLICK,分別表示結束測量和取消測量。

具體程序詳見源程序,這裡就不再說明了。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved