1. 在单文档中,MFC视类窗口是覆盖在框架窗口上的。
此时如果编写针对MainFrame的mouseClick事件,将不会有反应,框架窗口不能感应到鼠标消息.
2. MFC的消息映射机制
(1)在每个能接收和处理消息的类中,定义一个消息和消息函数对照表,即消息映射表.
(2)在消息映射表中,消息与对应的消息处理函数指针成对出现.某个类能处理的所有消息及其对应的消息处理函数的
地址都列在这个类所对应的静态表中.当有消息需要处理时,程序只要搜索该消息静态表,查看表中是否含有该消息,
就可知道该类能否处理此消息.如果能处理该消息,则同样依照静态表很容易找到并调用对应的消息处理函数.
(3)MFC消息映射机制是针对能接受消息和处理消息的类来定义对应的消息映射表,而不是由父类来定义所有消息对应
的虚函数,由子类来覆盖其函数实现,因为这样做会使程序背着一个很大的虚拟函数表的包袱运行,对内存是一种浪费.
MFC工程中一个消息映射在三处添加代码:
(1) CDrawView.h
//{{AFX_MSG(CDrawView)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
两个AFX_MSG注释宏(因为加了注释符)之间,afx_msg是限定符(也是宏),表明函数是一个消息响应函数的声明,如果是用户自定义的消息函数响应声明则在注释宏下, DECLARE_MESSAGE_MAP之上加写代码
(2) CDrawView.cpp
BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间,定义了CDrawView类的消息映射表,其中ON_WM_LBUTTONDOWN映射宏就是将鼠标左键按下消息(WM_LBUTTONDOWN)与一个消息响应函数(OnLButtonDown)关联.
BEGIN_MESSAGE_MAP(CDrawView, CView)
//{{AFX_MSG_MAP(CDrawView)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
如果添加自定义的消息映射,使用ON_MESSAGE(用户定义消息,消息响应函数名)无”;”结尾
(3) CDrawView.cpp函数实现
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) { // TOD Add your message handler code here and/or call default m_ptOrigin=m_ptOld=point; m_bDraw=TRUE; CView::OnLButtonDown(nFlags, point); }
3. 以下绘图程序,参考代码的注释可解决部分绘图问题
void CLesson3View::OnLButtonUp(UINT nFlags, CPoint point) { //调用SDK函数获取设备上下文句柄 HDC hdc; hdc = ::GetDC(m_hWnd);//这个m_hWnd是CWnd类中的保护成员, 保存窗口句柄,而CLesson3View类是从CWnd类继承来的
MoveToEx(hdc, m_ptnOrigin.x, m_ptnOrigin.y, NULL); LineTo(hdc, point.x, point.y); ::ReleaseDC(m_hWnd, hdc); // 在使用完设备上下文句柄后一定注意释放*/ /*使用CDC(MFC)关于作图对HDC一个封装*/ // CDC *pDc; // pDc = GetDC(); // pDc->MoveTo(m_ptnOrigin); // pDc->LineTo(point); // ReleaseDC(pDc); /*使用客户区绘图类,这个是比较常用的*/ //CClientDC dc(this);//CClientDC的构造函数,使用当前窗口句柄值做为参数 //CClientDC dc(GetParent());//得到关于父类窗口一个设备上下文 // dc.MoveTo(m_ptnOrigin); // dc.LineTo(point); // CClientDC类在构造时调用GetDC,然后在释放时又调用ReleaseDC所以不用手动释放 //利用MFC的CWindowDC绘图 //好处是可以访问整个窗口区域,包括框架窗口客户区和非客户区,桌面等, // CWindowDC dc(this); // CWindowDC dc(GetParent()); // dc.MoveTo(m_ptnOrigin); // dc.LineTo(point); // CWindowDC dc(GetDesktopWindow());//这个可以画到桌面上其它地方 // dc.MoveTo(m_ptnOrigin); // dc.LineTo(point); //以上所画的线条颜色都是黑色的,因为在设备描述表中使用默认的画笔(黑色), //要改变线条颜色则需要自己生成一个新的画笔对象, //将它选到设备描述表中,再画就使用新画笔来绘图 // CPen m_pen(PS_DASH, 2, RGB(255, 0, 0));//生成新的画笔 // CClientDC dc(this); // CPen *pOldPen = dc.SelectObject(&m_pen);//选择进设备描述表中 // dc.MoveTo(m_ptnOrigin); // dc.LineTo(point); // dc.SelectObject(pOldPen);//在使用完新的画笔后,要将原来的画笔重新选择时设备描述表 //使用画刷来填充矩形 // CBrush m_brush(RGB(120, 0, 23)); // CClientDC dc(this); // dc.FillRect(CRect(m_ptnOrigin, point), &m_brush); //使用位图画刷来填充矩形 //创建一个位图对象 // CBitmap m_bitmap; // m_bitmap.LoadBitmap(IDB_MyBitmap); // CBrush m_Brush(&m_bitmap); // CClientDC dc(this); // dc.FillRect(CRect(m_ptnOrigin, point), &m_Brush); //透明画刷 //首先使用Win32的API函数GetStockObject来获取一个NULL_BRUSH画刷 CClientDC dc(this); CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); //是静态成员函数,从句柄获取对象的指针 CBrush *pOldBrush = dc.SelectObject(pBrush); dc.Rectangle(CRect(m_ptnOrigin, point)); dc.SelectObject(pOldBrush); bIsMouseDown = FALSE; CView::OnLButtonUp(nFlags, point); }