MFC程序设计(十二)绘图
只有类对象和绘图设备句柄进行绑定,该类对象才可以进行绘图
相关类
m_hDC和m_hAttribDC保存了同一个绘图设备句柄
CPaintDC类和CClientDC类继承于CDC类
CPaintDC类在WM_PAINT消息的OnPaint消息处理函数中使用,CClientDC类在其他消息,如COMMAND消息的消息处理函数中使用
接下来我们通过MFC向导创建一个单文档视图架构项目进行分析CPaintDC类和CClientDC
CPaintDC类对象
首先通过类向导添加WM_PAINT消息
接下来我们可以在类向导为我们生成的函数中进行绘图
void CMFCDrawView::OnPaint()
{
CPaintDC dc(this); //类对象与绘图句柄绑定,其中this为视图窗口
dc.Rectangle(100, 100, 300, 300);//其内部实现为::Rectangle
//也可::Rectangle(dc.m_hDC, 100, 100, 300, 300);
}
该代码绘制了一个矩形。接下来我们通过第一行代码观察MFC是如何将类对象和绘图句柄绑定在一起的,我们进入CPaintDC dc(this)内部观察
CPaintDC dc(pView) === CPaintDC::CPaintDC(...)//构造函数,函数内部this为&dc
{
Attach(::BeginPaint(pView->m_hWnd, &m_ps))//获取绘图设备句柄hDC,函数内部this为&dc
{
m_hDC = hDC;//将绘图设备句柄hDC保存到dc对象的一个成员变量中
SetAttribDC(m_hDC)//函数内部this为&dc
{
m_hAttribDC = m_hDC;//将绘图设备句柄hDC保存到dc对象的另一个成员变量中
}
}
}
通过代码可知,在CPaintDC dc(this)的内部,MFC将绘图句柄和类对象进行了绑定
在上述代码中,我们在CPaintDC dc(pView)构造函数的内部发现了Win32的::BeginPaint,与之配对的::EndPaint则存在与CPaintDC dc(pView)的析构函数中。由于dc是局部变量,因此在离开OnPaint函数时,dc被析构,出现::EndPaint
CClientDC类对象
接下来我们将通过点击菜单项,在视图窗口客户区进行绘图
首先添加一个菜单项
如图,这是我们添加的菜单项,ID为ID_CLIENT
我们为该菜单项添加消息处理函数
void CMFCDrawView::OnClient()
{
CClientDC dc(this);
dc.Ellipse(300, 300, 500, 500);
}
此时便绘画了一个圆形。
但这个圆和上文的矩形有所差别,当视图窗口改变时,这个圆会消失,而矩形不会消失。这是因为当窗口发生改变时,就会产生绘图消息,OnPaint就会被调用,重新绘制矩形,而上述代码绘制的圆形,只有在点击菜单项时才会被调用
绘图相关类
接下来我们将针对这些类进行一个应用学习
首先我们添加一些菜单,并添加相应的消息处理函数,使得我们点击相关菜单项时触发不同的消息处理函数
CPen的ID为ID_PEN
CBrush的ID为ID_BRUSH
CFont的ID为ID_CFont
CBitmap的ID为ID_BMP
CPen应用
//MFC写法
void CMFCDrawView::OnCfont()
{
CClientDC dc(this);//CClientDC类对象绑定绘图设备句柄
CPen pen(PS_SOLID, 2, RGB(255, 0, 0));//CPen类对象绑定画笔句柄
CPen* oldpen = dc.SelectObject(&pen);//函数返回原来的CPen类对象
dc.Rectangle(100, 100, 300, 300);
dc.SelectObject(oldpen);//恢复原来的CPen类对象
pen.DeleteObject();
}
//win32写法
void CMFCDrawView::OnPen()
{
CClientDC dc(this);
CPen pen(PS_SOLID, 2, RGB(255, 0, 0));
HGDIOBJ nOldPen = ::SelectObject(dc.m_hDC, pen.m_hObject);
::Rectangle(dc.m_hDC, 100, 100, 300, 300);
::SelectObject(dc.m_hDC, nOldPen);
::DeleteObject(pen.m_hObject);
}
运行程序,视图窗口出现一个线条空心的矩形
接下来我们观察一下CPen类对象是如何和绘图句柄绑定的
CPen pen(PS_SOLID, 2, RGB(255,0,0)) === CPen::CPen(PS_SOLID, 2, RGB(255,0,0))//函数内部this &pen
{
Attach(::CreatePen(PS_SOLID, 2, RGB(255,0,0)))//函数内部this &pen
{
m_hObject = hObject;//将::CreatePen获取的画笔句柄hObject,保存到pen对象的一个成员变量中
}
}
在接下来的CBrush,CFont等等都是通过上述代码的方式进行类成员和绘图句柄进行绑定的
CBrush应用
void CMFCDrawView::OnBrush()
{
CClientDC dc(this);
CBrush brush(RGB(255, 0, 0));
CBrush* oldbrush = dc.SelectObject(&brush);
dc.Rectangle(100, 100, 300, 300);
dc.SelectObject(&oldbrush);
}
运行程序,出现一个实心的矩形
CFont应用
void CMFCDrawView::OnCfont()
{
CClientDC dc(this);
CFont font;
font.CreatePointFont(300, "黑体");
dc.SelectObject(&font);
CFont* oldfont = dc.SelectObject(&font);
dc.TextOutA(100, 100, "hello");
dc.SelectObject(&oldfont);
}
运行程序,出现字体hello
CBitmap应用
1.添加一个位图资源,ID = IDB_BITMAP1
2.代码实现
void CMFCDrawView::OnClient()
{
//添加位图资源
CClientDC dc(this);//当前DC
//创建一个和当前DC相匹配的内存DC
CDC mendc;//内存DC
mendc.CreateCompatibleDC(&dc);//内存DC和当前DC进行匹配
//将位图数据送给内存DC
CBitmap bmp;
bmp.LoadBitmap(IDB_BITMAP1);
CBitmap* oldbmp = mendc.SelectObject(&bmp);//传送位图数据
//成像
dc.BitBlt(100, 100, 50, 50, &mendc, 0, 0, SRCCOPY);
//将位图数据要回来
mendc.SelectObject(oldbmp);
//销毁位图
bmp.DeleteObject();
//销毁内存DC
mendc.DeleteDC();
}