- 在MFC中用CClientDC这个类来画图,添加OnLButtonUp的消息响应函数,程序如下:
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CClientDC dc(this); //在该句的 CClientDC 构造函数中用this,也就是当前CDrawView对象的指针 dc.MoveTo(m_ptOrigin); dc.LineTo(point); CView::OnLButtonUp(nFlags, point); }
画出来的效果是这样子的:可以看到,线条根本不可能超出CDrawView的客户区(也就是CDrawView的整个区域)
2. 我把CClientDC的构造函数参数改变一下,改成用GetParent(), 也就是取View窗口的父窗口,也就是框架窗口Frame的指针
发现效果是这样的: 画的线条可以超出View窗口,去到框架窗口
3、我找了一下原因,首先,看看这个CClientDC的构造函数源代码,如下:
CClientDC::CClientDC(CWnd* pWnd) // 1 in File---------WINGDI.CPP { ASSERT(pWnd == NULL || ::IsWindow(pWnd->m_hWnd)); // 2 if (!Attach(::GetDC(m_hWnd = pWnd->GetSafeHwnd()))) // 3 AfxThrowResourceException(); } CClientDC::~CClientDC() { ASSERT(m_hDC != NULL); ::ReleaseDC(m_hWnd, Detach()); }
4、注意画红线的三个地方,首先明确一点,CClientDC当中也有m_hWnd这个数据成员,CWnd当中也有m_hWnd这个句柄数据成员
class CClientDC : public CDC //in File-----------AFXWIN.H { DECLARE_DYNAMIC(CClientDC) // Constructors public: CClientDC(CWnd* pWnd); // Attributes protected: HWND m_hWnd; // Implementation public: virtual ~CClientDC(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif };
然后,当创建CDrawView对象完成以后,由于CDrawView这个类继承与CView,CView这个类继承自CWnd,而且只有一下几个类含有m_hWnd这个数据成员,如下图,所以CDrawView这个对象的基类不会含有m_hWnd这个数据成员,当CDrawView的当前对象创建完成以后,这个数据成员已经赋值完成,也就是已经把CDrawView这个窗口的句柄传递给了,CDrawView的m_hWnd这个句柄成员。
因此,看会CClientDC的构造函数, 由于当前CDrawView是CWnd的派生类,因此可以传递this指针给基类,其实也是一种隐式类型转换,派生类指针转化为基类指针,转化后的指针只能指向派生类的基类部分,因为不可能违背pWnd这个指针本身就是基类类型这个事实。然后用
pWnd->m_hWnd 来获取这个指针所指对象的数据成员,也就是派生类中的基类部分的m_hWnd, 由于m_hWnd已经被赋值,也就是当前CDrawView
对象窗口的句柄,所以就调用的就是CDrawView窗口句柄。
下面3处,这种用GetSafeHwnd()来调用主要是为了安全起见,确认一下,当前的指针是否为空,为空就没有句柄。
CClientDC::CClientDC(CWnd* pWnd) { ASSERT(pWnd == NULL || ::IsWindow(pWnd->m_hWnd)); // 2 if (!Attach(::GetDC(m_hWnd = pWnd->GetSafeHwnd()))) // 3 AfxThrowResourceException(); }
5、最后来解释一下画图出现的两种情况,第一种,用this,就是当前对象的地址,当然就是调用CDrawView的句柄,也可以说绑定了CDrawView的句柄;第二种
用GetParent()来获取CDrawView的父窗口的句柄,就是绑定了MainFram窗口的句柄,而由于MainFrame窗口的客户区包括工具栏,因此也就可以把线画到工具栏上。
谢谢阅读,请指正。