+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MFC如何擷取控件在對話框上的位置坐标
2010-09-13 20:20
本來希望的效果是在對話框上設定兩個picture控件,分别顯示兩幅圖像,然後将兩幅圖像中的相似部分利用一條直線連接配接起來。要實作這樣的效果需要知道相似位置在這兩幅圖中的坐标以及這兩個控件在對話框上的坐标,然後通過加減運算就可以得到圖像上的相似區域在對話框的坐标,直接将這兩個坐标用直線連接配接就可以了。
為此,如何獲得控件在對話框上的坐标是關鍵問題。編寫了如下的測試小程式,目的是将兩個picture控件中的點用直線連接配接起來,比較直覺的是picture控件的四個角,是以程式中是将控件的拐角連接配接起來。首先在對話框上并排放置兩個同樣大小的picture控件,将他們的辨別分别設成IDC_LEFT和IDC_RIGHT,然後添加兩個編輯框用于顯示picture控件的大小,給這兩個編輯框添加相應的資料成員m_row和m_colume。添加一個按鈕用于連接配接picture控件中的點,為這個按鈕添加成員函數OnMatch() 。
void CControlDlg::OnMatch()
{
// TODO: Add your control notification handler code here
CRect rectL,rectR;
GetDlgItem(IDC_LEFT)->GetWindowRect(&rectL);//擷取控件相對于螢幕的位置
ScreenToClient(rectL);//轉化為對話框上的相對位置
GetDlgItem(IDC_RIGHT)->GetWindowRect(&rectR);//擷取控件相對于螢幕的位置
ScreenToClient(rectR);//轉化為對話框上的相對位置
m_row=rectL.bottom-rectL.top;
m_colume=rectL.right-rectL.left;
UpdateData(FALSE);
CClientDC dc(this);
dc.MoveTo(rectL.left,rectL.top);
dc.LineTo(rectR.right,rectR.bottom);
dc.MoveTo(rectL.right,rectL.top);
dc.LineTo(rectR.left,rectR.bottom);
dc.MoveTo(rectL.left+m_colume/2,rectL.top+m_row/2);//連接配接兩個控件中心點
dc.LineTo(rectR.left+m_colume/2,rectR.top+m_row/2);
}
MFC中,如何獲得對話框控件相對于父視窗(對話框視窗)的位置
建立者: nottoobad
最後修改: 2010-11-29 21:07:54
狀态: 公開
在MFC中,如何獲得對話框控件相對于父視窗(對話框視窗)的位置:
CRect r;
pWnd->GetWindowRect(&r);
這樣獲得的r是控件相對于螢幕的坐标,然後用ScreenToClient(&r)就可以獲得控件相對于父視窗的坐标。如果用GetClientRect(&r)的話,r.left和r.top始終是0,得到的并不是實際坐标。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
以用GetSystemMetrics函數可以擷取系統分辨率,但這隻是其功能之一,GetSystemMetrics函數隻有一個參數,稱之為「索引」,這個索引有75個辨別符,通過設定不同的辨別符就可以擷取系統分辨率、窗體顯示區域的寬度和高度、滾動條的寬度和高度。
為了使使GetSystemMetrics的功能,我們以擷取系統分辨率為例,并将其中的兩個值用TextOut輸出到窗體中。
第一步:用GetSystemMetrics擷取螢幕的寬度和高度
int x, y;
x = GetSystemMetrics(SM_CXSCREEN); //螢幕寬度
y = GetSystemMetrics(SM_CYSCREEN); //螢幕高度
擷取窗體顯示區域大小
已我現在的了解,擷取窗體顯示區域大小有三種方法。
第一種方法:使用GetSystemMetrics函數
GetSystemMetrics(SM_CXFULLSCREEN); //擷取最大化窗體的顯示區域寬度
GetSystemMetrics(SM_CYFULLSCREEN); //擷取最大化窗體的顯示區域高度
下面是GetSystemMetrics函數參數nIndex的定義:
SM_ARRANGE 傳回是否預備最小化.
SM_CLEANBOOT 傳回系統啟動方式:
0 正常啟動
1 安全模式啟動
2 網絡安全模式啟動
SM_CMOUSEBUTTONS 傳回值為系統支援的滑鼠鍵數,傳回0,則系統中沒有安裝滑鼠。
SM_CXBORDER,
SM_CYBORDER 傳回以相素值為機關的Windows視窗邊框的寬度和高度,如果Windows的為3D形态,則
等同于SM_CXEDGE參數
SM_CXCURSOR,
SM_CYCURSOR 傳回以相素值為機關的标準光标的寬度和高度
SM_CXDLGFRAME,
SM_CYDLGFRAME 等同與SM_CXFIXEDFRAME and SM_CYFIXEDFRAME
SM_CXDOUBLECLK,
SM_CYDOUBLECLK 以相素值為機關的輕按兩下有效的矩形區域
SM_CXEDGE,SM_CYEDGE 以相素值為機關的3D邊框的寬度和高度
SM_CXFIXEDFRAME,
SM_CYFIXEDFRAME 圍繞具有标題但無法改變尺寸的視窗(通常是一些對話框)的邊框的厚度
SM_CXFRAME,SM_CYFRAME 等同于SM_CXSIZEFRAME and SM_CYSIZEFRAME
SM_CXFULLSCREEN,
SM_CYFULLSCREEN 全螢幕視窗的視窗區域的寬度和高度
SM_CXHSCROLL,
SM_CYHSCROLL 水準滾動條的高度和水準滾動條上箭頭的寬度
SM_CXHTHUMB 以相素為機關的水準滾動條上的滑動塊寬度
SM_CXICON,SM_CYICON 系統預設的圖示的高度和寬度(一般為32*32)
SM_CXICONSPACING,
SM_CYICONSPACING 以大圖示方式檢視Item時圖示之間的間距,這個距離總是大于等于
SM_CXICON and SM_CYICON.
SM_CXMAXIMIZED,
SM_CYMAXIMIZED 處于頂層的最大化視窗的預設尺寸
SM_CXMAXTRACK,
SM_CYMAXTRACK 具有可改變尺寸邊框和标題欄的視窗的預設最大尺寸,如果視窗大于這個
尺寸,視窗是不可移動的。
SM_CXMENUCHECK,
SM_CYMENUCHECK 以相素為機關計算的菜單選中标記位圖的尺寸
SM_CXMENUSIZE,
SM_CYMENUSIZE 以相素計算的菜單欄按鈕的尺寸
SM_CXMIN,SM_CYMIN 視窗所能達到的最小尺寸
SM_CXMINIMIZED,
SM_CYMINIMIZED 正常的最小化視窗的尺寸
SM_CXMINTRACK,
SM_CYMINTRACK 最小跟蹤距離,當使用者拖動視窗移動距離小于這個值,視窗不會移動。
SM_CXSCREEN,
SM_CYSCREEN 以相素為機關計算的螢幕尺寸。
SM_CXSIZE,SM_CYSIZE 以相素計算的标題欄按鈕的尺寸
SM_CXSIZEFRAME,
SM_CYSIZEFRAME 圍繞可改變大小的視窗的邊框的厚度
SM_CXSMICON,
SM_CYSMICON 以相素計算的小圖示的尺寸,小圖示一般出現在視窗标題欄上。
M_CXVSCROLL,
SM_CYVSCROLL 以相素計算的垂直滾動條的寬度和垂直滾動條上箭頭的高度
SM_CYCAPTION 以相素計算的普通視窗标題的高度
SM_CYMENU 以相素計算的單個菜單條的高度
SM_CYSMCAPTION 以相素計算的視窗小标題欄的高度
SM_CYVTHUMB 以相素計算的垂直滾動條中滾動塊的高度
SM_DBCSENABLED 如果為TRUE或不為0的值表明系統安裝了雙位元組版本的USER.EXE,為FALSE或0則不是。
SM_DEBUG 如果為TRUE或不為0的值表明系統安裝了debug版本的USER.EXE,為FALSE或0則不是。
SM_MENUDROPALIGNMENT 如果為TRUE或不為0的值下拉菜單是右對齊的否則是左對齊的。
SM_MOUSEPRESENT 如果為TRUE或不為0的值則安裝了滑鼠,否則沒有安裝。
SM_MOUSEWHEELPRESENT 如果為TRUE或不為0的值則安裝了滾輪滑鼠,否則沒有安裝。(Windows NT only)
SM_SWAPBUTTON 如果為TRUE或不為0的值則滑鼠左右鍵交換,否則沒有。
(2010-05-03 02:58:24)
标簽:
在使用Invalidate(TRUE)進行視窗重繪時,總是會遇到閃屏的問題。
一開始以為是繪圖速度過慢照成的,但在對繪圖時間做了一個測試之後發現,即使整個繪圖過程隻持續了幾個毫秒,還是會看見很明顯的閃爍,是以時間并不是造成閃爍的決定性因素。
那到底是什麼原因呢?現在來看看Invalidate(TRUE)都幹了些什麼。其實,它隻是間接向消息隊列添加了WM_ERASEBKGND和WM_PAINT兩個消息。但是,如果使用Invalidate(FALSE)的話,則隻有WM_PAINT消息産生,這時是不會有任何閃爍的。
現在看來,閃爍似乎是由WM_ERASEBKGND消息産生的,事實上,的确與它有關。那WM_ERASEBKGND有幹了什麼呢?WM_ERASEBKGND消息由OnEraseBkgnd()消息處理函數響應,它的作用就是重繪客戶區背景。我們可以通過向工程裡添加WM_ERASEBKGND這個消息,然後在重寫的消息處理函數中将傳回語句修改為return TRUE來屏蔽這一功能,這樣做的好處是這時不會重繪背景了,壞處是這時背景也不會被擦出來。
好像還沒有說到真實原因,其實真正的原因就隐含在其中。現在來做一個實驗,分别嘗試一下快速的眨眼和慢速的眨眼,你會發現快速眨眼時我們會感覺眼前的黑色一閃而過,而慢速眨眼時,則會覺得整個過程是連續的,沒有什麼異樣。其實閃爍也就是這麼回事,即多張不連續圖像的快速切換。這裡有三個條件,多張和快速和不連續,而且需要同時具備才會發生閃爍。如果隻是兩張,隻會感覺到突變,還談不上閃爍;如果頻率慢的話,也相當于兩張圖像的情況了;最後如果是連續圖像的話,那就像是看電影,平穩的過渡也不會讓人覺得不适。
知道了這些,接下來就可以做決策了。
解決方案:
使用Invalidate(FALSE),添加WM_ERASEBKGND消息處理函數或者局部重新整理三者選其一,都是可以解決問題的。它們的都是通過除去圖像不連續這一因素來達到目的的。
另外,要說的是GDI的BitBlt()函數是及其高效的,一次操作所需要的時間隻有幾到十幾個微秒,是以我們可以放心的使用它,而不用擔心任何效率問題。不過相對于BitBlt()來說StretchBlt()就要慢的多,大概是幾十倍的差别。
還有就是一般的繪圖工作都是先繪制在一個緩沖區上,然後再一次拷貝到螢幕上。
有時,當我們需要利用閃爍的效果的話,也是可以通過多張圖像的快速切換來做到,在這裡我們也将兩張圖像的重複切換了解為多張圖像。