由于项目需要,需要学习CGridCtrl控件的使用,测试控件时发现了一个问题,我无法将控件放在对话框的制定位置。

  该问题的原因很容易发现,其实就是GetWindowRec()函数和GetClientRect()函数在不同情况下返回的Rect含义不同,以及CWnd::Create()函数的特性造成的。

目的

  在Dialog上创建一个CGridCtrl控件,控件的位置由一个PictureBox控件(拖动到对话框模板上的控件)决定,即在PictureBox控件的位置上创建一个与其大小相同的CGridCtrl,下图中虚线内即为PictureBox。

  GetWindowRect和GetClientRect的异同-LMLPHP

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代表一个基于对话框工程的主对话框。

  GetWindowRect和GetClientRect的异同-LMLPHP

  如果调用该函数的CWnd有父窗口,即CWnd::GetParent()不返回null,那么GetWindowRect()返回的CRect的坐标为相对父窗口(包括标题栏、边框等)左上角的坐标,如下图所示,其中IDC_GRid是一个对话框控件的资源ID。  

  GetWindowRect和GetClientRect的异同-LMLPHP

CWnd::Create()函数的特性

  CWnd::Create()函数在不同的派生类中有不同的实现,其中一种形式为:

 BOOL CWnd::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)

即指定父窗口和在父窗口中的位置,加入要在一个对话框中创建一个Grid控件,采用如下代码:

   

     CRect rectGridWnd;
GetDlgItem(IDC_GRID)->GetWindowRect(&rectGridWnd); //获取Grid控件的位置,相对于整个Dlg
m_pGrid = new CGridCtrl(,);
m_pGrid->Create(rectGridWnd,this,IDC_GRID);

  那么呈现的效果如下:

  GetWindowRect和GetClientRect的异同-LMLPHP

  即CGridCtrl与PictureBox有了错位,原因在于CWnd::Create()中的CRect是以父窗口客户区的左上角为原点坐标,而GetWindowRect()是以父窗口(包括非客户区)的左上角为原点,所以造成了错位。

要想正确显示,需要采用以下的代码,即根据对话框的边框和标题的尺寸对rectGridWnd进行平移:

     // TODO: 在此添加额外的初始化代码
int captionHeight = ::GetSystemMetrics(SM_CYCAPTION);
int cxframe = GetSystemMetrics(SM_CXFRAME);
int cyframe = GetSystemMetrics(SM_CYFRAME); CRect rectGridWnd;
GetDlgItem(IDC_GRID)->GetWindowRect(&rectGridWnd);
rectGridWnd.OffsetRect(-cxframe,-cyframe-captionHeight);
m_pGrid = new CGridCtrl(,);
m_pGrid->Create(rectGridWnd,this,IDC_GRID);

  最终界面如下图所示:

  GetWindowRect和GetClientRect的异同-LMLPHP

05-07 09:23