GUI作图概述
描绘图形
位图
文本输出
设置画刷/画笔/字体
MFC 资源句柄的获得与释放
(本章节中例子都是用 VS2005 编译调试的)
作图步骤
流程图如下:
获取/释放设备资源描述表
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);
程序源码
运行结果:
单击鼠标右键和重绘窗口时
在单击鼠标右键后
绘图操作分类
与设备描述表相关函数
常用绘图函数:
步骤:
流程图如下所示:
代码示例:
.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);
程序源码
运行结果:
文本输出操作
有关文本操作:
相关结构体:
字体结构体
TEXTMETRIC
作用: 记录基本的字体信息
结构体定义(MSDN 链接):
图示:
步骤:
如下图所示:
代码示例:
在窗口重画的时候添加创建新画笔操作:
创建新画笔,并将画笔选入设备描述表中
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); }
绘图是选用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的区别
获得设备资源描述表实现步骤