目录
1.设备描述表(Device Context, DC) 10
(2)对于位图等复杂图形需要在内存中保存一个副本,重绘窗口的时候再将副本输出... 13
(3)记录曾经发生过的事件,窗口刷新的时候重新执行这个事件... 13
(3)绘制椭圆弧线的函数Arc,从起始点逆时针到终止点的曲线... 14
(4)画一个饼并用当前画刷进行填充的函数Pie(),从起始径线逆时针到终止径线扫过地扇形... 14
(5)绘制一个矩形,并用当前画刷进行填充的函数Rectangle() 14
(6)绘制一个圆角矩形,并用当前画刷填充的函数RoundRect() 15
(7)绘制一个椭圆,并用当前画刷填充的函数Ellipse() 15
(8)绘制一个多边形,并用当前画刷进行填充的函数Polygon() 15
正文
一、Windows编程基础知识
Windows程序根据事件或消息的不同驱动运行处理函数Proc,这个过程叫做事件驱动
1.句柄
句柄是用于唯一标识对象的PVOID数据、一个4字节长的数值,通过句柄能够访问对象的信息
HWND | 窗口句柄 |
HINSTANCE | 当前实例的句柄,管理当前窗口的有关资源(图标、光标等) |
HCURSOR | 光标句柄 |
HFONT | 字体句柄 |
HPEN | 画笔句柄 |
HBRUSH | 笔刷句柄 |
HDC | 设备环境句柄 |
HBITMAP | 位图句柄 |
HICON | 图标句柄 |
HMENU | 菜单句柄 |
HFILE | 文件句柄 |
2.消息
作用是信息交换,由消息号UINT、字参数wParam、长字参数lParam,长字参数和具体消息的附加信息有关,比如:
typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
//这个消息到队列的时间
DWORD time;
//消息产生时,屏幕光标的位置,横坐标x、纵坐标y
POINT pt;
}MSG;
(1)系统定义的消息分类
BM_ | 按钮控件消息 |
CB_ | 组合框控件消息 |
DM_ | 下压式按钮控件消息 |
EM_ | 编辑控件消息 |
LB_ | 列表框控件消息 |
SBM_ | 滚动条控件消息 |
WM_ | 窗口消息 |
(2)不同消息的取值范围
系统定义消息(部分1) | 0x0000-0x03FF |
系统定义消息(部分2) | 0x8000-0xBFFF |
用户自定义的内部消息 | 0x0400-0x07FF |
用户自定义的外部消息 | 0xC000-0xFFFF |
(3)Windows应用中的常用消息
①WM_LBUTTONDOWN
点击鼠标左键会触发这个消息,字参数wParam表示鼠标的单击状态,长字参数lParam的低字节表示当前光标的x坐标、高字节表示当前光标的y坐标;和WM_LBUTTONDOWN类似的消息还有松开鼠标左键WM_LBUTTONUP、点击鼠标右键WM_RBUTTONDOWN、松开鼠标右键WM_RBUTTONUP、双击鼠标左键WM_LBUTTONBLCLK、双击鼠标右键WM_RBUTTONDBLCLK。
wParam的值 | 意义 |
MK_LBUTTON | 点击了鼠标左键 |
MK_MBUTTON | 点击了鼠标中键 |
MK_RBUTTON | 点击了鼠标右键 |
②WM_KEYDOWN
按下非系统控制键时产生的消息,非系统键指不是系统内置的键,类似消息有松开非系统键产生的消息WM_KEYUP;字参数wParam表示按下或释放的键,长字参数lParam表示按键的重复次数等信息;VK_END、VK_HOME、VK_DELETE、VK_LEFT、VK_RIGHT、VK_UP、VK_DOWN
③WM_CHAR
也是按下非系统键产生的消息,wParam表示按键的ASCII码值、lParam表示重复次数等信息,VK_BACK、VK_RETURN
④WM_CREATE
由CreateWindow()触发,wParam未使用、lParam是一个指向数据结构CREATESTRUCT的指针,修改这个结构体就可以在创建窗口的时候给CreateWindow()传递参数
⑤WM_CLOSE
窗口关闭时产生的消息
⑥WM_DESTROY
由DestroyWindow()触发
⑦WM_QUIT
由PostQuitMessage()触发,wParam表示程序退出时的有关信息,lParam未使用
⑧WM_PAINT
窗口的显示状态发生变化的时候触发,比如窗口位置、大小发生变化等情况会触发WM_PAINT消息
⑨WM_COMMAND
和用户定义的控件ID有关的消息,也包括一些内置消息IDOK、IDCANCEL
二、Windows应用的基本结构
Windows项目中可能会遇到这几种类型的文件,.cpp程序的源文件、.h头文件、.def模块定义文件、.rc资源描述文件
1.数据类型
LONG | 32位有符号整数 |
DWORD | 32位无符号整数 |
UINT | 32位无符号整数 |
BOOL | 布尔值 |
LPTSTR | 指向字符串的32位指针(用于Unicode) |
LPCTSTR | 指向字符串常量的32位指针(用于Unicode) |
LPSTR | 指向字符串的32位指针 |
LPCSTR | 指向字符串常量的32位指针 |
2.数据结构
(1)MSG
消息的结构体,包含消息必要的信息
(2)WNDCLASSEX
一个窗口类的全部信息,通过结构体可以修改一个窗口类的属性信息
Typedef struct
{
//结构体的大小,通常取sizeof(WNDCLASSEX)
UINT cbSize;
//窗口类的样式,一般设为0
UINT style;
//指向处理函数的指针
WNDPROC lpfnWndProc;
//分配给窗口类的额外字节数
int cbClsExtra;
//分配给窗口实例的额外字节数
int cbWndExtra;
//窗口类的实例句柄
HANDLE hInstance;
//图标
HICON hIcon;
//光标样式
HCURSOR hCursor;
//背景笔刷
HBRUSH hbrBackground;
//菜单资源的名字
LPCTSTR lpszMenuName;
//窗口类的名字
LPCTSTR lpszClassName;
//小图标,暂不知道差别在哪里,小图标和图标的取值一样
HICON hIconSm;
}WNDCLASSEX;
(3)POINT
typedef struct tagPOINT
{
LONG x;
LONG y;
}POINT;
(4)RECT
矩形区域
typedef struct _RECT
{
//矩形框左上角的x坐标值
LONG left;
//矩形框左上角的y坐标值
LONG top;
//矩形框右下角的x坐标值
LONG right;
//矩形框右下角的y坐标值
LONG bottom;
}RECT;
3.入口函数WinMain()
(1)参数说明
HINSTANCE hThisInstance | 应用程序当前实例的句柄 |
HINSTANCE hPrevInstance | 其他实例的句柄 |
LPSTR lpszArgument | 指向命令行参数的指针 |
int nCmdShow | 程序开始执行时窗口显示方式,这是一个整数标识 |
(2)定义窗口类
给结构体WNDCLASSEX特定的属性值,可能会用到的函数:
添加特定的图标
HICON LoadIcon(
//需要设置图标的对象的句柄,设置为NULL可能会快些
HINSTANCE hInstance,
//图标的名字
LPCTSTR lpIconName);
设置窗口的光标
HCURSOR LoadCursor(
//需要设置光标的对象的句柄,设置为NULL可能会快些
HINSTANCE hInstance,
//光标的名字
LPCTSTR lpCursorName);
设置窗口背景
HBRUSH GetStockObject(
//笔刷的名字
int nBrush);
(3)注册窗口类
//如果注册成功返回值为真TRUE
BOOL RegisterClassEx(WNDCLASSEX&);
(4)创建窗口
GetSystemMetrics (SM_CXSCREEN)获取全屏的宽度、GetSystemMetrics (SM_CYSCREEN)获取全屏的高度,类似的有SM_CXFULLSCREEN、不含任务栏;LOWORD(GetDialogBaseUnits())得到x方向的相对长度、HIWORD(GetDialogBaseUnits())得到y方向的相对长度
CreateWindow函数
HWND CreateWindow(
//窗口类的名字
LPCTSTR lpszClassName,
//窗口标题的名字
LPCTSTR lpszTitle,
//窗口的样式
DWORD dwStyle,
//窗口左上角的x坐标
int x,
//窗口左上角的y坐标
int y,
//窗口的宽度
int nWidth,
//窗口的高度
int nHeight,
//当前窗口的父窗口句柄
HWND hwndParent,
//当前窗口的主菜单句柄
HMENU hMenu,
//当前应用程序的实例句柄
HINSTANCE hInstance,
//传递给窗口的参数值的指针
LPVOID lpParam);
窗口常用样式
多个样式通过位或运算组合成窗口的样式
WS_BORDER | 带边框的窗口 |
WS_CAPTION | 带标题栏的窗口 |
WS_CHILD | 子窗口,不能和WS_POPUP一起使用 |
WS_HSCROLL | 带水平滚动条的窗口 |
WS_MAXIMIZEDBOX | 带最大化按钮的窗口 |
WS_MAXIMIZE | 最大化的窗口 |
WS_MINIMIZEBOX | 带最小化按钮的窗口 |
WS_MINIMIZE | 最小化的窗口 |
WS_OVERLAPPED | 带边框和标题栏的窗口 |
WS_OVERLAPPEDWINDOW | 带边框、标题栏、系统菜单、最大最小化按钮的窗口 |
WS_POPUP | 弹出式窗口,不能和WS_CHILD一起使用 |
WS_POPUPWINDOW | 带边框和系统菜单的弹出式窗口 |
WS_SYSMENU | 带系统菜单的窗口 |
WS_VSCROLL | 带垂直滚动条的窗口 |
WS_VISIBLE | 可见窗口,ShowWindow()或者SetWindowPos()可以改变它的值 |
WS_TABSTOP | 可能和tab键的选中状态有关,必要时取否定NOT |
(5)显示窗口
ShowWindow函数将窗口显示在屏幕上
BOOL ShowWindow(
//窗口句柄
HWND hwnd,
//显示形式的标识
int nCmdShow);
UpdateWindow函数更新窗口
UpdateWindow(HWND hwnd);
显示样式的标识
SW_HIDE | 隐藏窗口 |
SW_SHOW | 按当前的位置和大小激活窗口 |
SW_SHOWNA | 按当前的状态显示窗口 |
SW_SHOWNORMAL | 显示并激活窗口 |
(6)消息循环
Windows产生的消息将放到程序的消息队列中,程序将消息取出并传递给处理函数
//从消息队列中取出一条消息放大MSG类型的结构中,最后两个参数表示过滤的最小消息号、过滤的最大消息号,都为0表示不过滤
//当取到WM_QUIT消息时程序退出循环
While(GetMessage(MSG&,NULL,0,0)
{
//将虚拟键转换为字符信息
TranslateMessage(MSG&);
//将消息传递给制定的处理函数
DispatchMessage(MSG&);
}
4.处理函数
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case ...:
...;
break;
...
case WM_DESTROY:
PostQuitMessage (0);
break;
default:
//我们不处理的消息交给系统以默认方式处理
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
三、图形绘制
Windows图形设备接口GDI屏蔽了硬件设备的差异,分担了程序的硬件设备适配器的功能;SetTimer()设置定时器,可以按照一定的时间间隔“提醒”某个窗口,从而得到动态的效果对应的事件是WM_TIMER、计时器的编号和wParam有关、KillTimer()将销毁一个定时器
1.设备描述表(Device Context, DC)
位图 | 大小、像素、颜色、缩放模式 |
画刷 | 样式、颜色、起始点 |
调色板 | 颜色和尺寸 |
字体 | 字体名称、粗细、大小、所属字符集 |
画笔 | 样式、宽度、颜色 |
区域 | 位置和大小 |
2.设备描述表的默认属性和相关函数
背景色 | WHITE | SetBkColor() GetBkColor() |
背景模式 | OPAQUE | SetBkMode() GetBkMode() |
位图 | CreateBitMap() CreateBitMapIndirect() CreateCompatibleBitmap() SelectObjce() | |
画刷 | WHITE_BRUSH | CreateBrushIndirect() CreateDIBPatternBrush() CreateHatchBrush() CreatePatternBrush() CreateSolidBrush() SelectObject() |
画刷的起始位置 | (0,0) | SetBrushOrg() GetBrushOrg() UnrealizeObject() |
剪截域 | DISPLAY SURFACE | ExcludeCipRect() IntersectClipRect() OffsetClipRgn() SelectClipPath() SelectObject() SelectClipRgn() |
调色板 | DEFAULT_PALETTE | CreatePalette() RealizePalette() SelectPalette() |
绘图方式 | R2_COPYPEN | SetROP2() GetROP2() |
字体 | SYSTEM_FONT | CreateFont() CreateFontIndirect() SelectObject() |
字符间距 | 0 | SetTextCharacterExtra() GetTextCharacterExtra() |
映射方式 | MM_TEXT | SetMapMode() GetMapMode() |
画笔 | BLACK_PEN | CreatePen() CreatePenIndirect() SelectObject() |
多边形填充方式 | ALTERNATE | SetPolyFillMode() GetPolyFillMode() |
缩放模式 | BLACKONWHITE | SetStretchBltMode() GetStretchBltMode() |
文本颜色 | BLACK | SetTextColor() GetTextColor() |
视图范围 | (1,1) | SetViewportExtEx() GetViewportExtEx() ScaleViewportExtEx() |
视图原点 | (0,0) | SetViewportOrgEx() GetViewportOrgEx() |
窗口范围 | (1,1) | SetWindowExtEx() GetWindowExtEx() ScaleWindowExtEx() |
窗口原点 | (0,0) | SetWindowOrgEx() GetWindowOrgEx() OffsetWindowOrgEx() |
3.图形刷新的办法
用户区移动或显示、用户区窗口大小发生改变、程序通过滚动条滚动窗口、下拉式菜单关闭后需要恢复被覆盖的部分、光标穿过用户区、图标拖过用户区都会导致图形的显示状态发生改变时,Windows系统将发送WM_PAINT消息给应用程序
(1)对于简单的图形重新绘制即可
InvalidateRect(hwnd,NULL,TRUE);
(2)对于位图等复杂图形需要在内存中保存一个副本,重绘窗口的时候再将副本输出
(3)记录曾经发生过的事件,窗口刷新的时候重新执行这个事件
4.常用绘图函数
(1)设置画笔当前位置的函数MoveToEx()
BOOL MoveToEx(
HDC hdc,
//最新位置
int x,
int y,
//原位置的POINT结构体指针
LPPOINT lpPoint);
(2)从当前位置到指定位置画线的函数LineTo
BOOL LineTo(HDC hdc,int x,int y);
从当前位置开始依次连接各点
BOOL Polyline(
HDC hdc,
//POINT结构体数组的指针
LPPOINT lpPoints,
//数组中元素的个数
Int nCount);
(3)绘制椭圆弧线的函数Arc,从起始点逆时针到终止点的曲线
BOOL Arc(
HDC hdc,
//边框矩形左上角的逻辑坐标
int x1,int y1,
//边框矩形右下角的逻辑坐标
int x2,int y2,
//起始点坐标,可以不在椭圆上(点和中心的连线与椭圆的交点,起到方向的作用)
int x3,int y3,
//终止点坐标,可以不在椭圆上(点和中心的连线与椭圆的交点,起到方向的作用)
int x4,int y4);
(4)画一个饼并用当前画刷进行填充的函数Pie(),从起始径线逆时针到终止径线扫过地扇形
BOOL Pie(
HDC hdc,
//边框矩形左上角的逻辑坐标
int x1,int y1,
//边框矩形右下角的逻辑坐标
int x2,int y2,
//起始点坐标,可以不在椭圆上(点和中心的连线与椭圆的交点,起到方向的作用)
int x3,int y3,
//终止点坐标,可以不在椭圆上(点和中心的连线与椭圆的交点,起到方向的作用)
int x4,int y4);
(5)绘制一个矩形,并用当前画刷进行填充的函数Rectangle()
BOOL Rectangle(
HDC hdc,
//矩形左上角的逻辑坐标
int x1,int y1,
//矩形右下角的逻辑坐标
int x2,int y2);
(6)绘制一个圆角矩形,并用当前画刷填充的函数RoundRect()
BOOL RoundRect(
HDC hdc,
//矩形左上角的逻辑坐标
int x1,int y1,
//矩形右下角的逻辑坐标
int x2,int y2,
//圆角的宽度
int nWidth,
//圆角的高度
int nHeight);
(7)绘制一个椭圆,并用当前画刷填充的函数Ellipse()
BOOL Ellipse(
HDC hdc,
//边界矩形左上角的逻辑坐标
int x1,int y1,
//边界矩形右下角的逻辑坐标
int x2,int y2);
(8)绘制一个多边形,并用当前画刷进行填充的函数Polygon()
BOOL Polygon(
HDC hdc,
//POINT结构体数组的指针
LPPOINT lpPoints,
//数组中元素的个数
int nCount);
5.图形绘制的一般步骤
(1)获取设备环境
①响应WM_PAINT消息,对无效区域进行刷新
HDC BeginPaint(HWND,PAINTSTRUCT&);
BOOL EndPaint(HWND,PAINTSTRUCT&);
结构体PAINTSTRUCT
typedef struct tagPAINTSTRUCT
{
//设备环境句柄
HDC hdc;
//一般取真TRUE,表示擦除无效矩形的阴影
BOOL fErase;
//无效矩形
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
}PAINTSTRUCT;
②独立于WM_PAINT消息的刷新
//也可以使用GetDCEx(),它是GetDC()的扩展、提供了更丰富的操作
HDC GetDC(HWND);
int ReleaseDC(HWND,HDC);
(2)映射模式
MM_TEXT是默认的映射模式;对逻辑坐标系的定义(窗口),屏蔽了输出设备的坐标系差异(视口)
① 可选的映射模式
映射模式 | 坐标系方向 | 一个逻辑单位的大小 |
MM_ANISOTROPIC | 可选 | 由SetWindowExtEx()或SetViewPortExtEx()确定 |
MM_ISOTROPIC | 可选,x轴和y轴单位长度相同 | 由SetWindowExtEx()或SetViewPortExtEx()确定 |
MM_HIENGLISH | x向右,y向上 | 0.001英寸 |
MM_HIMETRIC | x向右,y向上 | 0.01毫米 |
MM_LOENGLISH | x向右,y向上 | 0.01英寸 |
MM_LOMETRIC | x向右,y向上 | 0.1毫米 |
MM_TEXT | x向右,y向下 | 一个像素 |
MM_TWIPS | x向右,y向上 | 1/1440英寸 |
② 设置映射模式
int GetMapMode(HDC);
int SetMapMode(HDC hdc,int nMapMode);
③ 设置窗口区域、视口区域
BOOL SetWindowExtEx(
HDC hdc,
//窗口区域的逻辑高度
int nHeight,
//窗口区域的逻辑宽度
int nWidth,
//调用前窗口区域的SIZE结构体的地址,取NULL将忽略之前的尺寸
LPSIZE lpSize);
设置视口区域
BOOL SetViewportExtEx(
HDC hdc,
/视口区域的物理高度
int nHeight,
//视口区域的物理宽度
int nWidth,
//调用前窗口区域的SIZE结构体的指针,取NULL将忽略之前的尺寸
LPSIZE lpSize);
④ 当映射模式是MM_ANISOTROPIC或者MM_ISOTROPIC时,可以设置窗口、视口的默认原点
BOOL SetWindowOrgEx(
HDC hdc,
//窗口原点的最新位置
int x,
int y,
//调用前窗口原点的POINT结构体的指针,取NULL将忽略之前的尺寸
LPPOINT lpPoint);
BOOL SetViewportOrgEx(
HDC hdc,
//视口原点的最新位置
int x,
int y,
//调用前视口原点的POINT结构体的指针,取NULL将忽略之前的尺寸
LPPOINT lpPoint);
⑤ 获取用户区的大小
绘制图形的时候可能会参考用户区的大小
BOOL GetWindowRect(
//目的窗口句柄
HWND hWnd,
//将结果装入RECT结构体的指针中
LPRECT lpRect);
BOOL GetClientRect(
//用户区的窗口句柄
HWND hWnd,
//将结果装入RECT结构体的指针中
LPRECT lpRect);
(3)使用绘图工具和颜色
①画笔
创建画笔
//使用系统内置的画笔
HPEN hP=(HPEN)GetStockObject(BLACK_PEN);
//使用自定义的画笔
HPEN hP=CreatePen(
//画笔的样式
int nPenStyle,
//画笔的像素宽度,取0表示一个像素宽度
int nWidth,
//画笔的颜色
COLORREF rgbColor);
画笔的样式
PS_DASH | 虚线 |
PS_DASHDOT | 点划线 |
PS_DASHDOTDOT | 双点划线 |
PS_DOT | 点线 |
PS_INSIDEFRAME | 实线边框线 |
PS_NULL | 无 |
PS_SOLID | 实线 |
将画笔置入设备环境
//hPenOld是上一次使用的画笔
HPEN hPenOld=SelectObject(hdc,hP);
删除画笔
//恢复原来的画笔
SelectObject(hdc,hPenOld);
//删除画笔
DeleteObject(hP);
②画刷
创建画刷
//使用系统内置的画刷
HBRUSH hBr=(HBRUSH)GetStockObject(int nBrushStyle);
画刷的样式
BLACK_BRUSH | 黑色画刷 |
DKGRAY_BRUSH | 深灰色画刷 |
GRAY_BRUSH | 灰色画刷 |
HOLLOW_BRUSH | 虚画刷 |
LTGRAY_BRUSH | 浅灰色画刷 |
NULL_BRUSH | 空画刷 |
WHITE_BRUSH | 白色画刷 |
DC_BRUSH | 纯色画刷,由SetDCBrushColor确定 |
创建指定颜色的单色画刷
HBRUSH hBr=(HBRUSH)CreateSolidBrush(COLORREF rgbColor);
创建带阴影和颜色的画刷
HBRUSH hBr=(HBRUSH)CreateHatchBrush(
//阴影样式
int nHatchStyle,
COLORREF rgbColor);
阴影样式
HS_BDIAGONAL | 从左上角到右下角45度的阴影线 |
HS_DIAGCROSS | 45度叉线 |
HS_FDIAGONAL | 从左下角到右上角45度的阴影线 |
HS_CROSS | 垂直相交的阴影线 |
HS_HORIZONTAL | 水平阴影线 |
HS_VERTICAL | 垂直阴影线 |
将画刷置入设备环境
//hBrOld是上一次使用的画刷
HBRUSH hBrOld=SelectObject(hdc,hBr);
删除画刷
//恢复原有画刷
SelectObject(hdc,hBrOld);
DeleteObject(hBr);
③颜色
画笔用于绘制线条、画刷用于区域填充
Windows使用32位无符号整数表示颜色,从低位到高位依次是蓝、绿、红,各占一个字节(8个bit位)
COLORREF RGB(int nRed,int nGreen,int nBlue);
四、文字输出和字体设置
由_T(“”)创建字符串常用变量,在VC的环境下默认是unicode字符集的用L(“”)、或者设置为多字节字符集的工程;一个汉字的处理长度是一个英文字母的两倍,字体的选择和超级键+fonts下面的字体有关
1.选择字体
使用系统内置的字体
//nFont是字符集可以是ANSI_CHARSET、BALTIC_CHARSET、CHINESEBIG5_CHARSET、DEFAULT_CHARSET、GB2312_CHARSET等
HFONT hf=(HFONT)GetStockObject(int nfont);
SelectObject(hdc,hf);
使用自定义的字体
HFONT CreateFont(
//字体逻辑高度,取0表示使用系统默认值
Int nHeight
//字体逻辑宽度,取0表示使用系统默认值
Int nWidth,
//每行文字相对于页底的角度,一个单位表示十分之一度
Int nEscapement,
//每个文字相对于页底的角度,一个单位表示十分之一度
Int nOrientation,
//字体的粗细,取值是0-1000,400是正常字体700是黑体
Int nWeight,
//非零值表示倾斜
DWORD fdwItalic
//非零值表示下划线,
DWORD fdwUnderline,
//非零值表示中划线
DWORD fdwStrikeOout,
//字符集
DWORD fdwCharset,
//输出精度,一般取OUT_DEFAULT_PRECIS
DWORD fdwOutputPrecision,
//剪裁精度,一般取CLIP_DEFAULT_PRECIS
DWORD fdwClipPrecision,
//输出质量,一般取DEFAULT_QUALITY
DWORD fdwQuality,
//字体间距和字体系列,一般取DEFAULT_PITCH
DWORD fdwPitchAndFamily,
//字体名,和C:Windowsfonts下面的字体有关
DWORD lpszFacename);
创建全局字体
case WM_CREATE:
hdc=GetDC(hwnd);
GetTextMetrics(hdc,&tm);
nLnHeight=tm.tmHeight+tm.tmExternalLeading;
nCharWidth=tm.tmAveCharWidth;
CreateCaret(hwnd,NULL,nCharWidth/10,tm.tmHeight);
ShowCaret(hwnd);
ReleaseDC(hwnd,hdc);
break;
2.设置字体颜色
SetTextColor(hdc,crColor);
SetBkColor(hdc,crColor);
3.文本输出
从某个位置开始输出
BOOL TextOut(
HDC hdc,
//字符串的起始坐标
Int x,int y,
//字符串
LPCTSTR lpString,
//字符串的字符数
Int nCount);
文本输出到一个矩形中
Int DrawText(
HDC hdc,
//字符串
LPCTSTR lpString,
//字符串中的字符数
Int nCount,
//矩形的指针
LPRECT lpRect,
//其他选项
UINT uFormat);
全局字体输出
case WM_PAINT:
hdc=BeginPaint(hwnd,&PtStr);
for(int i=0; i<=nNumLine; ++i)
TextOut(hdc,0,nLnHeight*i,cCharInfo[i],nArrayPos[i]);
SIZE size;
GetTextExtentPoint(hdc,cCharInfo[nY],nX,&size);
nXCaret=size.cx;
nYCaret=nLnHeight*nY;
SetCaretPos(nXCaret,nYCaret);
EndPaint(hwnd,&PtStr);
break;
4.删除字体
DeleteObject(hFont);
五、键盘和鼠标
1.键盘消息
(1)wParam中的虚拟码
扫描码是对按键的唯一标识、当按下或释放时扫描码发挥作用,虚拟码用于屏蔽不同设备扫描码的差异;键盘的处理要结合WM_CHAR、WM_KEYDOWN等消息
VK_ENTER | Enter键 |
VK_SHIFT | Shift键 |
VK_ALT | Alt键 |
VK_CAPS_LOCK | Caps Lock键 |
VK_PAGE_UP | Page Up键 |
VK_END | End键 |
VK_LEFT | 左箭头 |
VK_UP | 上箭头 |
VK_0-VK_9 | 0-9键 |
VK_TAB | Tab键 |
VK_BACK_SPACE | Back Space键 |
VK_CONTROL | Ctrl键 |
VK_PAUSE | Pause键 |
VK_ESCAPE | Esc键 |
VK_PAGE_DOWN | Page Down键 |
VK_HOME | Home键 |
VK_RIGHT | 右箭头 |
VK_DOWN | 下箭头 |
VK_A-VK_Z | A-Z键 |
(2)插字符
插字符表示当前文本编辑的位置,就像光标表示当前鼠标的位置一样
创建插字符
BOOL CreateCaret(HWND hwnd,HBITMAP hBitMap,int nWidth,int nHeight);
显示插字符
BOOL ShowCaret(HWND hWnd);
获取插字符的位置
BOOL GetCarerPos(LPPOINT lpPoint);
设置插字符
BOOL SetCaretPos(int X,int Y);
2.鼠标消息
(1)不同样式的光标
hCursor=LoadCursor();SetCursor(hCursor);可以更改光标的样式
IDC_APPSTARTING | 标准箭头和小沙漏 |
IDC_ARROW | 箭头 |
IDC_CROSS | 十字光标 |
IDC_HAND | 手型光标 |
IDC_HELP | 箭头加问号 |
IDC_IBEAM | I型文本光标 |
IDC_NO | 圆圈中带斜线 |
IDC_SIZEALL | 带东南西北箭头的十字光标 |
IDC_SIZENESW | 带有东北方和西南方箭头的光标 |
IDC_SIZENS | 带有北方和南方箭头的光标 |
IDC_SIZENWSE | 带有西北方和东南方箭头的光标 |
IDC_SIZEWE | 带有东方和西方箭头的光标 |
IDC_UPARROW | 垂直箭头 |
IDC_WAIT | 沙漏 |
(2)常用的鼠标消息
定义wincl.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS的窗口可以接收鼠标双击的消息,通过SetDoubleClickTime()可以重新设定表示双击的时间间隔;捕捉所有鼠标消息SetCapture()、释放消息ReleaseCapture();获取鼠标屏幕坐标的函数GetCursorPos(),将屏幕坐标转换成窗口坐标ScreenToClient()
WM_LBUTTONDOWN | 单击鼠标左键 |
WM_LBUTTONUP | 释放鼠标左键 |
WM_LBUTTONDBLCLK | 双击鼠标左键 |
WM_MBUTTONDOWN | 单击鼠标中键 |
WM_MBUTTONUP | 释放鼠标中键 |
WM_MBUTTONDBLCLK | 双击鼠标中键 |
WM_RBUTTONDOWN | 单击鼠标右键 |
WM_RBUTTONUP | 释放鼠标右键 |
WM_RBUTTONDBLCLK | 双击鼠标右键 |
WM_MOUSEMOVE | 鼠标移动 |
WM_MOUSEWHEEL | 鼠标滚轮转动 |
WM_MOUSEACTIVATE | 在非激活窗口单击鼠标按钮 |
WM_MOUSEHOVER | 鼠标在窗口上悬浮 |
(3)鼠标消息中的字参数和长字参数
用LOWORD()获取长字参数的低位得到鼠标的窗口位置x坐标,用HIWORD()获取长字参数的高位得到鼠标啊的窗口位置y坐标;鼠标消息中的字参数是否有效可以通过和下面常量按位与&来判断
字参数 | 表示的意义 |
MK_CONTROL | Ctrl键 |
MK_LBUTTON | 鼠标左键 |
MK_MBUTTON | 鼠标中键 |
MK_RBUTTON | 鼠标右键 |
MK_SHIFT | Shift键 |
MK_XBUTTON1 | Windows第一徽标键 |
MK_XBUTTON2 | Windows第二徽标键 |
六、程序的资源
1.菜单资源
(1)定义菜单
自定义的菜单项名称 MENU[,载入特性选项]
BEGIN
菜单项列表
END
载入特性选项
DISCARDABLE | 当不再需要菜单时可以丢弃 |
FIXED | 将菜单保存在内存中的固定位置 |
LOADONCALL | 需要时加载菜单 |
MOVEABLE | 菜单在内存中可移动 |
PRELOAD | 立即加载菜单 |
由POPUP、MENUITEM定义的菜单项列表
POPUP定义弹出式菜单、弹出式菜单可以包含MENUITEM定义的菜单,如果菜单项名称中有&字母、那么它就获得了热键(alt+字母进行访问)
POPUP “自定义的菜单项名称”[,选项]
BEGIN
菜单项列表
END
选项
MENUBARBREAK | 纵向分割 |
CHECKED | 选中 |
INACTIVE | 禁止第一个菜单项 |
GRAYED | 禁止第一个菜单项并以灰色显示 |
MENUITEM定义的菜单项
自定义的菜单项标识是提前自定义的常量用于区别其他菜单项,WM_COMMAND消息中字参数wParam的低字段包含这些定义过的常量;这些常量一般在.h文件中定义,在需要的地方使用#include引入
MENUITEM “自定义的菜单项名称”,自定义的菜单项标识[,选项]
//创建菜单中的水平分隔符
MENUITEM SEPARATOR
(2)加载菜单资源
窗口类中加载
wincl.lpszMenuName = "OwnMenu";
创建窗口时加载
CreateWindow(,,,,,,,,,LoadMenu(hThisInstance,"OwnMenu"),,);
动态加载
BOOL SetMenu(
HWND hwnd,
HMENU hmenu);
(3)操作菜单项
获取主菜单句柄
hmenu=GetMenu(hwnd);
禁用或激活菜单项,可以在初始化的时候资源描述文件中设置禁用或激活,也可以调用函数
BOOL EnableMenuItem(HMENU hmenu,UINT enableItem,UINT dwEnable);
EnableMenuItem(hmenu,OWN_CLOSE,MF_BYCOMMAND|MF_DISABLED);
dwEnable是操作标识,通过或|可以选择多个操作标识
MF_BYCOMMAND | 以定义的ID值标识菜单项 |
MF_BYPOSITION | 以位置标识菜单项 |
MF_DISABLE | 禁用菜单项 |
MF_ENABLED | 激活菜单项 |
MF_GRAYED | 禁用菜单项并以灰色显示 |
设置或取消选中标志,可以在资源描述文件中使用CHECKED,也可以调用函数
DWORD CheckMenuItem(
HMENU hmenu,
UINT itemID,
//dwCheck的取值是MF_CHECKED或MF_UNCHECKED
UINT dwCheck);
在菜单中插入菜单项
BOOL InsertMenu(
HMENU hmenu,
//菜单项的ID值或者菜单项的下标(下标从0开始)
UINT position,
//MF_BYCOMMAND|MF_ENABLED或MF_BYCOMMAND|MF_DISABLED或MF_POPUP|MF_BYPOSITION
UINT flags;
UINT itemID,
LPCTSTR lpNewItem);
删除菜单项
BOOL DeleteMenu(
HMENU hmenu,
UINT position,
//flags取MF_BYCOMMAND或者MF_POSITION
UINT flags);
修改菜单项
BOOL ModifyMenu(
HMENU hmenu,
UINT position,
//取MF_COMMAND就可以
UINT flags,
UINT newItemID,
LPCTSTR lpNewItem);
动态地创建菜单
HMENU hmenu=CreateMenu();
HMENU hmenu1=CreateMenu();
InsertMenu(hmenu1,(UINT)hmenu1,MF_BYCOMMAND|MF_ENABLED,OWN_NEW,"新建");
InsertMenu(hmenu1,(UINT)hmenu1,MF_BYCOMMAND|MF_ENABLED,OWN_NEW,"修改");
HMENU hmenu2=CreateMenu();
InsertMenu(hmenu2,(UINT)hmenu2,MF_BYCOMMAND|MF_ENABLED,OWN_NEW,"新建");
InsertMenu(hmenu2,(UINT)hmenu2,MF_BYCOMMAND|MF_ENABLED,OWN_NEW,"修改");
AppendMenu(hmenu,MF_POPUP,(UINT)hmenu1,"菜单1");
AppendMenu(hmenu,MF_POPUP,(UINT)hmenu2,"菜单2");
SetMenu(hwnd,hmenu);
重新显示窗口菜单
DrawMenuBar(hwnd);
2.加速键资源
同样是在WM_COMMAND的字参数低字节获取对应的消息
(1)定义加速键资源
加速键表名 ACCELERATORS
BEGIN
加速键资源描述
END
加速键资源描述
//这是Ctrl组合的加速键,NOINVERT表示菜单项不高亮显示,ALT、SHIFT、CONTROL表示组合方式
“^字母”,id值,ASCII,[NOINVERT][ALT][SHIFT][CONTROL]
//这是使用虚拟键的加速键,需要额外使用头文件windows.h
虚拟键,id值,VIRTKEY,[NOINVERT][ALT][SHIFT][CONTROL]
(2)载入加速键资源
HACCEL hacc=LoadAccelerators(
//当前应用的句柄
hInstance,
//加速键表名
lpAcceIName;)
(3)翻译加速键
//一个应用程序只有一个消息循环,非模态对话框的捕获也是要放在这个地方
MSG message;
While(GetMessage(&message,NULL,0,0)
{
If(!TranslateAccelerator(hwnd,hacc,&message))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
}
3.位图资源
(1)定义位图资源
位图的ID值 BITMAP “位图的全称”
(2)初始化
定义一个位图句柄
HBITMAP hBitmap;
加载或创建位图资源
加载位图
hBitmap=LoadBitmap(
//当前应用的句柄,可能需要全局变量来传入
hInstance,
//定义过的位图的ID值
MAKEINTRESOURCE(bitmapID));
创建位图
hBitmap=CreateCompatibleBitmap(
hdc,
//位图的宽度
nWidth,
//位图的高度
nHeight);
选入内存设备环境,位图进入设备环境后就可以编辑位图
case WM_CREATE:
hdc=GetDC(hwnd);
hMemDC=CreateCompatibleDC(hdc);
hBitmap=LoadBitmap(hins,MAKEINTRESOURCE(IDB_BITMAP1));
//选入内存设备环境
SelectObject(hMemDC,hBitmap);
GetObject(hBitmap,sizeof(BITMAP),&bitmap);
ReleaseDC(hwnd,hdc);
break;
(3)输出位图
获取位图的尺寸
//这个宽度是bitmap.bmWidth,高度是bitmap.bmHeight
GetObject(hBitmap,sizeof(BITMAP),&bitmap);
获取窗口的尺寸
//这个宽度是clientRect.right-clientRect.left,高度是clientRect.bottom-clientRect.top
GetClientRect(hwnd,&clientRect);
按原图像尺寸输出
BOOL BitBlt(
//目标设备环境句柄
HDC hdc,
//目标显示位置
int xDest,int yDest,
//显示的宽度和高度
int nWidth,int nHeight,
//之前定义的内存设备环境
HDC hMemDC,
//源位图中要显示的位置
int xSrc,int ySrc,
//操作选择
DWORD dwRop);
操作选择
BLACKNESS | 输出全黑色位图 |
DSTINVERT | 目标位图“取反”输出 |
MERGECOPY | 源位图和模板“与” |
MERGEPAINT | 源位图和模板“或” |
NOTSRCCOPY | 在拷贝前将源位图“取反” |
NOTSRCERASE | 将源位图和目标位图“或”操作后“取反” |
NOMIRRORBITMAP | 禁止对位图的镜像操作 |
PATCOPY | 将模板拷贝到目标位图上 |
PAINTVERT | 将模板和目标位图“异或” |
SRCCOPY | 将源位图拷贝到目标位图(常用) |
SRCAND | 将源位图和目标位图“与” |
SRCPAINT | 将源位图和目标位图“或” |
SRCERASE | 将目标为徒“取反”后与源位图“与” |
SRCINVERT | 将源位图和目标位图“异或” |
WHITENESS | 输出全白色位图 |
可缩放的图像输出
BOOL StretchBlt(
//目标设备环境句柄
HDC hdc,
//目标显示位置
int xDest,int yDest,
//显示的宽度和高度
int nWidthDest,int nHeightDest,
//之前定义的内存设备环境
HDC hMemDC,
//源位图要显示的位置
int xSrc,int ySrc,
//源位图要显示的宽度和高度
int nWidthSrc,int nHeightSrc,
//操作选择
DWORD dwRop);
4.对话框资源
显式的向消息队列发消息SendMessage(hwnd,WM_DESTROY,0,0);;对话框中SetDlgItemText()可以设置控件的显示文字、GetDlgItemText()可以获得控件中的文字;GetParent()可以获得对话框的父窗口
(1)模式对话框
不关闭这个对话框就无法和应用的其他窗口交互
① 定义对话框资源
自定义对话框名称 DIALOGEX [载入特性选项],xDialogEx,yDialogEx,widthDialogEx,heightDialogEx
//定义样式的时候需要用到头文件#include "afxres.h",WS_POPUP|WS_CAPTION|WS_VISIBLE一般会用到
STYLE 对话框常用样式|窗口常用样式
FONT 字体大小,”字体名称”
CAPTION “标题名称”
BEGIN
对话框的常用控件 “自定义的控件名称”,自定义的控件的ID值,x,y,width,height
END
自定义对话框名称在头文件中定义、对于无意义但是非要定义ID的可以使用同一个ID值ID.._STATIC,载入特性选项和菜单资源的相同
对话框常用样式
DS_3DLOOK | 使用三维边框 |
DS_FIXEDSYS | 使用SYSTEM_FIXED字体 |
DS_MODALFRAME | 使用细实线边框 |
DS_SYSMODAL | 系统模式对话框 |
DS_CENTERMOUSE | 鼠标点作为对话框的中心点 |
DS_CENTER | 对话框居中 |
DS_SETFOREGROUND | 使对话框在最前台 |
对话框常用控件
CHECKBO | 复选框 | |
COMBOBOX | 组合框 | |
CTEXT | 文本居中的静态控件 | |
DEFPUSHBUTTON | 默认按钮 | |
EDITTEXT | 编辑框 | 常用属性ES_MULTILINE |ES_AUTOHSCROLL |WS_VSCROLL|ES_READONLY;SendMessage(GetDlgItem(hwnd,IDE_0),EM_REPLACESEL,FALSE,(LPARAM)TEXT (" "));动态的使编辑框换行 |
CROUPBOX | 组合框 | |
ICON | 图标 | |
LISTBOX | 列表框 | |
LTEXT | 左对齐文本 | |
PUSHBUTTON | 按钮 | |
RADIOBUTTON | 单选按钮 | |
RTEXT | 右对齐文本 | |
SCROLLBAR | 滚动条 |
② 调用对话框
INT_PRINT DialogBox(
//当前应用程序的句柄,((LPCREATESTRUCT) lParam)->hInstance这种方法也可以得到
HINSTANCE hInstance,
//使用MAKEINTRESOURCE加载对话框的ID值,或者使用LPCSTR强制转换这个ID
LPCTSTR lpTemplate,
//父窗口句柄
HWND hwndParent,
//对话框的处理函数,可能需要强制转换
DLGPROC lpDialogFunc);
③ 对话框的处理函数
BOOL CALLBACK 对话框处理函数的名称(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
Switch(message)
{
case WM_INITDIALOG:
…
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 自定义的控件的ID值:
…
return TRUE;
…
}
break;
case WM_CLOSE:
EndDialog(hwnd,0);
Return TRUE;
}
//由系统完成
return FALSE;
}
④ 关闭对话框
//nResult可以填触发控件的ID
BOOL EndDialog(HWND hwnd,INT_PTR nResult);
(2)Windows消息框MessageBox
这是系统内置的模态对话框
int MessageBox(
//Windows消息框的父窗口
HWND hwnd,
//显示的内容
LPCTSTR lpszText,
//标题
LPCTSTR lpszCaption,
//Windows消息框的类型
DWORD dwType);
Windows消息框的类型
MB_CANCELTRYCONTINUE | 含有Cancel、Try Again、Contiue按钮的消息框 |
MB_ICONEXXCLAMATION,MB_ICONWARING | 含有感叹号的消息框 |
MB_ICONQUESTION | 含有问号的消息框 |
MB_ICONSTOP,MB_ICONERROR,MB_ICONHAND | 含有停止图标的消息框 |
MB_OK | 含有OK按钮的消息框 |
MB_OKCANCEL | 含有OK和CANCEL按钮的消息框 |
MB_RETRYCANCEL | 含有RETRY和CANCEL按钮的消息框 |
MB_YESNO | 含有YES和NO按钮的消息框 |
MB_YESNOCANCEL | 含有YES、NO、CANCEL按钮的消息框 |
MessageBox的返回值
IDABORT | 按下Abort按钮 |
IDCANCEL | 按下Cancel按钮 |
IDIGNORE | 按下Ignore按钮 |
IDNO | 按下No按钮 |
IDOK | 按下OK按钮 |
IDRETRY | 按下Retry按钮 |
IDYES | 按下Yes按钮 |
(3)非模式对话框
不关闭这个对话框也可以和应用的其他窗口交互,非模态对话框和模态对话框有很多相似的地方,但是也有不同之处:
① 调用非模式对话框
HWND CreateDialog(
//当前应用程序的句柄
HINSTANCE hInstance,
//使用MAKEINTRESOURCE加载定义过的非模式对话框的ID值
LPCTSTR lpTemplate,
//父窗口句柄
HWND hwndParent,
//非模式对话框的处理函数
DLGPROC lpDialogFunc);
② 截获非模式对话框消息的消息循环
MSG message;
while(GetMessage(&message,NULL,0,0))
{
//这个hdlg是个HWND类型的全局变量,由CreateDialog()的返回值进行初始化
if(!IsDialogMessage(hdlg,&message))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
}
③ 关闭非模态对话框
BOOL DestroyWindow(HWND hdlg);
5.图标资源
定义图标资源
定义的图标ID值 ICON “图标全称”
加载图标
wincl.hIcon = LoadIcon (hThisInstance, MAKEINTRESOURCE(IDI_552));
wincl.hIconSm = LoadIcon (hThisInstance, MAKEINTRESOURCE(IDI_552));
七、Windows标准控件
设置控件文件SetWindowText()、设置控件文件GetWindowText()是比较通用的函数;Windows标准控件是指无需定义,用CreateWindow(_T(“”),…)即可调用的控件,其中倒数第三个参数可以是自定义的(HMENU)ID,在WM_COMMAND的子参数低字节可以找到它的信息
1.静态控件
(1)创建方法
CreateWindow(_T(“static”),…);得到静态的文字
2.按钮
(1)创建方法
CreateWindow(_T(“button”),…);
(2)按钮的样式
BS_AUTOCHECKBOX | 和BS_CHECKBOX类似,只是单击按钮会自动反转 |
BS_AUTORADIOBUTTON | 和BS_RADIOBUTTON类似,单击按钮时会自动反转 |
BS_AUTO3STATE | 和BS_3STATE类似,只是单击按钮时会改变状态 |
BS_DEFPUSHBUTTON | 默认按钮,按回车键可以快速选中它 |
BS_GROUPBOX | 指定一个组合框 |
BS_LEFTTEXT | 控件的标题在按钮左边 |
BS_CHECKBOX | 按钮右边带上选择框 |
BS_RADIOBUTTON | 指定一个单选按钮 |
BS_3STATE | 和BS_CHECKBOX类似,只是有三种状态:选中、未选中、灰色 |
BS_PUSHBUTTON | 指定一个命令按钮 |
BS_OWNERDRAW | 指定一个自定义的按钮 |
3.列表框
(1)创建方法
CreateWindow(_T(“listbox”),…);
(2)常用属性
WS_CHILDWINDOW | WS_VISIBLE | LBS_STANDARD
4.滚动条
(1)创建方法
CreateWindow(_T(“scrollbar”,…);
5.编辑框
(1)创建方法
CreateWindow(_T(“edit”,…);
(2)常用属性
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |WS_BORDER | ES_LEFT | ES_MULTILINE |ES_AUTOHSCROLL | ES_AUTOVSCROLL
6.组合框
(1)创建方法
CreateWindow(_T(“combobox”,…);
八、单文档与多文档
1.CC++多线程
对于需要较长执行时间的功能模块,如果只放在主线程不分出线程的话,可能会造成UI无响应的糟糕情况
//用宏定义的变量加上条件语句的判断可以动态控制线程的开启和结束
_beginthread(timer,0,NULL);
VOID timer(PVOID pvoid){…;_endthread();}
九、附录
1.应用程序的发布
当前工程->Properties->Built Targets->Type->GUI application;
选择Release编译
2.参考网址
http://laurencejackson.com/win32/ | win32API下载 |