由於項目需要,需要學習CGridCtrl控件的使用,測試控件時發現了一個問題,我無法將控件放在對話框的制定位置。
該問題的原因很容易發現,其實就是GetWindowRec()函數和GetClientRect()函數在不同情況下返回的Rect含義不同,以及CWnd::Create()函數的特性造成的。
目的
在Dialog上創建一個CGridCtrl控件,控件的位置由一個PictureBox控件(拖動到對話框模板上的控件)決定,即在PictureBox控件的位置上創建一個與其大小相同的CGridCtrl,下圖中虛線內即為PictureBox。
GetClientRect()
獲取窗口客戶區的大小,返回的CRect的左上角坐標永遠為(0,0)
GetWindowRect()
首先說一說GetWindowRect()在幫助文檔中的介紹是:The dimensions are given in screen coordinates relative to the upper-left corner of the display screen. The dimensions of the caption, border, and scroll bars, if present, are included。就是GetWindowRect()返回的是相對屏幕左上角的的坐標,包括標題欄、邊框和滾動條。
在實際測試中我發現,如果調用該函數的CWnd沒有父窗口,即CWnd::GetParent()返回null,那么GetWindowRect()返回的CRect的左上角坐標永遠為(0,0),如圖所示,其中this代表一個基於對話框工程的主對話框。
如果調用該函數的CWnd有父窗口,即CWnd::GetParent()不返回null,那么GetWindowRect()返回的CRect的坐標為相對父窗口(包括標題欄、邊框等)左上角的坐標,如下圖所示,其中IDC_GRid是一個對話框控件的資源ID。
CWnd::Create()函數的特性
CWnd::Create()函數在不同的派生類中有不同的實現,其中一種形式為:
1 BOOL CWnd::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)
即指定父窗口和在父窗口中的位置,加入要在一個對話框中創建一個Grid控件,采用如下代碼:
1 CRect rectGridWnd; 2 GetDlgItem(IDC_GRID)->GetWindowRect(&rectGridWnd); //獲取Grid控件的位置,相對於整個Dlg 3 m_pGrid = new CGridCtrl(5,5); 4 m_pGrid->Create(rectGridWnd,this,IDC_GRID);
那么呈現的效果如下:
即CGridCtrl與PictureBox有了錯位,原因在於CWnd::Create()中的CRect是以父窗口客戶區的左上角為原點坐標,而GetWindowRect()是以父窗口(包括非客戶區)的左上角為原點,所以造成了錯位。
要想正確顯示,需要采用以下的代碼,即根據對話框的邊框和標題的尺寸對rectGridWnd進行平移:
1 // TODO: 在此添加額外的初始化代碼 2 int captionHeight = ::GetSystemMetrics(SM_CYCAPTION); 3 int cxframe = GetSystemMetrics(SM_CXFRAME); 4 int cyframe = GetSystemMetrics(SM_CYFRAME); 5 6 CRect rectGridWnd; 7 GetDlgItem(IDC_GRID)->GetWindowRect(&rectGridWnd); 8 rectGridWnd.OffsetRect(-cxframe,-cyframe-captionHeight); 9 m_pGrid = new CGridCtrl(5,5); 10 m_pGrid->Create(rectGridWnd,this,IDC_GRID);
最終界面如下圖所示: