博文
MFC中的GDI绘图(5)(2008-12-22 12:56:00)
摘要:坐标映射实例
(1)建立单文档MFC项目Draw:New—>Projects—>MFC AppWizard(EXE)—>Single Document。
(2)找到CMainFrame::PreCreateWindow函数,在其中设置默认窗口大小为400 pixel*300 pixel。
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx=400;
cs.cy=300;
return TRUE;
}
(3)添加OnPaint事件
资源管理器—>ClassView—>右击CDrawView 选择Add Windows Message Handler
—>WM_PAINT—> Add Handler
1. void CDrawView::OnPaint()
2. {
3. CPaintDC dc(this); // device context for painting
4. // TODO: Add your message handler code here
5. &nb......
MFC中的GDI绘图(4)(2008-12-21 21:29:00)
摘要:3、创建绘图工具并选入DC
有了画布,要绘图我们必须有画笔画刷。在Windows中有HPEN、HBRUSH等GDI对象,MFC对GDI对象进行了很好的封装,提供了封装GDI对象的类,如CPen、CBrush、CFont、CBitmap和CPalette等,这些类都是GDI对象类CGdiObject的派生类。
一般先创建画笔(刷),然后调用CDC::SelectObject函数将画笔(刷)选入设备环境最为当前绘图工具,绘图完毕恢复设备环境以前的画笔(刷)对象,最后调用CGdiObject::DeleteObject函数删除画笔(刷)对象。
这里需要注意的是,CGdiObject::DeleteObject函数彻底删除底层GDI对象(CPen和CBrush类的基类)。在MFC中,当对象销毁时会调用对象的析构函数自动删除对象,一般不必调用CGdiObject::DeleteObject删除GDI对象,因为如果设备环境还在使用一个GDI对象时,将引起应用程序崩溃或出现难以理解的运行错误。
(1)创建画笔
BOOL CPen::CreatePen( int nPenStyle, int nWidth, COLORREF cfColor );
nPenStyle 指定画笔的风格。其可能取值的列表,请参见CPen构造函数中的nPenStyle参数。
nWidth 指定画笔的宽度。如果这个值为0,则不管是什么映射模式,以设备单位表示的宽度总是一个像素。
crColor 包含画笔的一个RGB颜色,为COLORREF结构。
此外,可通过CDC::SelectStockObject函数来调用系统预定义的库存笔对应的CGdiObject对象。
pOldPen = (Cpen*)pDC->SelectStockObject(BLACK_PEN);
(2)创建画刷
BOOL CBrush::CreateSolidBrush ( COLORREF crColor );
BOOL CBrush::CreateHatchBrush( int nIndex, COLORREF crColor );
参数: nIndex 指定......
MFC中的GDI绘图(3)(2008-12-21 19:59:00)
摘要:2、设置坐标映射
(1)Windows坐标系统
Windows坐标系分为逻辑坐标系和设备坐标系两种,GDI支持这两种坐标系。一般而言,
GDI的文本和图形输出函数使用逻辑坐标,而在客户区移动或按下鼠标的鼠标位置是采用设备坐标。
<1>逻辑坐标系是面向DC的坐标系,这种坐标不考虑具体的设备类型,在绘图时,Windows会根据当前设置的映射模式将逻辑坐标转换为设备坐标。
<2>设备坐标系是面向物理设备的坐标系,这种坐标以像素或设备所能表示的最小长度单位为单位,X轴方向向右,Y轴方向向下。设备坐标系的原点位置(0, 0)不限定在设备显示区域的左上角。
设备坐标系分为屏幕坐标系、窗口坐标系和客户区坐标系三种相互独立的坐标系。
l 屏幕坐标系以屏幕左上角为原点,一些与整个屏幕有关的函数均采用屏幕坐标,如GetCursorPos()、SetCursorPos()、CreateWindow()、MoveWindow()。弹出式菜单使用的也是屏幕坐标。
l 窗口坐标系以窗口左上角为坐标原点,它包括窗口标题栏、菜单栏和工具栏等范围。
l 客户区坐标系以窗口客户区左上角为原点,主要用于客户区的绘图输出和窗口消息的处理。鼠标消息的坐标参数使用客户区坐标,CDC类绘图成员函数使用与客户区坐标对应的逻辑坐标。
(2)坐标之间的相互转换
l 编程时,有时需要根据当前的具体情况进行三种设备坐标之间或与逻辑坐标的相互转换。
l MFC提供了两个函数CDC::DPtoLP()和CDC:: LPtoDP()用于设备坐标与逻辑坐标之间的相互转换。
l MFC提供了两个函数CWnd::ScreenToClient()和CWnd::ClientToScreen()用于屏幕坐标与客户区坐标的相互转......
MFC中的GDI绘图(2)(2008-12-21 18:01:00)
摘要:二.MFC中GDI绘图
GDI绘图包括以下步骤:获取设备环境,设置坐标映射,创建绘图工具,调用DC绘图函数绘图。
1、获取设备环境
(1)在SDK编程中,获取设备环境的方法有两种:
<1>通过API函数BeginPaint。应用程序响应WM_PAINT消息进行图形刷新时主要通过BeginPaint函数获取设备环境,在消息处理函数返回前调用API函数EndPaint释放设备环境。
函数原型为:WINUSERAPI HDC WINAPI BeginPaint( HWND hWnd,LPPAINTSTRUCT lpPaint);
//以下为Win API示例::BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
case WM_PAINT://窗口客户区需要重绘
{
char szText[]="Hello World";
PAINTSTRUCT ps;
HDC hdc=::BeginPaint(hWnd,&ps);
::TextOut(hdc,10,10,szText,strlen(szText));
::EndPaint(hWnd,&ps);
return 0;
}
MFC对BeginPaint进行了封装:
CWnd::BeginPai......
MFC中的GDI绘图(1)(2008-12-21 15:07:00)
摘要:一.关于GDI的基本概念
什么是GDI
Windows绘图的实质就是利用Windows提供的图形设备接口GDI(Graphics Device Interface)将图形绘制在显示器上。
在Windows操作系统中,动态链接库C:\WINDOWS\system32\gdi32.dll(GDI Client DLL)中定义了GDI函数,实现与设备无关的包括屏幕上输出像素、在打印机上输出硬拷贝以及绘制Windows用户界面功能。在Visual C++6.0中的头文件C:\Program Files\Microsoft Visual Studio\VC98\Include\wingdi.h和Visual Studio 2005中的头文件C:\Program Files\Microsoft Visual Studio 8\VC\PlatformSDK\Include\WinGDI.h是访问gdi32.dll库文件的钥匙。下面我们大致浏览一下wingdi.h(included in Windows.h)头文件:
/* Bitmap Header Definition */定义了BITMAP位图结构
/* Mapping Modes */定义了DC中的坐标映射方式,包括以下常用函数:
SetMapMode、SetViewportExtEx、SetViewportOrgEx、 SetWindowExtEx 、SetWindowOrgEx。
/* Stock Logical Objects */系统预定义的堆(STOCK)对象,包括BRUSH、PEN和FONT对象
/* Brush Styles */定义了画刷格式,包括SOLID、HOLLOW、HATCHED等格式
/* Hatch Styles */定义了画刷阴影格式,包括:
HS_VERTICAL /* ||||| */
HS_FDIAGONAL /* \\\\\ */
HS_BDIAGONAL /* ///// */
HS_CROSS /* ++......
命名规范(2008-12-09 11:24:00)
摘要:一.术语定义
Pascal 大小写
将标识符的首字母和后面连接的每个单词的首字母都大写。可以对三字符或更多字符的标识符使用Pascal 大小写。例如: MessageBox
Camel 大小写
标识符的首字母小写,而每个后面连接的单词的首字母都大写。例如:hInstance
二.命名概述
名称应该说明“什么”而不是“如何”。通过避免使用公开基础实现(它们会发生改变)的名称,可以保留简化复杂性的抽象层。
例如,可以使用 GetNextStudent(),而不是 GetNextArrayElement()。
三.命名原则
选择正确名称时的困难可能表明需要进一步分析或定义项的目的。使名称足够长以便有一定的意义,并且足够短以避免冗长。唯一名称在编程上仅用于将各项区分开。表现力强的名称是为了帮助人们阅读;因此,提供人们可以理解的名称是有意义的。不过,请确保选择的名称符合适用语言的规则和标准。
四.命名方法
1、 变量的名字应该是非形式的、简单的、易记忆的。变量的作用越大,它的名字要携带的信息就越,全局变量应该受到更多的注意。
2、 即使对于可能仅出现在几个代码行中的生存期很短的变量,仍然使用有意义的名称。可能的情况下,尽量不要使用原义数字或原义字符串,如For i = 1 To 7,应该使用命名常数,如 For i = 1 To NUM_DAYS_IN_WEEK 以便于维护和理解。
3、 只要合适,在变量名的末尾或开头加计算限定符(Avg、Sum、Min、Max、Index)。
4、 在变量名中使用互补对,如 min/max、begin/end 和 open/close。
5、 布尔变量名应该包含 Is,这意味着 Yes/No 或 True/False 值,如 fileIsFound。
6、 在命名状态变量时,避免使用诸如 Flag 的术语。状态变量不同于布尔变量的地方是它可以具有两个以上的可能值。不是使用 documentFlag,而是使用更具描述性的名称,如 documentFormatType。 (此项只供参考)
7、 变量名并不是越长越好,在力求描述性的同时还要兼顾简洁清晰性。一般一次性临时变量(例如短循环索引)可以被取名为i、j、k、m 和n,它......
由MessageBox透视Win API的调用(2008-12-07 21:56:00)
摘要: 下面我们来看看Windows平台下应用程序是怎么调用Windows提供的底层API服务运行的。
我们编写Win32SDK程序时,需要弹出对话框以作出友好的选择,MessageBox这个API函数就可以实现该功能。在开头要添加<windows.h>,因为其包含了众多的API函数声明头文件。为了探究这个小小的MessageBox是怎么弹出来的,我们右击MessageBox,选择“Go to definition of MessageBox(转到定义) ”将打开<winuser.h>中的#define MessageBox MessageBoxW定义行,我们继续对MessageBoxW右击“Go to definition of MessageBox(转到定义) ”将转到MessageBoxW的函数原型声明处:
int
WINAPI
MessageBoxW(
__in_opt HWND hWnd,
__in_opt LPCWSTR lpText,
__in_opt LPCWSTR lpCaption,
__in UINT uType);
我们在使用Windows窗口操作系统时,经常会蹦出大大小小的窗口, MessageBox只是Windows作为提示的对话框窗口单元。那么,MessageBoxW这个API函数到底在哪里实现的呢?应用程序是如何调用系统接口函数的呢?
动态链接库(.dll)
实际上Windows API函数是定义在一些DLL中的, DLL 实现了代码封装,从这个角度来看DLL才是真正意义上的API函数包,它是非开源Windows操作系统提供给我们的底层接口。DLL的编制与具体的编程语言及编译器无关。
动态链接库dll文件(Linux中与之对应的是的.so)存放在C:\WINDOWS\system目录和C:\WINDOWS\system32目录下,它在被应用程序调用时才同程序相链接。
其中最重要的DLL是User32.dll、Gdi32.dll和Kernel32.dll这三个库文件。这三个库文件中的API函数都在Windows.h头文件中进行了声明。......
Visual Studio的SDK配置(2008-12-07 20:08:00)
摘要:
1. SDK和API的概念
请参考http://blog.programfan.com/article.asp?id=33421
2. Visual Studio的SDK
Visual Studio 6.0自带的SDK是1998年的,目录为C:\Program Files\Microsoft Visual Studio\VC98\,这里简记为VS6SDKDIR。
以下为打开vc6菜单tools->options->directories. 我们看到Platform为Win32,
Show directories for下拉列表框有以下四项:Executable files、Include files、Library files、Source files。
(1)Include files的目录:VS6SDKDIR\Include,VS6SDKDIR \MFC\Include,VS6SDKDIR \ATL\Include
(2)Library files目录:VS6SDKDIR\LIB,VS6SDKDIR \MFC\ LIB
(3)Source files目录:VS6SDKDIR\MFC\SRC,VS6SDKDIR\MFC\Include,VS6SDKDIR\ATL\Include,VS6SDKDIR\CRT\ SRC
如果想更新VC++6.0的SDK,只要从微软网站上下载SDK
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm
然后增加以下路径即可:
Executable files:你的platform安装路径\bin;你的platform安装路径\bin\winnt
Include file:你的platform安装路径\include
Library files:你的platform安装路径\lib
Source files:可添加也可不添加
配置完之后,可以调整各路径与原有路径的前后次序,因为编译和连接......
从char/wchar_t到TCHAR(2)(2008-04-26 00:56:00)
摘要:五.MFC动态字符串类CString
// …\Microsoft Visual Studio 8\VC\atlmfc\include\afx.h
一个CString对象由可变长度的一队字符组成。CString使用类似于Basic的语法提供函数和操作符。连接和比较操作符以及简化的内存管理使CString对象比普通字符串数组容易使用。
CString是基于TCHAR数据类型的对象。如果在你的程序中定义了符号_UNICODE,则TCHAR被定义为类型wchar_t,即16位字符类型;否则,TCHAR被定义为char,即8位字符类型。在UNICODE方式下,CString对象由16位字符组成。非UNICODE方式下,CString对象由8位字符组成。 而VS2005默认TCHAR是wchar而不是char.
当不使用_UNICODE时,CString是多字节字符集(MBCS,也被认为是双字节字符集,DBCS)。注意,对于MBCS字符串,CString仍然基于8位字符来计算,返回,以及处理字符串,并且你的应用程序必须自己解释MBCS的开始和结束字节。
CString 提供 operator LPCTSTR 来在 CString 和 LPCTSTR 之间进行转换。
有关CString的操作请参考MSDN MFC类库。
六.更安全的C语言字符串处理函数 Strsafe.h
// …\Microsoft Visual Studio 8\VC\PlatformSDK\Include\strsafe.h
注意:使用StringCchCopy /StringCchPrintf时要#include "strsafe.h".
STRSAFEAPI是为了解决现有的 C 语言运行时函数的代码太容易产生的“内存溢出”问题。当我们引用 strsafe 系列函数时,原有的 C 语言字符串处理函数都将被自动进行 #undef 处理。调试过程中的警告或出错信息将会告诉我们哪些函数哪些不安全,哪些已经被相应的 strsafe 系列函数取代了。
//1.不赞成使用不安全的函数,以避免产生编译错误
//2.如果你不要安全处理,你可以在包含strsafe.h头文件之前,
#define STRSAFE_NO_DEPRECATE
#ifdef DEPREC......
从char/wchar_t到TCHAR(1)(2008-04-26 00:54:00)
摘要:一.ANSI和UNICODE
1.为什么要使用Unicode?
(1) 可以很容易地在不同语言之间进行数据交换。
(2) 使你能够分配支持所有语言的单个二进制.exe文件或DLL文件。
(3) 提高应用程序的运行效率。
Windows 2000是使用Unicode从头进行开发的,如果调用任何一个Windows函数并给它传递一个ANSI字符串,那么系统首先要将字符串转换成Unicode,然后将Unicode字符串传递给操作系统。如果希望函数返回ANSI字符串,系统就会首先将Unicode字符串转换成ANSI字符串,然后将结果返回给你的应用程序。进行这些字符串的转换需要占用系统的时间和内存。通过从头开始用Unicode来开发应用程序,就能够使你的应用程序更加有效地运行。
Windows 98只支持ANSI,只能为开发ANSI应用程序。 Windows CE 就是使用Unicode的操作系统,完全不支持ANSI版函数。
Microsoft将COM从Win16转换成Win32时,所有COM接口方法都只能接受Unicode字符串。
2.ANSI字符和Unicode字符
ANSI字符类型为CHAR,指向字符串的指针PSTR(LPSTR),指向一个常数字符串的指针PCSTR(LPCSTR);对应的Windows定义的Unicode字符类型为WCHAR(typedef WCHAR wchar_t),指向Unicode字符串的指针PWSTR ,指向一个常数Unicode字符串的指针PCWSTR 。
ANSI “ANSI”
Unicode L“UNICODE”
ANSI/Unicode T(“string”)或_TEXT(“string”)
3.ANSI字符和Unicode字符串的操作
双字节(DBCS)字符集中,字符串的每个字符可以包含一个或两个字节。如果只是调用strlen()函数,那么你就无法知道字符串到底有多少个字符,它只能告诉你到达结尾的0之前有多少个字节。
标准c中的strcpy,strchr,strcat等只能用于ANSI字符串,不能正确处理Unicode字符串,因此也提供了一组补充函数,功能等价,但用于Unicode码。我们来看看string .h字符串头文件中是怎样处理char*和wchar_t......