孙鑫vc++ 第四课 笔记 MFC消息映射机制及CDC的使用

MFC消息映射机制的剖析,掌握设备描述表及其封装类CDC的使用

同样笔记也是没有整理过的,如果有错误,请你告诉我,谢谢^_^

1、mfc在后台维护了一个句柄,以及程序各个类的句柄映射表,当我门在某个窗口上操作产生消息,该消息携带一个该窗口的句柄,通过该句柄找到该对象的指针,由窗口类传至父类,再由父类通过消息循环调用一个CWnd::WindowProc()
WindowProc()是一个虚函数,每个从CWnd继承的子类都有这样一个虚函数
WindowProc()调用了一个OnWndMsg(),该函数完成了主要的消息映射的处理
OnWndMsg()会辨别消息的种类,随后根据传过来的隐含的this指针来到类.h消息宏(DECLARE_MESSAGE_MAP()之上)查找有无对应的消息处理函数原形的声明,然后到类.cpp中的消息映射表(BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP())中寻找有没有对应的处理函数,最终调用消息处理函数

2、每个继承于CWnd的窗口类中都维护着一个窗口句柄m_hWnd,要在该类中使用该类窗口的句柄,直接使用m_hWnd即可

3、用api画线
   HDC hdc=::GetDC(m_hWnd); //GetDC()要传入窗口句柄,返回dc句柄
   MoveToEx(hdc,oldpoint.x,oldpoint.y,NULL); //dc句柄,移至坐标,移动时上一坐标(不用就NULL)
   LineTo(hdc,point.x,point.y); //dc句柄,终点坐标
   ::ReleaseDC(m_hWnd,hdc); //窗口句柄,dc句柄,每次画完后一定要释放dc

4、mfc把所有的窗口操作都封装到cwnd类中,把所有做图的操作封装到cdc类中
   CDC : CObject

5、cdc类中也维护着一个与该dc相关的句柄m_hDc

6、用mfc 的cdc类画线,同样也是4句,简单了许多,没有了传递窗口句柄m_hDc的操作,因为类内有维护
   CDC *pDC=GetDC();//CWnd::GetDC(),原CView没有这个函数,当然就用父类的了,其中也传递了m_hDc
   pDC->MoveTo(oldpoint);//MoveTo()是cdc的成员函数
   pDC->LineTo(point);
   ReleaseDC(pDC);  //这里当然也是父类cwnd的了

7、CClientDC : CDC : CObject
   CClientDC 类在构造函数和析构函数中分别调用了GetDC()和ReleaseDC()

8、用CClientDC画线,更简单了
   CClientDC dc(this);  //传入窗口类指针,构造函数原形:CClientDC(CWnd* pwnd)
   dc.MoveTo(oldpoint);
   dc.LineTo(point);

   注意不同的类的构造函数的参数,有的是窗口句柄HWND,有的是类对象指针CWnd*,你想到了什么?
   this 换成 getparent()呢,当然就是在框架客户区内画图了

9、CWindowDC : CDC : CObject
   CWindowDC 类在构造函数和析构函数中分别调用了GetWindowDC()和ReleaseDC()
   CWindowDC 可以访问整个屏幕,包括客户区和非客户区,即标题栏等

10、用CWindowDC画线
   CWindowDC dc(this);  //传入窗口类指针,构造函数原形:CWindowDC(CWnd* pwnd)
   dc.MoveTo(oldpoint);
   dc.LineTo(point);
  
   这样,参数换成getparent()时,就能画到标题栏去了
         参数换成getdesktopwindow()时,就能画到窗口外面去了
  
   sdk函数返回的一般是句柄,::Get****() ,使用api相应就配合使用sdk函数
   mfc函数返回的一般是指针,Get****() ,使用mfc相应就配合使用mfc函数

