🔳🔳 绘制线条 、画刷绘图、绘制连续线条、绘制扇形效果的线条
🔳🔳 插入符【文本插入符|图形插入符】、窗口重绘、路径、字符输入【设置字体|字幕变色】
🔳🔳 菜单命令响应函数、菜单命令的路由、基本菜单操作、动态菜单操作、电话本实例
🔳🔳 对话框的创建与显示、动态创建按钮、控件的访问【控件调整|静态文本控件|编辑框控件】、对话框伸缩功能、输入焦点的传递、默认按钮的说明
🔳🔳修改应用程序窗口的外观【窗口光标|图标|背景】、模拟动画图标、工具栏编程、状态栏编程、进度栏编程、在状态栏上显示鼠标当前位置、启动画面
🔳🔳设置对话框、颜色对话框、字体对话框、示例对话框、改变对话框和控件的背景及文本颜色、位图显示

文章目录
一、绘制线条
在创建的单文档程序中实现绘画线条功能。
1)在view类中添加单击鼠标左键事件WM_LBUTTONDOWN。
自动生成的类如下:
void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CView::OnLButtonDown(nFlags, point);
}
生成的两个参数,其中第二个参数是CPoint类型,表示一个点。当鼠标按下后,鼠标单击处的坐标点由此参数传递给OnLButtonDown这个响应函数。
2)在消息响应函数中保存CPoint点的信息。
需要在类视图中添加一个成员变量:
①通过在类视图选项卡上用鼠标右键单击该类,并从弹出的快捷菜单中选择添加——>添加变量菜单命令。
②通过在类视图选项卡上用鼠标右键单击该类,并从弹出的快捷菜单中选择类向导——>成员变量——>添加自定义。
在View的构造函数中初始化这个值。
CMFCTestView::CMFCTestView() noexcept
{
// TODO: 在此处添加构造代码
m_ptPoint.x = 0;
m_ptPoint.y = 0;
}
在消息响应函数中保存鼠标按下点的信息。
void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptPoint = point;
CView::OnLButtonDown(nFlags, point);
}
3)绘制线段的终点。
终点是鼠标左键弹起来时获得。对WM_LBUTTONUP消息进行响应。
1.1 利用SDK全局函数实现画线功能
进行绘图操作,必须获得一个设备描述表(DC)。
1)通过GetDC()获得当前窗口的设备描述表。
CWnd类有一个成员变量(m_hWnd)用于保存窗口句柄。
2)调用MoveToEx()函数将当前位置移动到所需要绘制的线段起点处。
第一个参数:设备描述表的句柄;
第二个参数:新位置的X坐标;
第三个参数:新位置的Y坐标;
第四个参数:指向POINT结构体的指针,用于保存移动操作前鼠标的位置坐标。
3)调用LineTo()函数绘制一条到指定终点的线。
第一个参数:设备描述表的句柄;
第二个参数:终点X坐标;
第三个参数:终点Y坐标。
4)绘图结束后,释放设备描述表资源。调用ReleaseDC函数。
void CMFCTestView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//获得窗口设备描述表
HDC hdc;
//冒号说明是全局SDK函数
hdc = ::GetDC(m_hWnd);
//移动到线条的起点
MoveToEx(hdc, m_ptPoint.x, m_ptPoint.y, NULL);
//画线
LineTo(hdc, point.x, point.y);
//释放设备描述表
//冒号说明是全局SDK函数
::ReleaseDC(m_hWnd, hdc);
CView::OnLButtonUp(nFlags, point);
}
1.2 利用MFC的CDC类实现画线功能
MFC为我们提供了一个设备描述表的封装类CDC,该类封装了所有与绘图相关的操作。该类提供了一个数据成员m_hDC,用于保存与CDC类相关的DC句柄。
void CMFCTestView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//获取当前窗口的设备描述表对象的指针
CDC* pDC= GetDC();
//移动到线条的起点
pDC->MoveTo(m_ptPoint);
//画线
pDC->LineTo(point);
//释放设备描述表
ReleaseDC(pDC);
CView::OnLButtonUp(nFlags, point);
}
1.3 利用MFC的CClientDC类实现画线功能
利用MFC提供的CClientDC类实现画线功能。
CClientDC派生于CDC类,当CClientDC对象构造时,内部会调用GetDC函数,获得一个设备描述表对象;并且在析构时调用ReleaseDC函数。
void CMFCTestView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//===============CClientDC===================
CClientDC dc(this);
dc.MoveTo(m_ptPoint);
dc.LineTo(point);
//===========================================
CView::OnLButtonUp(nFlags, point);
}
1.4 利用MFC的CWindowDC类实现画线功能
CWindowDC派生于CDC类,并在构造时调用GetWindowDC函数获得相应的设备描述表对象,在析构时调用ReleaseDC函数释放资源。
CWindowDC对象可以访问整个窗口区域,包括框架窗口的客户区和非客户区。
void CMFCTestView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//===============CWindowDC===================
CWindowDC dc(this);
dc.MoveTo(m_ptPoint);
dc.LineTo(point);
//===========================================
CView::OnLButtonUp(nFlags, point);
}
当把this指针换成指向视图类父窗口的指针:
CWindowDC dc(GetParent());
发现此时线条可以画到工具栏和菜单栏上。
1.5 在桌面窗口中画线
若获得一个与桌面窗口相关的设备描述表,就可以在桌面窗口中绘图。CWnd类的GetDesktopWindow成员函数可以获得Windows桌面窗口的句柄。
void CMFCTestView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//===============窗口桌面画线===================
CWindowDC dc(GetDesktopWindow());
dc.MoveTo(m_ptPoint);
dc.LineTo(point);
//================================================
CView::OnLButtonUp(nFlags, point);
}
1.6 绘制彩色线条
上面绘制的线条都是黑色,是因为设备描述表中有一个默认的黑色画笔。
若绘制其他颜色:需要创建一个特定颜色的画笔,然后将此画笔选入设备描述表中。
1)MFC提供的类CPen创建画笔对象。
构造函数如下:
CPen(int nPenStyle,int nWidth,COLORREF crColor);
参数一:指定笔的线型(实线PS_SOLID,虚线PS_DASH,点线PS_DOT等),画笔宽度小于等于1时,虚线线型才有效;
参数二:指定笔的线宽;
参数三:指定笔的颜色,这个参数是COLORREEF类型,利用RGB这个宏可以创建这种类型的值。
RGB声明如下:
COLORREF RGB(BYTE bRed, BYTE bGreen, BYTE bBlue)
;
RGB宏三个参数,分别代表红,绿,蓝三种颜色得值。取值范围0~255。其中(0,0,0)代表黑色;(255,255,255)代表白色。
2)构造一个GDI对象,该对象并不会立即生效,必须选入设备描述表。
通过SelectObject函数可以实现将GDI对象选入设备描述表,并返回指向先前被选对象的指针。目的:为了完成当前绘图操作后,还原设备描述表。当绘图结束后,恢复到原来的画笔颜色。
一般情况下,完成绘图操作之后,都要利用SelectObject函数将先前的GDI对象选入设备描述表,以便将其恢复到原先的状态。
void CMFCTestView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//===============更改绘图的颜色===================
//创建一个宽度为9的红色的实线型画笔
CPen pen(PS_SOLID, 9, RGB(255, 0, 0));
//获取当前窗口的设备描述表
CClientDC dc(this);
//将自己设置的画笔选入设备描述表
CPen* pOldPen = dc.SelectObject(&pen);
//画线
dc.MoveTo(m_ptPoint);
dc.LineTo(point);
//设备表的原画笔恢复
dc.SelectObject(pOldPen);
//===========================================
CView::OnLButtonUp(nFlags, point);
}
二、使用画刷绘图
MFC提供了一个CBrush类,可以用于创建画刷对象。画刷通常用于填充一块区域。
2.1 简单画刷
1)创建一个画刷。
2)创建设备描述表对象。
3)调用设备描述表的FillRect填充一块矩形区域,鼠标拖动的过程的起点和终点构造矩形。
CRect构造矩形区域。
CRect(POINT topLeft,POINT bottomRight);
CDC类的成员函数FillRect填充所有的矩形区域。包括左边和上边的边界,但不填充右边和底部边界。
void FillRect(LPCRECT lpRect, CBrush* pBrush);
lpRect: 指向一个RECT结构体或者CRect对象的指针,该结构体包含要填充的矩形的逻辑坐标。
pBrush: 指向用于填充矩形的画刷对象的指针。
//===============画刷绘制矩形===================
//创建红色画刷
CBrush brush(RGB(255, 0, 0));
//获取当前窗口的设备描述表
CClientDC dc(this);
//利用红色画刷填充鼠标拖曳过程中的形成的矩形区域
dc.FillRect(CRect(m_ptPoint, point), &brush);
//===========================================
2.2 位图画刷
CBrush类有个构造函数:
CBrush (CBitmap* pBitmap);
创建CBitmap对象时,需要调用一个初始化函数初始化位图对象。CBitmap类提供多个初始化函数:LoadBitmap、CreateBitmap、CreateBitmapIndirect等。
BOOL LoadBitmap(LPCTSTR lpszResourceName);
BOOL LoadBitmap(UINT nIDResource);
第一个声明需要一个资源的ID作为参数。首先需要给Draw程序增加一个位图资源。在资源视图的Bitmap下右键点击添加资源。
//===============位图绘制===================
//创建位图对象
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
//创建位图画刷
CBrush brush(&bitmap);
//获取当前窗口的设备描述表
CClientDC dc(this);
//利用红色画刷填充鼠标拖曳过程中的形成的矩形区域
dc.FillRect(CRect(m_ptPoint, point), &brush);
//===========================================
2.3 透明画刷
利用CDC的Rectangle函数绘制一个矩形。
//获取当前窗口的设备描述表
CClientDC dc(this);
//画刷填充鼠标拖曳过程中的形成的矩形区域
//dc设备表默认有一个白色画刷
dc.Rectangle(CRect(m_ptPoint,point));
白色画刷会覆盖底层的矩形。
利用GetStockObject函数可以获得黑色或者白色的画刷句柄。参数取值NULL_BRUSH获取一个空画刷。GetStockObject函数获取的是一个画刷句柄,而我们需要将画刷句柄转化成一个画刷对象。CBrush类提供了一个FromHandle函数用来实现这样的转化功能。
FromHandle函数是一个静态的成员函数。
该函数声明:
static CDC* PASCAL FromHandle(HDC hDC);
//===============透明画刷===================
//获取当前窗口的设备描述表
CClientDC dc(this);
//创建一个空画刷
CBrush* pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//将空画刷选入设备描述表
CBrush* pOldBrush = dc.SelectObject(pBrush);
//绘制矩形
dc.Rectangle(CRect(m_ptPoint,point));
//恢复原来的画刷
dc.SelectObject(pOldBrush);
透明画刷,不遮挡底部绘制图形。
三、绘制连续线条
绘制连续的线条,首先需要得到线条的起点,然后需要捕获鼠标移动过程中的每一个点,可以通过捕获鼠标移动消息WM_MOUSEMOVE实现。
1)视图增加鼠标移动消息WM_MOUSEMOVE的响应函数OnMouseMove。只要鼠标在应用程序窗口中移动,都会进入这个消息响应函数中。
void CMFCTestView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CView::OnMouseMove(nFlags, point);
}
2)设置一个变量表示鼠标左键是否按下这一状态。
①为视图类添加一个BOOL型成员变量m_bDraw,当鼠标左键按下的时候,此变量为真;鼠标左键弹起时候,此变量为假。
②在视图的构造函数中,初始化此变量为false。
③当鼠标左键按下时,即在OnLButtonDown函数中将此变量变成TRUE;当鼠标左键弹起时,即在OnLButtonUp函数中将此变量变成FALSE。
④在OnMouseMove函数中首先对m_bDraw变量进行判断。若为真,开始画线操作,每绘制一条线段后,下次的线段起点为上一条线段的终点。所以当绘制一条线段后,应该修改线段的起点。
void CMFCTestView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
if (m_bDraw == TRUE) {
dc.MoveTo(m_ptPoint);
dc.LineTo(point);
//修改线段的起点
m_ptPoint = point;
}
CView::OnMouseMove(nFlags, point);
}
改变画笔的颜色,使用CPen类实现。
void CMFCTestView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//创建一个宽度为2的实线画笔
CPen pen(PS_SOLID, 5, RGB(12, 100, 122));
//获取当前窗口的设备描述表
CClientDC dc(this);
//将自己的画笔选入设备描述表
CPen* pOldPen = dc.SelectObject(&pen);
if (m_bDraw == TRUE) {
dc.MoveTo(m_ptPoint);
dc.LineTo(point);
//修改线段的起点
m_ptPoint = point;
}
//恢复原来画笔
dc.SelectObject(pOldPen);
CView::OnMouseMove(nFlags, point);
}
四、绘制扇形效果的线条
鼠标左键按下的点为起点保持不变,分别绘制到鼠标移动点的直线,这时就会出现扇形。绘制一个带边线的扇形。
1)视类添加一个成员函数,用来保存鼠标上一个移动点。从鼠标当前点到鼠标上个移动点的连线,绘制一条边线。
2)保存当前鼠标点,为下一条边线做准备。
void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_bDraw = TRUE;
//鼠标按下的起点
m_ptPoint = point;
//鼠标上一个移动点
m_ptOld = point;
CView::OnLButtonDown(nFlags, point);
}
void CMFCTestView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//创建一个宽度为2的实线画笔
CPen pen(PS_SOLID, 5, RGB(12, 100, 122));
//获取当前窗口的设备描述表
CClientDC dc(this);
//将自己的画笔选入设备描述表
CPen* pOldPen = dc.SelectObject(&pen);
if (m_bDraw == TRUE) {
dc.MoveTo(m_ptPoint);
dc.LineTo(point);
dc.LineTo(m_ptOld);
m_ptOld=point;
}
//恢复原来画笔
dc.SelectObject(pOldPen);
CView::OnMouseMove(nFlags, point);
}