MFC绘图.docx
- 文档编号:25534882
- 上传时间:2023-06-09
- 格式:DOCX
- 页数:24
- 大小:46.11KB
MFC绘图.docx
《MFC绘图.docx》由会员分享,可在线阅读,更多相关《MFC绘图.docx(24页珍藏版)》请在冰豆网上搜索。
MFC绘图
一、绘制线条
1、新建MFC单文档工程Draw。
2、为CDrawView类添加CPoint类型的成员变量m_ptOrigin,将其访问权限设置为Private。
3、添加WM_LBUTTONDOWN的消息响应函数,该函数初始化m_ptOrigin变量m_ptOrigin=point。
4、添加WM_LBUTTONUP的消息响应函数voidCDrawView:
:
OnLButtonUp(UINTnFlags,CPointpoint),在该函数里可添加如下各种代码实现绘图:
(1)、利用SDK全局函数实现画线功能:
HDChdc;
hdc=:
:
GetDC(m_hWnd);//获得窗口的设备描述表
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);//移动到线条的起点
LineTo(hdc,point.x,point.y);//画线
:
:
ReleaseDC(m_hWnd,hdc);//释放设备描述表
知识点:
所有派生于CWnd类的子类都拥有m_hWnd这一成员变量,m_hWnd被定义为HWND类型,用于保存当前窗口的句柄,该成员变量具有public的访问权限。
(2)、利用MFC的CDC类实现画线功能:
CDC*pDC=GetDC();
pDC->MoveTo(m_ptOrigin);
pDC->LineTo(point);
ReleaseDC(pDC);
知识点:
MFC提供了设备描述表的封装类CDC,该类封装了所有与绘图相关的操作。
该类提供了一个数据成员m_hDC,用来保存与CDC类相关的DC句柄
(3)、利用MFC的CClientDC类实现画线功能:
CClientDCdc(this);//dc(GetParent())可获得父窗口的DC
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
知识点:
CClientDC派生于CDC类,当一个CClientDC对象在构造时,它在内部会调用GetDC函数,在这个CClientDC对象析构时,它会调用ReleaseDC函数。
这样,我们就不用显式地调用GetDC和ReleaseDC函数了。
(4)、利用MFC的CWindowDC类实现画线功能
CWindowDCdc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
知识点:
视类(View类)窗口只有客户窗口区(即视类窗口本身),而框架类(Frame类)窗口既有客户区(即菜单栏以下部分),还有非客户区(就是程序运行界面中的标题栏和菜单栏)。
CWindowDC对象可以访问整个窗口区域,包括框架窗口的非客户区和客户区。
CWindowDC类派生于CDC类。
该类对象在构造时调用GetWindowDC函数,在析构时调用ReleaseDC函数,也就是说不需要我们显式地调用GetDC和ReleaseDC函数。
提示:
CWnd类的GetDesktopWindow成员函数可以获得Windows桌面窗口的句柄。
(5)、绘制彩色线条
CPenpen(PS_SOLID,1,RGB(255,0,0));
CClientDCdc(this);
CPen*pOldPen=dc.SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.SelectObject(pOldPen);
知识点:
在程序中,当构造一个GDI对象后,该对象并不会立即生效,必须选入设备描述表,它才会在以后的绘制操作中生效。
利用SelectObject函数可以实现把GDI对象选入设备描述表中,并且该函数会返回指向先前被选对象的指针。
一般情况下,在完成绘图操作后,都要利用SelectObject函数将先前的GDI对象选入设备描述表,以便使其恢复到先前的状态。
(6)、使用画刷绘图(画刷用来填充一块区域)
CBrushbrush(RGB(255,0,0));
CClientDCdc(this);
dc.FillRect(CRect(m_ptOrigin,point),&brush);
(7)、位图画刷
CBitmapbitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
CBrushbrush(&bitmap);
CClientDCdc(this);
dc.FillRect(CRect(m_ptOrigin,point),&brush);
(8)、透明画刷
CClientDCdc(this);
//创建空画刷
CBrush*pBrush=CBrush:
:
FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
//将空画刷选入设备描述表
CBrush*pOldBrush=dc.SelectObject(pBrush);
dc.Rectangle(CRect(m_ptOrigin,point));//画矩形
dc.SelectObject(pOldBrush);
知识点:
设备描述表中有一个默认的白色画刷,当我们绘制两个相互重叠的矩形时,后绘制的矩形就会遮盖住先前绘制的矩形。
(9)、画像素点:
dc.SetPixel(point,RGB(255,0,0));
(10)、画圆
dc.Ellipse(CRect(m_ptOrigin,point));
CRect类重载了LPCRECT操作符,其作用是将CRect转换成LPCRECT类型。
当在程序中给CRect函数的参数赋值时,会隐式地调用LPCRECT操作符,将CRect类型的对象转换为LPCRECT类型。
(11)、获得控件的矩形区域:
CRectrect;
//获取ID为IDC_SAMPLE的控件的矩形区域
GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);
(12)、将屏幕坐标改为窗口坐标:
ScreenToClient(&rect);//rect被改为窗口坐标
提示:
当用户对编辑框控件(EditBox)中的文本进行改变时,会向其父窗口,即对话框发送一个EN_CHANGE通知消息。
当用户单击单选按钮(RadioButton)时,该按钮会向对话框发送BN_CLICKED消息。
二、绘图控制
创建一个MFC单文档类型的工程Graphic,以下实例都在该工程下:
1、颜色对话框
(1)、在CGraphicView类中添加COLORREF类型的私有成员变量m_clr,用于存储用户选择的颜色。
在CGraphicView类构造函数中初始化:
m_clr=RGB(255,0,0);
(2)、增加一个菜单项,用于创建颜色对话框,让CGraphicView类对此菜单项命令做出响应,即在ClassWizard中将Classname选择为CGraphicView。
增加的响应函数如下:
voidCGraphicView:
:
OnColor()
{
CColorDialogdlg;//颜色对话框
dlg.m_cc.Flags|=CC_RGBINIT;//设置标记,才能设置初始颜色的选择
dlg.m_cc.rgbResult=m_clr;//设置初始颜色为自定义的m_clr变量指定的颜色
if(IDOK==dlg.DoModal())//若点击的是OK按钮
{
m_clr=dlg.m_cc.rgbResult;//保存选择的颜色
}
}
注意:
若想要设置颜色对话框初始选择的颜色,需要设置该对话框的CC_RGBINIT标记,这个标记可以在创建颜色对话框时通过其构造函数的第二个参数来设置,也可以在该对话框创建之后,设置其m_cc成员变量的Flags成员。
但直接给Flags标记赋值会出错,应用或操作”|”将标记与Flags先前的标记组合起来。
2、字体对话框
(1)、在CGraphicView类中添加CFont类型的私有成员变量m_font,用于存储选择的字体。
再增加一个CString类型的私有成员变量m_strFontName,用来保存所选字体的名称。
在CGraphicView类的构造函数中将m_strFontName初始化为空,如:
(2)、增加一个菜单项,用于创建字体对话框,让CGraphicView类对此菜单项命令做出响应,即在ClassWizard中将Classname选择为CGraphicView。
增加的响应函数如下:
voidCGraphicView:
:
OnFont()
{
CFontDialogdlg;//定义字体对话框
if(IDOK==dlg.DoModal())//若用户选择的是OK按钮
{
if(m_font.m_hObject)//若m_font对象已经和字体资源相关联
{
m_font.DeleteObject();//删除m_font对象已经和字体资源的关联
}
//设置m_font的字体为字体对话框选择的字体
m_font.CreateFontIndirect(dlg.m_cf.lpLogFont);m_strFontName=dlg.m_cf.lpLogFont->lfFaceName;//保存字体对话框选择的字体名称
Invalidate();//让窗口无效,下一次WM_PAINT消息发生时,重绘窗口
}
}
说明:
m_font对象已经与一个字体资源相关联了,切断这种关联,释放该字体资源,可用CGdiObject类(CPen、CFont、CBitmap、CBrush都派生于该类)的DeleteObject成员函数。
该函数释放所有为WindowsGDI对象所分配的资源,从而删除与CGdiObject对象相关联的WindowsGDI对象(资源对象),同时与CGdiObject对象(类对象)相关的存储空间并不会受此影响。
CGdiObject对象的数据成员m_hObject保存了与CGdiObject对象相关联的WindowsGDI资源的句柄。
(3)、在CGraphicView类中按选择的字体显示字体名
CFont*pOldFont=pDC->SelectObject(&m_font);
pDC->TextOut(0,0,m_strFontName);
pDC->SelectObject(pOldFont);
3、改变对话框背景色:
(1)、为CSettingDlg类添加CBrush类型的私有成员变量m_brush。
在CSettingDlg类的构造函数中初始化该变量:
m_brush.CreateSolidBrush(RGB(0,0,255));
(2)、为CSettingDlg类添加WM_CTLCOLOR消息响应函数,在该函数OnCtlColor中返回画刷:
returnm_brush;
提示:
对于对话框来说,它上面的每一个控件在绘制时都会向它发送WM_CTLCOLOR消息。
WM_CTLCOLOR消息的响应函数是CWnd类的OnCtlColor。
该函数返回将被用来绘制控件背景的画刷的句柄。
若想改变对话框的背景色,只需自定义一个画刷,然后让OnCtlColor函数返回这个画刷句柄即可。
4、改变指定控件的背景色和文本颜色:
编写WM_CTLCOLOR的消息响应函数OnCtlColor如下:
HBRUSHCSettingDlg:
:
OnCtlColor(CDC*pDC,CWnd*pWnd,UINTnCtlColor)
{
HBRUSHhbr=CDialog:
:
OnCtlColor(pDC,pWnd,nCtlColor);
//pWnd是当前绘制的控件窗口对象
if(pWnd->GetDlgCtrlID()==IDC_LINE_STYLE)
{
pDC->SetTextColor(RGB(255,0,0));//设置控件文本颜色
pDC->SetBkMode(TRANSPARENT);//设置文字背景为透明
returnm_brush;//返回背景画刷,CBrush类重载了HBRUSH操作符
}
returnhbr;//返回默认背景画刷
}
提示:
pDC->SetBkColor(RGB(255,255,0));可以改变文字背景。
5、修改控件的文本字体
(1)、为CSettingDlg类添加CFont类型的私有变量m_font。
在CSettingDlg类的构造函数中初始化该变量:
m_font.CreatePointFont(200,"System");
(2)、在WM_CTLCOLOR的消息响应函数OnCtlColor添加如下语句:
if(pWnd->GetDlgCtrlID()==IDC_TEXT)//改变指定ID的控件的字体
{
pDC->SelectObject(&m_font);
}
6、改变按钮控件的文本颜色
若要改变一个自绘制按钮(具有BS_OWNERDRAW风格的按钮,即按钮的Ownerdraw属性)控件的背景色和文本颜色,应为按钮创建一个CButton类,然后重载CButton类的成员虚函数DrawItem。
(1)、在VC6.0界面中:
Insert->NewClass->Classtype选择MFCClass->Baseclass选择CButton->名字命名为CTestBtn
(2)、在ClassView选项卡下为CTestBtn类添加DrawItem虚函数,编写该函数如下:
voidCTestBtn:
:
DrawItem(LPDRAWITEMSTRUCTlpDrawItemStruct)
{
//TODO:
Addyourcodetodrawthespecifieditem
UINTuStyle=DFCS_BUTTONPUSH;
//Thiscodeonlyworkswithbuttons.
ASSERT(lpDrawItemStruct->CtlType==ODT_BUTTON);
//Ifdrawingselected,addthepushedstyletoDrawFrameControl.
if(lpDrawItemStruct->itemState&ODS_SELECTED)
uStyle|=DFCS_PUSHED;
//Drawthebuttonframe.
:
:
DrawFrameControl(lpDrawItemStruct->hDC,&lpDrawItemStruct->rcItem,
DFC_BUTTON,uStyle);
//Getthebutton'stext.
CStringstrText;
GetWindowText(strText);
//Drawthebuttontextusingthetextcolorred.
COLORREFcrOldColor=:
:
SetTextColor(lpDrawItemStruct->hDC,RGB(255,0,0));
:
:
DrawText(lpDrawItemStruct->hDC,strText,strText.GetLength(),
&lpDrawItemStruct->rcItem,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
:
:
SetTextColor(lpDrawItemStruct->hDC,crOldColor);
}
(3)、用ClassWizard为CSettingDlg对话框的OK按钮添加变量m_btnTest。
其中Category选择Control,Variabletype选择CTestBtn。
记得在CSettingDlg类中#include"TestBtn.h"
(4)、将OK按钮属性下Styles选项卡下的Ownerdraw选项勾上。
7、引入别人写的类来改变按钮类型的背景色和文本颜色
(1)、将别人写的类,如BtnST.cpp、BtnST.h、SXBtn.cpp、SXBtn.h复制到工程所在目录下。
(2)、在VC6.0中:
Project->AddToProject->Files->选择上步复制到工程的文件。
(3)、用ClassWizard为Cancel按钮添加m_btnST变量,其中Category选择Control,Variabletype选择CButtonST。
记得在CSettingDlg中添加#include"BtnST.h"
提示:
CButtonST类会自动设置按钮的Ownerdraw这个属性,即将按钮设置为BS_OWNERDRAW风格。
(4)、为CSettingDlg类添加WM_INITDIALOG消息响应函数初始化Cancel按钮,该函数编写如下:
BOOLCSettingDlg:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
//TODO:
Addextrainitializationhere
m_btnST.SetInactiveBgColor(RGB(255,0,255));//按钮不活动时的背景色
m_btnST.SetInactiveFgColor(RGB(255,255,0));//按钮不活动时的文本颜色
m_btnST.SetActiveBgColor(RGB(0,0,255));//按钮活动时的背景色
m_btnST.SetActiveFgColor(RGB(255,0,0));//按钮活动时的文本颜色
returnTRUE;//returnTRUEunlessyousetthefocustoacontrol
//EXCEPTION:
OCXPropertyPagesshouldreturnFALSE
}
8、位图的显示,位图大小保持不变
窗口更新时,会先发送WM_ERASEBKGND消息用于擦除窗口背景,然后再调用OnDraw函数重绘窗口。
这里将位图的显示放在擦除窗口的消息响应函数中,当然也可以放在OnDraw函数中,只不过前者显示较快。
(1)、准备一张位图,后缀为bmp的图片,复制到工程的res目录中。
(2)、Insert->Resource->Import该bmp图片
提示:
VC6.0的位图编辑器不能编辑颜色超过256种的位图。
但在程序中是能正常使用的。
(3)、为CGraphicView类添加WM_ERASEBKGND消息响应函数如下:
BOOLCGraphicView:
:
OnEraseBkgnd(CDC*pDC)
{//创建位图
CBitmapbitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
//创建兼容DC
CDCdcCompatible;
dcCompatible.CreateCompatibleDC(pDC);
//将位图选入兼容DC
dcCompatible.SelectObject(&bitmap);
//将兼容DC中的位图贴到当前DC中
CRectrect;
GetClientRect(&rect);//获取客户区长宽
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0,SRCCOPY);//BitBlt函数按照1:
1的比例将源设备上下文中的位图复制到目标设备上下文中
returnTRUE;
}
9、位图的显示,位图大小随窗口而拉伸或压缩
(1)、在WM_ERASEBKGND消息响应函数中添加如下代码:
BITMAPbmp;
bitmap.GetBitmap(&bmp);//获得源位图的大小
pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);//位图按窗口大小进行显示
三、坐标空间和转换
1、何为坐标空间:
一个坐标空间是一个平面的空间,通过使用两个互相垂直并且长度相等的轴来定位二维对象,如下图所示:
2、Win32程序的坐标空间:
Win32应用程序编程接口(API)使用四种坐标空间:
世界坐标系空间、页面空间、设备空间和物理设备空间。
Win32API将世界坐标系空间和页面空间称为逻辑空间。
应用程序运用世界坐标系空间对图形输出进行旋转、斜切或者反射。
物理设备空间通常指应用程序窗口的客户区,它包括整个桌面、完整的窗口(包括框架、标题栏、菜单栏)或打印机的一页或绘图仪的一页纸。
3、坐标空间转换:
若要在物理设备上绘制输出,Windows就把一个矩形区域从一个坐标空间复制到(或映射到)另一个坐标空间,直至最终完整的输出呈现在物理设备(通常是屏幕或打印机)上。
若应用程序调用了SetWorldTransform函数,那么映射就从应用程序的世界坐标系空间开始,否则,映射在页面空间开始进行。
Windows把矩形区域的每一点从一个空间复制到另一个空间,它采用了一种被称为转换的算法,转换就是把对象从一个坐标空间复制到另一个坐标空间时改变(或转变)这一对象的大小、方位和形态。
尽管转换把对象看成一个整体,但它也作用于对象中的每一点或每条线。
下图为调用SetWorldTransfer函数进行的转换:
提示:
在MSDN中搜索SetWorldTransform可以查看相关例子。
4、页面空间到设备空间的转换:
页面空间(也称为逻辑空间)到设备空间的转换是原Windows接口的一部分,这种转换确定与一个特定设备描述表相关的所有图形输出的映射方式。
映射方式是指确定用于绘图操作的单位大小的一种度量转换,也就是说,设定的映射方式主要是确定应该如何将页面空间的一个坐标点转换为设备空间中的一个设备坐标点。
页面空间到设备空间的转换所用的是两个矩形的宽和高的比率(通常称为转换因子),其中页面空间中的矩形被称为窗口,设备空间中的矩形被称为视口,Windows把窗口原点映射到视口原点,把窗口范围映射到视口范围,就完成了转换。
如下图所示:
提示:
窗口是基于逻辑坐标的,逻辑坐标可以使像素、毫米、英寸等单位;视口是基于设备坐标(像素)的,通常,视口和客户区相同。
5、设备空间到物理设备空间的转换:
设备空间到物理设备空间的转换有几个独特之处,它只限于平移,并由Windows的窗口管理部分控制。
这种转换唯一的用途是确保设备空间的原点被映射到物理设备上的适当点上。
没有函数能设置这种转换,也没有函数可以获取相关数据。
也就是说,从设备空间到物理设备空间的转换是由Windows控制的,程序员没有办法去设置这种转换。
6、逻辑坐标和设备坐标的转换:
(1)、窗口(逻辑)坐标转换为视口(设备)坐标的公式:
xViewPort=(xWindow-xWinOrg)*xViewExt/xWinExt+xViewOrg
yViewPort=(yWindow-yWinOrg)*yViewExt/yWinExt+yViewOrg
(2)、视口(设备)坐标转换为窗口(逻辑)坐标的公式:
xWindow=(xViewPort-xViewOrg)*xWinExt/xViewExt+xW
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- MFC 绘图