11、设备描述表中缺省的画笔是黑色的
   CPen 最常用的一个构造函数是CPen(类型,宽度,颜色);
  
   CDC::SelectObject                 构造函数,看了你是不是明白了很多东西
   CPen* SelectObject(CPen* pPen);  //返回的是先前的画笔,这样可以保存原画笔以用于还原
   CBrush* SelectObject(CBrush* pBrush);
   CBitmap* SelectObject(CBitmap* pBitmap);
   virtual CFont* SelectObject(CFont* pFont);

   用自己的颜色画线
   CClineDC dc(this);
   CPen pen(PS_SOLID,1,RGB(255,0,0));  //构造画笔
   CPen *pOldPen = dc.SelectObject(&pen);  //将新画笔选入dc,替换原画笔,用返回值保存原画笔
   dc.MoveTo(oldpoint);
   dc.LineTo(point);
   dc.SelectObject(pOldPen);  //还原原画笔
  
12、画刷用来填充一个矩形
   CBrush::CBrush    构造函数
   CBrush(COLORREF crColor);
   CBrush(int nIndex, COLORREF crColor);
   CBrush(CBitmap* pBitmap);

   CBrush brush(RGB(255,0,0));
   CClienDC dc(this);
   dc.FillRect(CRect(oldpoint,point),&brush);   //FillRect()用画刷填充矩形

   因为是用指定的画刷填充指定的矩形区域,所以并不需要把画刷选入设备描述表dc当中?什么?

   用位图画刷填充矩形
   CBitmap bitmap;
   bitmap.LoadBitmap(IDB_BITMAP1);
   CBrush brush(&bitmap);
   CClienDC dc(this);
   dc.FillRect(CRect(oldpoint,point),&brush);   //FillRect()用画刷填充矩形
   结果位图在指定范围内平铺填充,注意,这里用的都是画刷的“对象”及其“指针”

   CBitmap::CBitmap
   CBitmap(); //构造函数只有一个,没有任何参数,只能在初始化参数中对其初始化
   LoadBitmap(....);等等,有的类构造函数可以初始化,有的要用初始化函数初始化,不同,注意

   CRect::CRect
   CRect();
   CRect(int l,int t,int r,int b);
   CRect(const RECT& srcRect);
   CRect(LPCRECT lpSrcRect);
   CRect(POINT point, SIZE size);
   CRect(POINT topLeft, POINT bottomRight);

13、透明画刷
   CBrush并没有提供透明画刷构造函数,所以要用其他办法
   HGDIOBJ GetStockObject(int fnObject);//该sdk函数可以获取画刷,画笔,字体等等句柄,其中包括有黑、白、透明画刷的句柄,可是mfc绘图函数中用的是画刷对象或者指针,怎么办呢
   另外,GetStockObject()获取的句柄类型是HGDIOBJ,如何将该句柄转化为cdc用的类型HBRUSH呢,强制转换

   CBrush::FromHandle  //画刷类中有一个成员函数可以做到这一点
   static CBrush* PASCAL FromHandle(HBRUSH hBrush);   //可以把一个画刷句柄返回为一个画刷指针

   CClienDC dc(this);  
   CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
   CBrush *pOldBrush=dc.selectObject(pBrush);  //将画刷选入dc,替换原画刷,保存原画刷指针
   dc.Rectangle(oldpoint,point);   //Rectangle()画矩形
   dc.selectObject(pOldBrush);

   在上上上面的例子中,我们并没有将画刷选入dc中,是因为调用的dc使用画刷的绘图函数中已经将画刷选入其中
   dc.FillRect(CRect(oldpoint,point),&brush); 
   但这里或者上上上上上上面的例子需要用selectObject()选入画刷,是因为函数中没有指定画刷
   dc.Rectangle(oldpoint,point);

   我靠,看到这里,我终于明白了!!!

14、奇怪的调用方法
   CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
   以前用过的类成员调用方法,生成实例对象,用. ,生成对象指针并指向某一空间,用->
   这个方法可以用于静态成员,但不能用于非静态成员,因为静态成员不属于任何一个实例对象,它只属于所属的类,当类被加载的时候,该静态成员就已经分配了代码区了,而类内非静态成员只属于某个对象,因此在对象没有建立起来,没有实例化的时候,静态成员是无法使用非静态成员的,所以,如果在静态成员函数中使用非静态成员对象,就会报错
   反过来,非静态成员函数是可以调用静态成员的,静态成员变量可以被访问,但静态成员变量定义时必须初始化
   但如果访问了非静态成员的静态成员函数没有在主程序中被调用,则不会报错
   ===》一个对象一段代码能用,必须在内存中存在了该对象或代码
  

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值