原文地址: https://blog.csdn.net/ling_xiao007/article/details/51720890
3.1 MFC消息映射机制
首先新建一个单文档类型的MFC APPWizard(exe)工程,取名MyMFCApp。试完成左键消息的捕捉。在
3.1.1 ClassWizard(类向导)
项目->类向导。
有命令、消息、虚函数、成员变量、方法五个选项卡,此外,还可以添加类。
3.1.2 消息映射机制
用ClassWizard添加一个LButtonDown的响应函数,在源文件会增加以下代码。
1) 消息响应函数原型
在MyMFCAppView.h中
// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg voidOnLButtonDown(UINT nFlags, CPoint point);
2) ON_WM_LBUTTONDOWN消息映射宏
在MyMFCAppView.cpp中
BEGIN_MESSAGE_MAP(CMyMFCAppView, CView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT,&CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
在BEGAIN_MESSAGE_MAP到END_MESSAGE_MAP()两个宏之间定义了CMyMFCApp类的消息映射表。作用是把WM_LBUTTONDOWN与OnLButtonDown关联。
3) 消息响应函数的定义
void CMyMFCAppView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
MessageBox("Left button down!");
CView::OnLButtonDown(nFlags, point);
}
在windows应用程序中,消息被放到消息队列,应用程序GetMessage取消息,DispatchMessage交给操作系统,后者调用应用程序的窗口过程函数,WndProc进行处理。该函数用switch-case进行判别并分类处理。
而MFC程序中,只要定义了与消息有关的三处信息,就可以实现消息的响应。
当收到一个消息,消息的第一个参数指明了与哪个窗口句柄相关,通过对照表,可以找到与之相关的C++对象指针。把这个指针传递给应用程序框架类的基类,后者调用一个名为WindowProc的函数。该函数在WinCore.cpp中。该函数是一个虚函数。调用了OnWndMsg函数。
LRESULTCWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
//OnWndMsg does most of the work, except for DefWindowProc call
LRESULT lResult = 0;
if (!OnWndMsg(message, wParam, lParam, &lResult))
lResult = DefWindowProc(message, wParam,lParam);
return lResult;
}
OnWndMsg函数的处理过程:(1)首先判断消息是否有消息响应函数。判断方法是在相应窗口类中查找所需的消息响应函数。因为传递给WindowProc函数的事窗口子类指针,所以,OnWndMsg函数回到相应的子类头文件中查找,看看DECLARE_MESSAGE_MAP()宏上是否有消息响应函数的声明;再到子类源文件看看是否有相应的消息映射宏;(2)有消息响应函数则响应,没有则交给基类处理。
3.2 绘制线条
在CMyMFCAppView类添加一个类型为CPoint的m_ptOrigin私有成员。
在CMyMFCAppView.cpp初始化为0。
m_ptOrigin = 0;
在OnLButtonDown函数中保存鼠标按下点的信息。
m_ptOrigin = point;
WM_LBUTTONUP消息添加响应函数。
(1)利用Platform SKD函数
HDChdc;
hdc = ::GetDC(m_hWnd);
::MoveToEx(hdc, m_ptOrigin.x, m_ptOrigin.y, NULL);
::LineTo(hdc, point.x, point.y);
::ReleaseDC(m_hWnd, hdc);
(2)利用MFC CDC类
CDC*pDC = GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);
(3)利用CClientDC类
CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
(4)利用CWindowDC类
CWindowDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
(5)在桌面窗口划线
CWindowDCdc(GetDesktopWindow());
ClientToScreen(&m_ptOrigin);
dc.MoveTo(m_ptOrigin);
ClientToScreen(&point);
dc.LineTo(point);
因为客户区与桌面坐标转换问题的存在,需调用ClientToScreen函数。
(6)绘彩色线条
CPenpen(PS_SOLID, 5, RGB(255, 0, 0));
CClientDC dc(this);
CPen*pOldPen = dc.SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(pOldPen);
当构造一个GDI对象后,该对象并不会立即生效,必须通过SelectObject函数选入设备描述表,它才会在以后的绘制操作中生效。在完成绘图操作之后,都要利用SelectObject把先前的GDI对象选入设备描述表,以便使其恢复到先前的状态。
3.3使用画刷画图
(1)绘制矩形填充块
CBrush brush(RGB(255, 0, 0));
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin,point), &brush);
(2)绘制位图填充块
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP1);
CBrush brush(&bmp);
CClientDC dc(this);
dc.FillRect(CRect(m_ptOrigin,point), &brush);
(3)透明画刷
CPen pen(PS_SOLID, 5, RGB(255, 0, 0));
CClientDC dc(this);
//CBrush*pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//CBrush*pOldBrush = (CBrush*)dc.SelectObject(pBrush);
CBrush* pOldBrush =(CBrush*)dc.SelectStockObject(HOLLOW_BRUSH);
CPen* pOldPen = dc.SelectObject(&pen);
dc.Rectangle(CRect(m_ptOrigin, point));
dc.SelectObject(pOldPen);
3.4 连续线条等
(1)连续线条
添加WM_MOUSEMOVE响应函数到View类中。补充函数。
CClientDC dc(this);
if (nFlags == MK_LBUTTON)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin = point;
}
也可以添加私有成员BOOL m_bDraw到View类,View构造时赋值为FALSE,WM_LBUTTONDOWN为TRUE,
CClientDC dc(this);
if (m_bDraw == TRUE)
{
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_bDraw = FALSE;
m_ptOrigin = point;
}
(2)扇形效果线条
添加私有成员CPoint m_btEnd到View类,OnLButtonDown赋值point。
if (nFlags == MK_LBUTTON)
{
dc.MoveTo(m_ptOrigin);
/* 3.4.1 连续线条
//dc.LineTo(point);
//m_ptOrigin = point;
*/
// 3.4.2扇形
dc.LineTo(m_ptEnd);
m_ptEnd = point;
}
(3)橡皮筋技术
//通过取反异或的模式擦除旧线条
dc.SetROP2(R2_NOTXORPEN);
dc.MoveTo(m_ptOrigin);dc.LineTo(m_ptEnd);
//绘制新线条
m_ptEnd = point;
dc.MoveTo(m_ptOrigin);dc.LineTo(m_ptEnd);