绘图(VC_Win32)
目录
GUI作图概述
描绘图形
位图
文本输出
设置画刷/画笔/字体
MFC 资源句柄的获得与释放
(本章节中例子都是用 VS2005 编译调试的)
GUI作图概述
作图步骤
- 获得设备描述表资源句柄
- 绘图操作
- 释放设备描述表资源句柄
流程图如下:
获取/释放设备资源描述表
- 获取设备资源描述表: BeginPaint / GetDC
- 释放设备资源描述表: EndPaint / ReleaseDC
BeginPaint / GetDC 两种方式的区别:
BeginPaint GetDC
使用环境 只用于图形刷新时获取设备环境 使用较为广泛
操作区域 无效区 特定窗口的客户区或者整个窗口
释放设备环境所用函数 EndPaint () ReleaseDC ()
代码示例:
在 WM_PAINT 添加 BeginPaint 事件,在 WM_LBUTTONDOWN 添加 GetDC 事件.
BeginPaint 使用:
//获得资源DC hdc=BeginPaint(hwnd,&ps); //获得窗口大小 GetClientRect(hwnd,&rect); //绘制文本 DrawText(hdc,"hellow my first windows program",strlen("hellow my first windows program"),&rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); //释放资源DC EndPaint(hwnd,&ps);
GetDC 使用:
//获得设备资源描述表 hdc = GetDC(hwnd); //绘制带圆角矩形 RoundRect(hdc,10,10,110,60,10,10); //释放设备资源描述表 ReleaseDC(hwnd,hdc);
运行结果:
单击鼠标右键和重绘窗口时
在单击鼠标右键后
绘图操作分类
- 描绘图形
- 位图
- 文本输出
与设备描述表相关函数
- 背景色: GetBkColor / SetBkColor
- 背景模式: GetBkMode / SetBkMode
- 位图: CreateBitMap / CreateBitMapIndirect / CreateCompatibleBitmap / SelectObject
- 画刷: CreateBrushIndirect / CreateDIBPatternBrush CreateHatchBrush / CreatePatternBrush / CreateSolidBrush / SelectObject
- 画刷起始位置: GetBrushOrg / SetBrushOrg / UnrealizeObject
- 剪裁域: ExcludeClipRect / IntersectClipRect / OffsetClipRgn / SelectClipPath / SelectObject / SelectClipRgn
- 颜色调色板: CreatePalette / RealizePalette / SelectPalette
- 绘图方式: GetROP2 / SetROP2
- 字体: CreateFont / CreateFontIndirect / SelectObject
- 字符间距: GetTextCharacterExtra / SetTextCharacterExtra
- 映射方式: GetMapMode / SetMapMode
- 画笔: CreatePen / CreatePenIndirect / SelectObject
- 多边形填充方式: GetPolyFillMode / SetPolyFillMode
- 缩放模式: SetStretchBltMode / GetStretchBltMode
- 文本颜色: GetTextColor / SetTextColor
- 视图范围: GetViewportExtEx / SetViewportExtEx / ScaleViewportExtEx
- 视图原点: GetViewportOrgEx / SetViewportOrgEx
- 窗口范围: GetWindowExtEx / SetWindowExtEx / ScaleWindowExtEx
- 窗口原点: GetWindowOrgEx / SetWindowOrgEx
描绘图形
常用绘图函数:
- 画贝塞尔曲线:
- 画点: SetPixel
- 画矩形: Rectangle
- 画带圆角的矩形: RoundRect
函数原型: BOOL RoundRect( HDC hdc, int nLeftRect, int nTopRect,int nRightRect,int nBottomRect,int nWidth,int nHeight);
参数说明:
- 画椭圆: Ellipse
- 画椭圆的一部分(即画一个弦): Chord
- 画一个扇形区并用当前画刷填充: Pie
- 画椭圆弧线: Arc
函数原型: BOOL Arc(HDC hdc,int nLeftRect, int nTopRect,int nRightRect,int nBottomRect,int nXStartArc,int nYStartArc,int nXEndArc,int nYEndArc);
参数说明:
- 画椭圆弧线: ArcTo
- 画正圆弧线: AngleArc
函数原型: BOOL AngleArc(HDC hdc,int X,int Y,DWORD dwRadius,FLOAT eStartAngle,FLOAT eSweepAngle);
参数说明:
- 画一系列相连的直线:
- 画线条:
位图
步骤:
- 建立位图资源
- 载入/创建位图资源
- 获取设备内存
- 选入内存设备
- 贴图
流程图如下所示:
代码示例:
.rc 内容(位图资源):
IDB_BITMAP1 BITMAP "8c8a09f1gw1ds3qh4vtcyj.bmp"
位图(8c8a09f1gw1ds3qh4vtcyj.bmp 尺寸信息:440*622):
在鼠标左键单击事件中添加贴图操作:
加载位图:
hBmp = LoadBitmap(hinstance,MAKEINTRESOURCE(IDB_BITMAP1));
创建兼容 DC 并将位图选入兼容 DC 中:
hcmdc = CreateCompatibleDC(hdc);
SelectObject(hcmdc,hBmp);
获得窗口大小(被显示的区域),获得位图信息(要显示的区域)
//获取窗口大小 GetClientRect(hwnd,&rect); //获取位图信息(在 StretchBlt 时候有用到,而 BitBlt 没有) GetObject(hBmp, sizeof(BITMAP), &bmp);
显示位图:
//显示方式一, 按原图比例显示 BitBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,hcmdc,0,0,SRCCOPY); //显示方式二, 拉伸式显示 StretchBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,hcmdc,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY);
运行结果:
- 在未点击鼠标右键时候:
- 点击鼠标左键(用 BitBlt 方法):
- 点击鼠标左键(用 StretchBlt 方法):
文本输出
文本输出操作
- 文字输出: TextOut
- 显示字符串: DrawText
有关文本操作:
- 获取文字信息: GetTextMetrics
- 格式化文字: GetTextExtentPoint32
- 设置字体颜色和背景颜色:
- 字体: SetTextColor
- 背景: SetBkColor
设置画刷/画笔/字体
相关结构体:
字体结构体
TEXTMETRIC
作用: 记录基本的字体信息
结构体定义(MSDN 链接):
typedef struct tagTEXTMETRIC { LONG tmHeight; // Specifies the height (ascent descent) of characters. LONG tmAscent; // Specifies the ascent (units above the base line) of characters. LONG tmDescent; // Specifies the descent (units below the base line) of characters. LONG tmInternalLeading; // Specifies the amount of leading (space) inside the bounds set by the tmHeight member. LONG tmExternalLeading; // Specifies the amount of extra leading (space) that the application adds between rows. LONG tmAveCharWidth; // Specifies the average width of characters in the font. LONG tmMaxCharWidth; // Specifies the width of the widest character in the font. LONG tmWeight; // Specifies the weight of the font. LONG tmOverhang; // Specifies the extra width per string that may be added to some synthesized fonts LONG tmDigitizedAspectX; // Specifies the horizontal aspect of the device for which the font was designed. LONG tmDigitizedAspectY; // Specifies the vertical aspect of the device for which the font was designed. TCHAR tmFirstChar; // Specifies the value of the first character defined in the font. TCHAR tmLastChar; // Specifies the value of the last character defined in the font. TCHAR tmDefaultChar; // Specifies the value of the character to be substituted for characters not in the font. TCHAR tmBreakChar; // Specifies the value of the character that will be used to define word breaks for text justification. BYTE tmItalic; // Specifies an italic font if it is nonzero. BYTE tmUnderlined; // Specifies an underlined font if it is nonzero. BYTE tmStruckOut; // Specifies a strikeout font if it is nonzero. BYTE tmPitchAndFamily; // Specifies information about the pitch, the technology, and the family of a physical font. BYTE tmCharSet; // Specifies the character set of the font. } TEXTMETRIC, *PTEXTMETRIC;
图示:
步骤:
- 创建资源句柄
- 创建自定义资源/调用系统资源
- 将资源选入系统
如下图所示:
代码示例:
在窗口重画的时候添加创建新画笔操作:
创建新画笔,并将画笔选入设备描述表中
pen = CreatePen(PS_DOT,3,RGB(255,100,100)); SelectObject(hdc,pen);
为了区别创建画笔前和创建画笔后的作图的区别
在创建画笔前绘制一条直线:
//rect 为记录窗口大小的 RECT 结构体 MoveToEx(hdc,(rect.left+rect.right)/2-130,(rect.top+rect.bottom)/2-50,NULL); LineTo(hdc,(rect.left+rect.right)/2+130,(rect.top+rect.bottom)/2-50);
在创建画笔后绘制一条直线:
MoveToEx(hdc,(rect.left+rect.right)/2-130,(rect.top+rect.bottom)/2+50,NULL); LineTo(hdc,(rect.left+rect.right)/2+130,(rect.top+rect.bottom)/2+50);
运行结果:
程序源码
#include<windows.h> #include"resource.h" HINSTANCE hinstance; LRESULT CALLBACK textprom( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // pointer to command line int nCmdShow // show state of window ) { WNDCLASS wndclass; HWND hwnd; MSG msg; //设计窗口类 wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); wndclass.hIcon=LoadIcon(NULL,IDI_ERROR); wndclass.hInstance=hInstance; wndclass.lpfnWndProc=textprom; wndclass.lpszClassName="text"; wndclass.lpszMenuName=NULL; wndclass.style=CS_HREDRAW | CS_VREDRAW; //注册窗口类 if(!RegisterClass(&wndclass)) { MessageBox(NULL,"create windows error!","error",MB_OK | MB_ICONSTOP); } //创建无菜单资源的窗口窗口 hwnd=CreateWindow("text","hellow world",WS_DLGFRAME | WS_MINIMIZEBOX | WS_SYSMENU,0,0,500,300,NULL,NULL,hInstance,NULL); //显示更新窗口 ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); hinstance = hInstance; //消息循环 while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK textprom( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { HDC hdc,hcmdc; PAINTSTRUCT ps; RECT rect; HBITMAP hBmp; SIZE size; BITMAP bmp; HPEN pen; switch(uMsg) { //重绘事件 case WM_PAINT: hdc=BeginPaint(hwnd,&ps); //显示文本 GetClientRect(hwnd,&rect); DrawText(hdc,"hellow my first windows program",strlen("hellow my first windows program"),&rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); //画笔 MoveToEx(hdc,(rect.left+rect.right)/2-130,(rect.top+rect.bottom)/2-50,NULL); LineTo(hdc,(rect.left+rect.right)/2+130,(rect.top+rect.bottom)/2-50); pen = CreatePen(PS_DOT,3,RGB(255,100,100)); SelectObject(hdc,pen); MoveToEx(hdc,(rect.left+rect.right)/2-130,(rect.top+rect.bottom)/2+50,NULL); LineTo(hdc,(rect.left+rect.right)/2+130,(rect.top+rect.bottom)/2+50); EndPaint(hwnd,&ps); break; //绘制圆角矩形 case WM_LBUTTONDOWN: hdc = GetDC(hwnd); RoundRect(hdc,10,10,110,60,10,10); ReleaseDC(hwnd,hdc); break; //贴图 case WM_RBUTTONDOWN: hdc = GetDC(hwnd); hBmp = LoadBitmap(hinstance,MAKEINTRESOURCE(IDB_BITMAP1)); hcmdc = CreateCompatibleDC(hdc); SelectObject(hcmdc,hBmp); GetClientRect(hwnd,&rect); GetObject(hBmp, sizeof(BITMAP), &bmp); StretchBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,hcmdc,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY); //BitBlt(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top,hcmdc,0,0,SRCCOPY); ReleaseDC(hwnd,hdc); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd,uMsg,wParam,lParam); }
MFC 资源句柄的获得与释放
绘图是选用GDI资源的说明
在程序中,当构造函数构造一个GDI对象后,该对象并不会立刻生效,必须选入设备描述表,它才会在以后的操作中生效,利用SelectObject函数可以实现把GDI对象选入设备描述表中,并且返回指向先前GDI设备对象的指针,一般情况下,在完成绘图操作后,都要利用SelectObject函数吧先前的GDI对象选入设备表,以便使恢复到先前状态
GDI绘图对象(CPen,CFont.CBitmap,CBrush)都派生于CGdiObject类对象,都有一个m_hObject记录与对应资源联系的关系,当其对象与对应的资源调用CreateXXXX建立联系后若想把对象关联上新的资源时候,必须先对旧的资源释放才能和新的资源建立上联系,可以用CGdiObject对象的DeleteObject函数去切断与旧资源的联系,并释放旧的资源
相关函数
获得资源设备表
函数原型
CDC* GetDC();
返回值: 如果调用成功,则返回CWnd客户区的设备环境;否则,返回NULL。这个指针可能是临时的,不能被保存以供将来使用
说明: 这个函数获得一个指针,指向一个客户区的公用的、属于类的或者私有的设备环境,依赖于为CWnd指定的类风格。对于公用的设备环境,GetDC每次获得设备环境时都给它赋予缺省值。对于属于类的或者私有的设备环境,GetDC保持原来的属性不变。在随后的图形设备接口(GDI)函数中可以使用设备环境以在客户区中绘图
释放资源设备表
函数原型
int ReleaseDC( CDC* pDC );
参数说明: pDC 标识了要释放的设备环境
返回值: 如果成功,则返回非零值;否则返回0
说明: 释放设备环境,以供其它应用程序使用。ReleaseDC成员函数的效果依赖于设备环境的
CPainDC与CCleintDC的区别
- CPaintDC
- CPaintDC继承于CDC
- 在构造函数中调用BeginPaint
- 在析构函数调用EndPaint函数
- 用于相应WM_PAINT消息的函数中
- CClientDC
- CClientDC继承于CDC
- 在析构函数中调用GetDC
- 在析构函数中调用ReleaseDC
- 用于非WM_PAINT消息的GDI绘图函数中
获得设备资源描述表实现步骤