Windows程序设计3(资源、绘图、坐标系)
一、RC资源的使用
- 资源相关
资源脚本文件:*.rc文件
编译器:RC.EXE
- 菜单资源的使用
1 添加菜单资源:通过菜单栏中插入(rc)菜单资源。或直接添加资源脚本到工程中。
2 加载菜单资源
2.1 在注册时设置菜单资源
2.2 加载菜单资源,设置到窗口
HMENU LoadMenu(
HINSTANCE hInstance, //应用程序句柄
LPCTSTR lpMenuName //菜单字符串资源(或菜单资源ID)
);
MAKEINTRESOURCE宏,可以使得数字形式的资源ID,转化为字符串形式的资源ID。
宏原型:
LPTSTR MAKEINTRESOURCE(
WORD wInteger // 转化的整数
);
使用地方:
1. CreateWindow/Ex 创建窗口时。
如:wndclass.lpszMenuName =MAKEINTRESOURCE(IDR_MENU1);
2. 在WM_CREATE时,通过SetMenu():
函数原型:BOOL SetMenu(
HWND hWnd, // 窗口句柄
HMENU hMenu // 菜单句柄,可以通过LoadMenu()获得。
);
如:
HMENU hMenu=LoadMenu(g_hInstance,MAKEINTRESOURCE(IDR_MENU1));
SetMenu( hWnd , hMenu );
获取子菜单: GetSubMenu() ;
HMENU GetSubMenu(
HMENU hMenu, // 窗口句柄
int nPos // 菜单位置,索引
);
二、ICO图标资源
一个图标文件是由多个不同大小的图像组成的复合文件。(注意图标的大小)。
1 添加资源:通过新建资源文件,并在菜单栏中插入(icon)图标资源。
2 加载
HICON LoadIcon(
HINSTANCE hInstance, // 应用程序句柄
LPCTSTR lpIconName // 字符串或资源ID号
); 成功,返回HICON句柄,若hInstance为NULL,则加载需为标准的系统自带图标。
如:wndclass.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(IDI_WINICON));
wndclass.hIconSm=NULL;//注意此处小图标若为NULL,这样是自动加载小图标的,否则大小图标都变成了大图标了。
3 设置
3.1 注册窗口类时设置。
3.2 WM_SETICON消息中设置。
SendMessage(hWnd,WM_SETICON,wParam,lParam);
如:
//大图标
SendMessage(hWnd,WM_SETICON,ICON_BIG,(LPARAM)hIcon);
//小图标
SendMessage(hWnd,WM_SETICON,ICON_SMALL,(LPARAM)hIcon);
参数:
wParam -图标的类型,ICON_BIG/ICON_SMALL
lParam -图标句柄
4 绘制图标 :DrawIcon
BOOL DrawIcon(
HDC hDC, //设备上下文句柄
int X, // 左上角坐标x
int Y, // 左上角坐标y
HICON hIcon // 将绘制的图标句柄,可通过LoadIcon or LoadImage 获取。
);//成功返回TRUE,失败返回FALSE
BOOL DrawIconEx(
HDC hdc, // 设备上下文句柄
int xLeft, //左上角坐标x
int yTop, //左上角坐标y
HICON hIcon, // 图标句柄
int cxWidth, // 图标宽度
int cyWidth, // 图标高度
UINT istepIfAniCur, // 动画图标的帧数,不支持,置0.
HBRUSH hbrFlickerFreeDraw, // 系统绘制,置NULL.
UINT diFlags // 绘制标识
);
diFlags:DI_NORMAL 正常绘制(DI_IMAGE and DI_MASK的组合或运算)。
DI_IMAGE 图像部分
DI_MASK 掩码部分
三、CURSOR光标资源
1 添加光标的资源
同添加图标资源,光标的大小默认是32X32像素,每个光标有HotSpot,是当前鼠标的热点
2 使用资源
HCURSOR LoadCursor(
HINSTANCE hInstance, // 应用程序实例句柄
LPCTSTR lpCursorName //光标资源ID
); //成功,返回光标句柄,失败返回NULL。
hInstance - 可以为NULL,获取系统默认的Cursor
2.1 在注册窗口时,设置光标:(根据此窗口类创建的所有窗口都是使用此光标)
如:
wndclass.hCursor=LoadCursor(hInstance,MAKEINTRESOURCE(IDC_CIRCLE));
2.2 使用SetCursor设置光标,
HCURSOR SetCursor(
HCURSOR hCursor // handle to cursor
);
3 WM_SETCURSOR 动态设置光标通过SetCursor():(有鼠标动作且鼠标未捕获时受到此消息)
消息参数
WPARAM - 当前使用的光标句柄
LPARAM - LOWORD 当前区域的代码(Hit-Test code )
HIWORD - 当前鼠标消息ID
HCURSOR SetCursor(
HCURSOR hCursor ///光标句柄
);//返回原光标句柄。
4 从(**.cur)文件加载光标
HCURSOR LoadCursorFromFile(
LPCTSTR lpFileName; //文件指针或系统光标ID
);
如:hcurs=LoadCursorFromFile("G:/5000个ICO图标文件/生活用品/sword.ani");或hcurs=LoadCursorFromFile("G:\\5000个ICO图标文件\\生活用品\\sword.ani");
四、字符串资源
1.添加字符串表资源,在表中添加字符串
2.加载字符串资源
int LoadString(
HINSTANCE hInstance, // 应用程序实例句柄
UINT uID, //字符串ID
LPTSTR lpBuffer, //存放字符串缓冲区(BUFF)
Int nBufferMax // 字符串缓冲区(BUFF)长度(以字符为单位,含空字符)
); 成功返回字符串长度,失败返回0.
五、字符串资源
1 添加 添加加速键表,增加命令ID对应的加速键。
2 使用
2.1 加载加速键
HACCEL LoadAccelerators(
HINSTANCE hInstance, // 模块、实例句柄
LPCTSTR lpTableName // 加速键表名
); 成功,则返回加速键句柄,失败则返回NULL
2.2 处理(翻译)加速键消息
int TranslateAccelerator(
HWND hWnd, //处理消息的窗口句柄
HACCEL hAccTable, //加速键句柄
LPMSG lpMsg //消息
); 如果是加速键,返回非零。
2.3 在WM_COMMAND中响应消息,消息参数
WPARAM - HIWORD 为1表示加速键,为0表示菜单
LWORD 为命令ID
处理加速键消息过程:
TranslateAccelerator(HWND hWnd,HACCEL hAccTable ,LPMSG lpMsg)
{
if(lpMsg->message==WM_KEYDOWN||lpMsg->message==WM_SYSKEYDOWN)
{
从lpMsg提取按键消息;
if(hAccTable加速键表中存在与所按键相对应的命令ID)
{
PostMessage(hWnd,WM_COMMAND,MAKELONG(命令ID,1),NULL);
return 1;
}
}
}
用在:
MSG msg={0};
while(GetMessage(&msg,NULL,0,0))
{
if(!TranslateAccelerator(msg.hwnd, AccTable ,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/////最好让加速键的ID和相应菜单ID对应。另外快捷键也可以不与菜单对应,一样的做其他功能。
六、版本资源
通过添加VERSION资源。修改其中内容。
七、Windows 绘图
1. 设备上下文(Device Context,DC)
HDC - DC句柄,表示绘图设备,对绘图设备的抽象。
GDI - Windows graphics device interface Win32提供的绘图API.。
Case WM_PAINT:
……….
HDC hdc=BeginPaint(hWnd, &ps);//与窗口相关联
Case WM_PRINT:
…………
HDC hdc=BeginPaint(hPrinter, &ps);//与打印机相关联的,
2. 图形设备接口(Graphics Device Interface,GDI)
Win32的绘图API,封装在gdi32.dll中,通过该接口给设备上下文下达绘制命令。它是一个在Windows应用程序中执行与设备无关的函数库,这些函数在不同的输出设备上产生图形以及文字输出。
3. 颜色空间的使用
1.RGB :电脑显示器,每一个点颜色是3个字节24位保存 0-2^24
R - 0~255
G - 0~255
B - 0~255
2.CMYK 浅青(白--红),洋红(白—绿),黄(白—蓝),黑。(作减法)打印机上。
颜色深度:位/像素
1位/像素 2种颜色(黑,白)
4位/像素 16种颜色
8位/像素 256种颜色,调色板
16位/像素 R5G5B6,增强色,( R5G5B6表示红色5位绿色5位,蓝6位)
24位/像素 R8G8B8,真彩色
32位/像素 A8R8G8B8,增加透明度(A8)
颜色处理和使用
COLORREF - 实际为DWORD类型,OxAABBGGRR.
例如:
Ox00000000 黑色
Ox000000FF 纯红
Ox0000FF00 纯绿
Ox00FF0000 纯蓝
Ox00FFFF00 浅青
使用16进制挺麻烦,常使用颜色宏
颜色的组合宏:
RGB(r,g,b); // R/G/B 0~255
COLORREF nColor = 0;
赋值使用RGB宏,例如:
nColor = RGB( 255, 0, 0 );
获取RGB分解值,
GetRValue/GetGValue/GetBValue
例如:
BYTE nRed = GetRValue( nColor );
BYTE ----无符号8位整型
4. 点的使用
GetPixel 获取指定坐标像素点的颜色
COLORREF GetPixel(
HDC hdc, // handle to DC
int nXPos, // x-coordinate of pixel
int nYPos // y-coordinate of pixel
);
SetPixel 设置指定坐标像素点的颜色
COLORREF SetPixel(
HDC hdc,//DC句柄
int X,//X坐标
int Y,//Y坐标
COLORREF crColor //设置的颜色
); 返回点原来的颜色
5. 直线的使用(直线、圆形、弧线)
当前点:上一次绘图时的最后一点,初始为(0,0)点。
1.从当前点移动到目标点,并使目标点成为新的当前点。
(MoveTo扩展为MoveToEx(),)
BOOL MoveToEx(
HDC hdc, //设备上下文
Int x, //新的坐标位置
Int y,
LPPOINT lpPoint //当前位置
);
2.从当前点到指定点绘制一条直线.
BOOL LineTo(
HDC hdc, //设备上下文
int nXEnd, // 终点坐标位置
int nYEnd //
);
3.绘制(椭)圆弧
(绘制圆弧,只要控制好外切矩形使得为正方形即可,与画圆同样方式)
BOOL Arc(
HDC hdc, // 设备上下文
int nLeftRect, // 外切矩形左上角
int nTopRect, //
int nRightRect, //外切矩形右下角
int nBottomRect, //
int nXStartArc, //起点坐标
int nYStartArc, //
int nXEndArc, // 终点坐标
int nYEndArc //
);
设置截弧方向:
Int SetArcDirection(
HDC hdc, //设备上下文
int ArcDirection // 指定截弧方向
);//成功返回原截弧方向,失败返回0。
/// ArcDirection截弧方向:(默认为逆时针)
AD_COUNTERCLOCKWISE(逆时针),AD_CLOCKWISE(顺时针)
4.绘制封闭图形
1.封闭图形:可被画刷填充的图形,由直线弧线围起的不是封闭图形。
2.矩形:
BOOL Rectangle(
HDC hdc, // 设备上下文
int nLeftRect, // 矩形左上角
int nTopRect, //
int nRightRect, // 矩形右下角
int nBottomRect //
);
3.椭圆
BOOL Ellipse(
HDC hdc, // 设备上下文
int nLeftRect, //外切矩形左上角
int nTopRect, //
int nRightRect, //外切矩形右下角
int nBottomRect //
);
4.圆角矩形
BOOL RoundRect(
HDC hdc, //设备上下文
int nLeftRect, // 左上角坐标
int nTopRect, //
int nRightRect, // 右下角坐标
int nBottomRect, //
int nWidth, // 圆角椭圆的两个轴(分布于四个角上)
int nHeight //
);
6.画笔的作用
线的颜色、线型、线粗。
HPEN - 画笔句柄
1 创建画笔
HPEN CreatePen(
Int fnPenStyle, //画笔的样式
int nWidth, //画笔的粗细
COLORREF crColor //画笔的颜色
);创建成功返回句柄,失败返回NULL
fnPenStyle样式,:
PS_SOILD - 实心线,可以支持多个像素宽,其他线型只能是一个像素宽。
PS_DASH 虚线
PS_DOT 点线
PS_DASHDOT- --点划线
PS_DASHDOTDOT----双点划线
PS_NULL 不可见的线
nWidth 线宽进对PS_SOLID实线起作用。若nWidth>1,则无论fnPenStyle,去何值画出来的都是实线的了。
2 将画笔应用到设备上下文中,同时得到设备上下文中原画笔
HGDIOBJ SelectObject(
HDC hdc,//绘图设备句柄
HGDIOBJ hgdiobj //GDI绘图对象句柄,画笔句柄
);返回原来的GDI绘图对象句柄
//注意保存原来DC当中画笔。用以恢复原画笔。
3 绘图
4 恢复原画笔(取出DC中的画笔)
将原来的画笔,使用SelectObject函数,放入到设备DC中,就会将我们创建的画笔取出。SelectObject(hDc, hpenOld);//恢复原画笔
5 释放(删除)画笔
BOOL DeleteObject(
HGDIOBJ hObject //GDI绘图对象句柄,画笔句柄
);//成功返回TRUE,失败返回FALSE。
过程:建立->载入->画图->取出->删除
即: HGDIOBJ hpenOld=SelectObject(hDc, CreatePen(….));
……
DeleteObject( SelectObject( hDc, hpenOld);
//注意:永远不要删除设备上下文正在持有的GDI对象。
//只能删除不被DC使用的画笔,所以在释放前,必须将画笔从DC中取出。
7 画刷的使用
画刷 - 封闭图形的填充的颜色、图案
HBRUSH - 画刷句柄
画刷的使用
1 创建画刷
CreateSolidBrush - 创建实心画刷
HBRUSH CreateSolidBrush(
COLORREF crColor //画刷颜色值
);//成功返回画刷句柄,失败返回NULL
CreateHatchBrush - 创建填充画刷
HBRUSH CreateHatchBrush(
int fnStyle, // 阴影线风格
COLORREF clrref // 阴影线颜色
);//成功返回填充画刷,失败返回NULL
fnStyle风格:
HS_BDIAGONAL |
45-degree downward left-to-right hatch |
HS_CROSS |
Horizontal and vertical crosshatch |
HS_DIAGCROSS |
45-degree crosshatch |
HS_FDIAGONAL |
45-degree upward left-to-right hatch |
HS_HORIZONTAL |
Horizontal hatch |
HS_VERTICAL |
Vertical hatch |
2 将画刷应用到DC中
SelectObject
3 绘图
4 将画刷从DC中取出
SelectObject
5 删除画刷
DeleteObject
纹理画刷:
创建:
HBRUSH CreatePatternBrush(
HBITMAP hbmp //位图句柄
);//成返回画刷句柄,失败返回NULL
其他:
可以使用 GetStockObject 函数获取系统维护的画刷、画笔等。
如果不使用画刷填充,需要使用NULL_BRUSH参数,获取不填充的画刷。
GetStockObject返回的画刷不需要DeleteObject。
9.位图的使用
计算机图像分为:
光栅图形 - 记录图像中每一像素点的颜色和透明度等信息。
矢量图形 - 记录图像渲染算法、绘图指令,几何坐标等。
Windows中的位图是一种光栅图像。
HBITMAP - 位图句柄
位图使用:
1) 在资源中添加位图
2) 从资源中加载位图
HBITMAP LoadBitmap(
HINSTANCE hInstance, //应用程序句柄
LPCTSTR lpBitmapName //位图资源名
);//成功返回位图句柄,失败返回NULL
3) 创建与窗口设备上下文匹配的内存设备上下文
HDC CreateCompatibleDC(
HDC hdc // 匹配的源设备上下文句柄
);//成功返回内存设备上下文句柄,失败返回NULL
4) 将位图选入内存设备上下文
HGDIOBJ hbmpOld=SelectObject(hdcMem, hbmpNew);
5) 将内存设备上下文中的位图成像到目标设备上下文中
BOOL BitBlt(
HDC hdcDest, // 目标设备上下文句柄
int nXDest, //目标图像左上角坐标
int nYDest, //
int nWidth, //目标图像的宽度和高度
int nHeight, //
HDC hdcSrc, // 源设备上下文句柄
int nXSrc, // 源图像左上角坐标
int nYSrc, //
DWORD dwRop //光栅操作码(ROP),源像素与目标像素的位运算
);
缩放成像:
BOOL StretchBlt (
HDC hdcDest, // 目标设备上下文句柄
int nXDest, //目标图像左上角坐标
int nYDest, //
int nWidth, //目标图像的宽度和高度
int nHeight, //
HDC hdcSrc, // 源设备上下文句柄
int nXSrc, // 源图像左上角坐标
int nYSrc, //
DWORD dwRop //光栅操作码(ROP),源像素与目标像素的位运算
);
6) 恢复内存设备上下文的原位图
SelectObject(hdcMem, hbmpOld);
7) 删除新位图
DeleteDC(hbmpNew);
8) 释放内存设备上下文
DeleteDC(hdcMem);
//获取位图的信息:
GetObject(…,…);//可获取位图相关信息
八、坐标系
1. 坐标系分类:
设备坐标系
以像素为单位,即一个单位就是一个像素,以设备左上角为原点,X轴向右为正,Y轴向下为正的坐标系。(像素大小与成像设备有关,成像设备分辨率越高,像素点越多)
1 屏幕坐标系 - 以当前屏幕左上角为原点坐标系。
2 窗口坐标系 - 以窗口左上角为原点坐标系。
3 客户区坐标系 - 以窗口的客户区左上角为原点的坐标系。
逻辑坐标系
在GDI绘图中,都是使用逻辑坐标绘图,坐标单位、坐标原点、坐标轴的方向都可以设置。
默认情况下,逻辑坐标系与设备坐标系重合。1逻辑=1设备,显示器:1设备=1像素,打印机:1设备=1/1440英寸(0.018毫米)
2. 坐标系映射:
1)映射模式
A.确定了逻辑坐标系与设备坐标系之间的映射关系。
B.设备做你奥西的单位不能通过代码修改但是逻辑坐标系可修改。
Int SetMapMode(
HDC hdc, ///DC句柄
Int fnMapMode///映射模式
);//返回原先的映射模式
fnMapMode 映射模式如下:
MM_TEXT-默认(正文)模式,1逻辑单位对应1设备单位(显示器为像素),X右为正,Y下为正。
MM_LOENGLISH-低英制模式,1逻辑单位 = 0.01英寸,X右为正,Y上为正。
MM_HIENGLISH-高英制单位,1逻辑单位=0.001英寸,X右为正,Y上为正。
MM_LOMETRIC-低公制单位,1逻辑单位=0.1毫米,X右为正,Y上为正。
MM_HIMETRIC-高公制模式,1个逻辑单位=0.01毫米,X右为正,Y上为正。
MM_TWIPS-打印机模式,1个逻辑单位=1/1440英寸,打印机使用单位。
MM_ISOTROPIC-各向同性模式,1逻辑单位=自定义,X和Y正方向、原点可自定义,逻辑单位与设备单位的比例在水平和垂直方向上取一致。
MM_ANISOTROPIC-各向异性模式,1逻辑单位=自定义,X和Y正方向,原点可自定义,逻辑单位与设备单位的比例在水平和垂直方向上可不一致。
X的1个逻辑单位 = 自定义1
Y的1个逻辑单位 = 自定义2
2)设置逻辑单位与设备单位的比例(MM_ISOTROPIC/MM_ANISOTROPIC)
设置逻辑:
BOOL SetViewportExtEx(
HDC hdc,//设备上下文句柄
int nXExtent,///设备单位X尺度
int nYExtent,////设备单位Y尺度
LPSIZE lpSize///设备单位元尺度旧比例,可为NULL
);//成功返回TRUE,失败返回FALSE。
设置设备:
BOOL SetWindowExtEx(
HDC hdc,//设备上下文句柄
int nXExtent,///逻辑单位X尺度
int nYExtent,////逻辑单位Y尺度
LPSIZE lpSize///逻辑单位元尺度旧比例,可为NULL
);//成功返回TRUE,失败返回FALSE。
SetViewportExtEx(hdc,1,1,NULL);
SetWindowExtEx(hdc,2,3,NULL);
即:X方向:1逻辑=2设备
Y方向:1逻辑=3设备
也等价于(只要成比例):
SetViewportExtEx(hdc,1000,1000,NULL);
SetWindowExtEx(hdc,2000,3000,NULL);
另外:若设置有负值,意味自身轴方向改变了,但还是成比例。
SetViewportExtEx(hdc,-1,1,NULL);
SetWindowExtEx(hdc,2,-3,NULL);
设置逻辑坐标原点位置:
SetViewportOrgEx(hdc,0,32,NULL);//逻辑原点位置(0,32)。
设置窗口(设备)坐标显示原点位置:
SetWindowOrgEx(hdc,0,32,NULL);//设备原点位置(0,32)(仍是左上角位置)。