《多媒体技术附录A-MFC编程参考.doc》由会员分享,可在线阅读,更多相关《多媒体技术附录A-MFC编程参考.doc(29页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、 29 第1章 AutoCAD绘图基础附录A MFC编程参考本书的许多作业需要使用MFC进行Windows编程。有些内容(如位图动画、OpenGL、MCI、MMAPI和DirectX等)在书中已经作了介绍,下面对可能用到的其他一些内容作一点简单介绍,详细内容可参考文献5961等。MFC(Microsoft Foundation Class Library微软基础类库)由微软公司的AFX(Application Framework eXtension应用程序框架扩展)小组于1992年设计创建。MFC封装了Windows SDK的结构、功能、应用程序框架等内部技术,屏蔽了重复繁琐的实现细节,简化了
2、程序员的工作。MFC采用文档-视图结构,一般在文档类中读写用户数据文件,在视图类中显示用户数据所对应的文本和图形。MFC有多个版本,本附录主要针对MFC 6.0版,对MFC 7.08.0也基本适用。但是对于MFC 8.0(Visual C+ 2005),则因为其缺省字符(串)为宽字符(串)类型,需要作适当的修改,如在常数字符串前加转换符L。详细讨论参见A.1节。A.1 宽字符(串)本附录的讨论适用与MFC 6.08.0,区别主要在缺省字符(串)的类型。MFC 6.07.1的缺省字符(串)为普通字符(串)类型(单字节/多字节字符,兼容GB 2312),而MFC 8.0的缺省字符(串)的类型为宽字
3、符(串)类型(双字节字符,兼容Unicode的UTF-16)。A.1.1 常用的宽字符函数宽字符类型和函数是C和C+标准(ANSI/ISO/IEC C 1999和ISO/IEC C+ 1998/2003)新增加的内容,它们是用来支持国际通用的Unicode(1993)字符集的。微软公司从Visual C+ 2005版起,开始严格执行C/C+的新标准。由于Windows NT/2000/XP采用的是Unicode字符编码,字符都是双字节的。所以在MFC编程中,一般需要使用双字节的字符类型wchar_t和对应的字符串及其指针类型LPCWSTR和LPCTSTR,并在常数字符串前添加了L转换符,串长计
4、算函数不能用strlen而改用wcslen,串格式打印函数也不能用sprintf,而是改用swprintf(字符和串格式符也从%c和%s改为%lc和%ls)。wchar_t类型,在标准C+中为内置的数据类型和关键字;在C99标准中则为typedef类型,其等价的数据类型与具体的实现有关,在Win32和VC中定义为:typedef unsigned short wchar_t;下面是若干常用的宽字符函数(包含在ISO C99 / ISO C+的标准库中):#include size_t wcslen(const wchar_t *s);int wprintf(const wchar_t * re
5、strict format, .);int wscanf(const wchar_t * restrict format, .);int swprintf(wchar_t * restrict s, size_t n, const wchar_t * restrict format, .);int swscanf(const wchar_t * restrict s, const wchar_t * restrict format, .);long int wcstol(const wchar_t * restrict nptr, wchar_t * restrict endptr, int
6、base);float wcstof(const wchar_t * restrict nptr, wchar_t * restrict endptr);double wcstod(const wchar_t * restrict nptr, wchar_t * restrict endptr);#include errno_t _itow_s( int value, wchar_t *buffer, size_t sizeInCharacters, int radix ); errno_t _ultow_s( unsigned long value, wchar_t *str, size_t
7、 sizeOfstr, int radix );size_t mbstowcs( wchar_t *wcstr, const char *mbstr, size_t count );size_t wcstombs( char *mbstr, const wchar_t *wcstr, size_t count );A.1.2 常用的安全CRT函数安全CRT(C Runtime Library = C运行时间库)函数,是微软公司对C/C+语言的扩展。它在原来函数名后添加了“_s”后缀;一般返回出错代码;并将原来的函数返回值,作为一个参数,添加到函数输入参数列表的最后;对带缓冲区参数的函数,还添加
8、了表示缓冲区大小的输入参数,以防止内存溢出。在VC05中,如果不使用这些安全性函数,编译器会报告警告性错误。下面是若干常用的安全CRT函数:char *gets_s( char *buffer, size_t sizeInCharacters);wchar_t *_getws_s( wchar_t *buffer, size_t sizeInCharacters);errno_t _itoa_s( int value, char *buffer, size_t sizeInCharacters, int radix );errno_t _itow_s( int value, wchar_t *
9、buffer, size_t sizeInCharacters, int radix );errno_t _ultoa_s( unsigned long value, char *str, size_t sizeOfstr, int radix );errno_t _ultow_s( unsigned long value, wchar_t *str, size_t sizeOfstr, int radix );int printf_s( const char *format , argument. ); int wprintf_s( const wchar_t *format , argum
10、ent. );int scanf_s( const char *format , argument. );int wscanf_s( const wchar_t *format , argument. );int sprintf_s( char *buffer, size_t sizeOfBuffer, const char *format , argument . ); int swprintf_s( wchar_t *buffer, size_t sizeOfBuffer, const wchar_t *format , argument.); int sscanf_s( const ch
11、ar *buffer, const char *format , argument .);int swscanf_s( const wchar_t *buffer, const wchar_t *format , argument .);int fprintf_s( FILE *stream, const char *format , argument .);int fwscanf_s( FILE *stream, const wchar_t *format , argument . );int fscanf_s( FILE *stream, const char *format , argu
12、ment . ); int fwscanf_s( FILE *stream, const wchar_t *format , argument . );errno_t strcpy_s( char *strDestination, size_t sizeInBytes, const char *strSource );errno_t wcscpy_s( wchar_t *strDestination, size_t sizeInWords, const wchar_t *strSource );errno_t fopen_s( FILE* pFile, const char *filename
13、, const char *mode );errno_t _wfopen_s( FILE* pFile, const wchar_t *filename, const wchar_t *mode );errno_t mbstowcs_s( size_t *pConvertedChars, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count );errno_t wcstombs_s( size_t *pConvertedChars, char *mbstr, size_t sizeInBytes, const w
14、char_t *wcstr, size_t count );errno_t rand_s( unsigned int* randomValue);下面是若干安全函数原型用到的数据类型的定义:#include typedef int errno_t;typedef unsigned short wchar_t;#ifdef _WIN64typedef unsigned _int64 size_t;#elsetypedef _W64 unsigned int size_t;#endifA.1.3 字符串转换可以利用L运算符和若干函数在单字节/多字节的普通字符串和双字节的宽字符串之间进行相互转换。1
15、. char - wchar_tn L运算符在串常量前加上L运算符,可以将普通字符串转换为宽字符串;例如:wchar_t *wstr = LA string to a wide character string.;CString str = LA string to a wide character string.;MessageBox(L创建位图出错!, L错误);n AllocSysString函数可以利用CString类的AllocSysString()函数来将普通字符串转换成宽字符串:BSTR AllocSysString() const;其中BSTR相当于wchar_t *的type
16、def类型。例如:CString str(A string to a wide character string.);wchar_t *wstr = str.AllocSysString();MessageBox(wstr);n mbstowcs_s函数可以用中定义的下列多字节字符串到宽字符串的C语言转换函数来将普通多字节字符串转换为宽字符串:size_t mbstowcs( wchar_t *wcstr, const char *mbstr, size_t count ); / 成功返回被转换的字符数,失败返回-1/ 若wcstr = NULL,则返回所需宽字符串的大小(宽字符数)errno
17、_t mbstowcs_s( size_t *pConvertedChars, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count ); / 成功返回0例如:char *str = A sample string.;wchar_t wstr80;size_t cn = 0; / 输出参数,用于存放被转换的字符数,包括null结束符0if (!mbstowcs_s(&cn, wstr, 80, str, strlen(str) MessageBox(wstr);else MessageBox(L转换字符串出错!)
18、;2. wchar_t - char只能利用中定义的下列宽字符串到多字节字符串的C语言转换函数来将宽字符串转换为普通多字节字符串:(返回值同前)size_t wcstombs( char *mbstr, const wchar_t *wcstr, size_t count );errno_t wcstombs_s( size_t *pConvertedChars, char *mbstr, size_t sizeInBytes, const wchar_t *wcstr, size_t count );例如:char str80;wchar_t *wstr = LA sample string
19、.;size_t cn = 0; / 输出参数,用于存放被转换的字符数,包括null结束符0if (wcstombs_s(&cn, str, 80, wstr, wcslen(wstr) MessageBox(L转换字符串出错!);又例如:int m, n;const size_t bufSize = 300;char bufbufSize;wchar_t wbufbufSize;CString fn = pDoc-GetPathName();wcscpy_s(wbuf, bufSize, fn);size_t cn = 0;wcstombs_s(&cn, buf, bufSize, wbuf
20、, bufSize);FILE *stream;if (!fopen_s(&stream, buf, rt) fscanf_s(stream, %d %d, &m, &n);/A.2 文字输出为了能选用不同的字体和大小来输出文本串,须使用作为GDI对象的CFont类。Windows和常用的字处理软件(如Word)、绘图软件(如CorelDraw)等应用软件会提供多种与设备无关的字体,主要是TrueType轮廓字体。A.2.1 创建字体函数CFont类是CGDIObject的派生类:CObject CGDIObject CFont。只有一个缺省构造函数CFont( ); 必须用字体创建成员函数C
21、reateFontIndirect或CreatePointFont Indirect来初始化,其中的CreatePointFont提供了创建字体的一种简单方法:BOOL CreatePointFont( int nPointSize, LPCTSTR lpszFaceName, CDC* pDC = NULL );其中:n nPointSize为字体的大小,以0.1点(像素/墨点/磅数)为单位,如汉字的字号与nPointSize值及磅数的对应关系见表A-1。各种字号的文字可参见图A-1。表A-1 汉字字号与点大小和磅数汉字字号nPointSize值磅数汉字字号nPointSize值磅数初号42
22、042四号14014小初36036小四12012一号26026五号10510.5小一24024小五909二号22022六号757.5小二18018小六656.5三号16016七号555.5小三15015八号505n lpszFaceName为字体名称字符串的指针,对MFC 6.0缺省为普通字符串,对MFC 8.0缺省为宽字符串n 若pDC非空,则系统会将设备单位点自动转换为pDC中的映射模式所指定的逻辑单位例如:CFont font;font.CreatePointFont(160, 宋体);注意:CFont类的这些逻辑字体创建函数,并不是从无到有创建一个新的GDI字体,而只是从GDI的物理字
23、体库中选择与所设置参数最匹配的字体。图A-1 汉字的字号与磅数A.2.2 字体公用对话框为了方便用户选择各种字体参数,可使用字体公用对话框: A-2 字体公用对话框使用字体公用对话框需要用到CFontDialog类。CFontDialog类的构造函数为CFontDialog( LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, CDC* pdcPrinter = NULL, CWnd* pParentWnd = NULL );其中,lplfInitial为逻辑字体结构的指针(可用CFont的成员函
24、数GetLogFont来获得),dwFlags为对话框的可选参数,CF_EFFECTS表示对话框中有删除线和下划线复选框与选择颜色的下拉式组合框,CF_SCREENFONTS则使得对话框中只列出系统支持的显示字体。CFontDialog类的常用成员函数有:virtual int DoModal( ); / 显示对话框,返回IDOK或IDCANCELCString GetFaceName( ) const; / 返回字体名称串int GetSize( ) const; / 返回所选择的字体大小,以0.1点为单位COLORREF GetColor( ) const; / 返回所选择的字体颜色A.2
25、.3 文本输出函数常用的文本输出函数有TextOut、DrawText和ExtTextOut,它们都是CDC类的成员函数。下面只介绍最简单的TextOut:BOOL TextOut( int x, int y, const CString& str );其中,x与y为显示串的左上角坐标,str为要显示的文本串。如:pDC-TextOut(10, 10, Test text);还可以使用CDC类的成员函数SetTextColor和SetBkColor来分别设置输出文本的前景色和背景色:(缺省的前景色为黑色,背景色空)virtual COLORREF SetTextColor( COLORREF
26、crColor );virtual COLORREF SetBkColor( COLORREF crColor );例如:pDC-SetTextColor(RGB(0, 128, 0);pDC-TextOut(10, 30, Test text);pDC-SetBkColor(RGB(0, 0, 128);pDC-TextOut(10, 50, Test text);A.3 文件读写MFC支持文档-视图结构,文件的读写一般在文档类的Serialize成员函数中进行。A.3.1 创建支持文档/视图体系项目在创建项目 (Project)时,选择Siggle document (SDI单文档界面)或
27、Multiple documents(MDI多文档界面,缺省)而不是Dialog based(基于对话框)的应用程序,并且选择缺省的Document/View architecture suport?(支持文档-视图体系)的复选框,建立支持文档/视图体系的项目。应用程序框架会自动生成应用程序类C*App、文档类C*Doc、主框架窗口类CMainFrame、视图类C*View,对多文档界面还有子框架窗口类CChildFrame。A.3.2 在系列化函数中用文档类对象读写文件在应用程序框架自动生成的C*Doc类的Serialize(系列化)成员函数中使用其输入参数文档类CArchive的对象ar来
28、读写文件,读写方法似文件流操作。如void CWaveDoc:Serialize(CArchive& ar) if (ar.IsStoring() / TODO: add storing code here 写文件. .ar id;ar id;ar fileLen;. .注意,用输出或输入的为二进制数据;为了输出或输入字符串,可以用CArchive类的成员函数:void WriteString( LPCTSTR lpsz ); 或Bool ReadString(CString& rString );。如:char str80;sprintf(str, %d区(%XA1%XFE):rn, a,
29、c1, c1);ar.WriteString(str);可将重要的读入数据作为文档类的类变量或数组,供视图类的代码访问和图形输出,也可供文档类自己在写入文件时使用。A.3.3 数据类型在Windows API中,定义了一些常用数据类型,包括无符号整数类型和四字符代码等。1. 无符号整数表A-2 无符号整数类型名称类型字节数定义(windef.h)字节BYTE1Btypedef unsigned char BYTE;字WORD2Btypedef unsigned short WORD;双字DWORD4Btypedef unsigned long DWORD;无符号整数UINT4B(Win32)t
30、ypedef unsigned int UINT;2. 四字符代码为了简化RIFF文件中的4字符标识的读写与比较,Windows SDK在多媒体头文件mmsystem.h中定义了类型FOURCC(Four-Character Code四字符代码):typedef DWORD FOURCC;及其构造宏(用于将4个字符转换成一个FOURCC数据)FOURCC mmioFOURCC(CHAR ch0, CHAR ch1, CHAR ch2, CHAR ch3);其定义为MAKEFOURCC宏:#define mmioFOURCC(ch0, ch1, ch2, ch3) MAKEFOURCC(ch0,
31、 ch1, ch2, ch3);而MAKEFOURCC宏又定义为:#define MAKEFOURCC(ch0, ch1, ch2, ch3) (DWORD)(BYTE)(ch0) | (DWORD)(BYTE)(ch1) 8) | (DWORD)(BYTE)(ch2) 16) | (DWORD)(BYTE)(ch3) 24 ); 例如:#include #define ID_RIFFmmioFOURCC(R, I, F, F)#define ID_WAVEmmioFOURCC(W, A, V, E)FOURCC id;ar id;if (id != ID_RIFF) A.3.4 出错处理在文
32、件读写过程中,如果出现读写错误或文件的格式与数据不对,可动态创建一个普通的(generic)文件异常类(CFileException)对象,作抛出(throw)处理。例如if (id != ID_RIFF) MessageBox(NULL, Not RIFF format!, Error, MB_OK);throw(new CFileException(CFileException:generic);在MFC 8.0中,应该改为:if (id != ID_RIFF) MessageBox(NULL, LNot RIFF format!, LError, MB_OK);throw(new CFi
33、leException(CFileException:genericException);A.4 播放波形声音文件全局函数PlaySound可以播放系统声音、声音资源和声音文件,其函数原型为:BOOL PlaySound(LPCSTR pszSound, HMODULE hmod, DWORD fdwSound);其中参数l pszSound的含义与fdwSound的设置有关:n 若fdwSound标志设置为SND_ALIAS、SND_FILENAME或SND_RESOURCE,则pszSound为系统事件的别名、文件名或资源IDn 若fdwSound标志没有设置这些值,则先在注册表或win.
34、ini中寻找串为pszSound的声音,若没有,则视其为文件名n 若pszSound=NULL,则停止播放正在播放的任何声音(同sndPlaySound)。若要停止非波形格式的声音,必须设置fdwSound的标志SND_PURGEl hmodn 若设置了fdwSound的标志SND_RESOURCE,则hmod为包含pszSound所指定资源的可执行文件的句柄n 若没有设置fdwSound的标志SND_RESOURCE,则hmod必须为NULLl fdwSound为标志参数,可以取表A-3中的各值。表A-3 PlaySound函数中的fdwSound参数的值fdwSound值对应数值含义SND
35、_ASYNC0x01异步播放,调用后立即返回(最常用)SND_LOOP0x08循环播放,必须与SND_ASYNC标志同用SND_MEMORY0x04lpszSound指向内存中波形声音映像(可以动态生产声音)SND_NODEFAULT0x02找不到指定声音时,不播放缺省的声音SND_NOSTOP0x10如果有声音正在播放,则不播放指定的声音而直接返回SND_SYNC0x00同步播放,直到声音播完后调用才返回(缺省值)SND_NOWAIT0x002000若设备忙,则不等待(不播放声音,立即返回)SND_ ALIAS0x010000pszSound为注册项的别名SND_ ALIAS_ID0x110
36、000别名是一个预定义的IDSND_ FILENAME0x020000pszSound为文件名SND_ RESOURCE0x040004pszSound为资源名或原子(atom)SND_ PURGE0x40清除任务的非静止事件SND_ APPLICATION0x80使用应用程序指定关联程序来播放声音例如:PlaySound(c:soundssample.wav, NULL, SND_ASYNC);PlaySound(ar.GetFile()-GetFilePath(), NULL, SND_ASYNC);为了使包含PlaySound的程序能够编译通过,必须包含多媒体头文件:#include 并
37、在项目中添加多媒体链接库:选Project/Settings菜单,在弹出的Project Settings对话框中选Link页,在中间的Object/Library Modulas域中添加winmm.lib。有关播放Wave文件的详细内容,可以参看本书的12.2节。A.5 绘图绘图一般在视图类的(屏幕/打印机)绘图消息响应函数OnDraw中进行:void CWaveView:OnDraw(CDC* pDC) CWaveDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);/ TODO: add draw code for native data here在绘
38、图前,必须先访问文档数据、得到客户区大小、设置绘图颜色,然后再根据文档数据来绘制图形。A.5.1 访问文档数据可通过在OnDraw函数中自动生成的代码所得到的文档指针pDoc来访问文档类对象中的各种变量和数组,并根据这些数据来绘图。例如CWaveDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);for(i = 0; in; i+) x = (int)(i * dx + 0.5); y = h0 - (int)(pDoc-di * dy + 0.5);if(i = 0) pDC-MoveTo(x, y); else pDC-LineTo(x, y);A.5
39、.2 获取客户区的大小绘图一般都是在视图窗口的客户区进行,而客户区的大小在运行时可由用户改变,为了使绘制的图形能随窗口大小自动改变,必须先得到当前客户区大小的数据(宽w和高h)。获取客户区大小的方法有两种:1. 在消息响应函数OnSize中获得使用类向导ClassWizard,在视图类中添加WM_SIZE消息的响应函数OnSize。该函数在窗口第一次显示或窗口大小被改变时会被Windows系统调用。其输入参数中的cx和cy就是当前客户区大小的宽和高,可将他们赋值给类变量(如m_iWidth和m_iHeight)供绘图时使用。例如void CClassView:OnSize(UINT nType
40、, int cx, int cy) m_iWidth = cx;m_iHeight = cy;2. 调用函数GetClientRect得到可在绘图前,定义一个矩形结构变量crect,然后再调用函数GetClientRect得到当前客户区矩形的数据,其中的字段right与bottom就是客户区的宽与高(因为其left与top都为0,所以right = 客户区的宽、bottom = 客户区的高),如:RECT crect;GetClientRect(&crect);m_iWidth = crect.right;m_iHeight = crect.bottom;其中,表示矩形的结构RECT的定义为(
41、windef.h)typedef struct _RECT LONG left; LONG top; LONG right; LONG bottom; RECT;其对应的MFC类为CRect。A.5.3 设置绘图颜色1. 颜色Windows中的颜色一般用4个字节表示(4B = 32b = 0BGR高位在前,整数序 = RGB0低位在前,字节序),定义了一个专门表示颜色索引值的变量类型COLORREF:(windef.h)typedef DWORD COLORREF;及由红绿蓝三原色构造颜色值的宏RGB:(wingdi.h)#define RGB(r,g,b) (COLORREF)(BYTE)(
42、r)|(WORD)(BYTE)(g)8)|(DWORD)(BYTE)(b)16)其中,r、g、b为字节变量,取值范围为0255。其函数说明为:COLORREF RGB( BYTE bRed, / red component of color BYTE bGreen, / green component of color BYTE bBlue / blue component of color);例如:COLORREF red, gray;red = RGB(255, 0, 0);gray = RGB(128, 128,128);2. 点色(像素)在Windows中,像素(pixel)的颜色是直
43、接由设备上下文类CDC的成员函数SetPixel来设置的,该函数的原型为:COLORREF SetPixel( int x, int y, COLORREF crColor );其中,x与y分别为像素点的横坐标与纵坐标,crColor为像素的颜色值。3. 线色(笔)在Windows中,线状图必须用笔(pen)来画,所以线的颜色就由笔色来确定。笔的创建与使用的步骤为:n 创建笔对象创建笔类CPen对象的方法有如下两种:u 使用构造函数CPenCPen( int nPenStyle, int nWidth, COLORREF crColor );其中,l nPenStyle为笔的风格,可取值见表A
44、-4。表A-4 笔的风格nPenStyle的取值风格值风格名称线例PS_SOLID实心PS_DASH虚线PS_DOT点线PS_DASHDOT虚点线PS_DASHDOTDOT虚点点线l nWidth为笔宽,与映射模式有关,使用缺省映射时为像素数,若nWidth = 0,则不论什么映射模式,笔宽都为一个像素;crColor为笔的颜色值。例如:CPen* pGrayPen = new CPen(PS_SOLID, 0, RGB(128, 128, 128);CPen grayPen(PS_SOLID, 0, RGB(128, 128, 128);u 使用成员函数CreatePenBOOL CreatePen( int nPenStyle, int nWidth, COLORREF crColor );例如:CPen grayPen;grayPen.CreatePen(PS_SOLID, 0, RGB(128, 128, 128);缺省的笔为单像素宽的实心黑色笔n 将笔对象选入设备上下文为了能使用我们所创建的笔对象来绘图,必须先将它选入设备上下文。这可以调用设备上下文类CDC的成员函数SelectObject来完成: