<Win32_9>SetWindowRgn函数的应用——绘制个性化形状的窗口
2013-08-10 11:55
399 查看
本文由BlueCoder编写 转载请说明出处:http://blog.csdn.net/crocodile__/article/details/9873037
我的邮箱:bluecoder@yeah.net 欢迎大家和我交流编程心得我的微博:BlueCoder_黎小华 欢迎光临^_^
SetWindowRgn这个函数比较好玩,它可以通过设定的区域(RGN)来制定该形状的窗口
先来看看函数原型:int SetWindowRgn(
HWND hWnd, // handle to window
HRGN hRgn, // handle to region
BOOL bRedraw // window redraw option
);由此可以看出我们需要先建立一个区域RGN,以此来设定窗口形状
这个不难,可以调用CreateEllipticRgn、CreatePolygonRgn等相关创建RGN的函数
关键是第三个参数bRedraw,它有点儿学问,我们先暂时放一下,待会儿细究……
今天写的程序,实现的功能为:
通过鼠标点击的次数来变换窗口的形状(为了简便起见,我只用了两种:椭圆形和五角形),同时变换窗口背景的颜色(待会儿你会看到奇怪的现象)
具体实现细节如下:
(1)首先建立两个自定义消息//自定义消息
#define WM_ELLIPSEWND (WM_USER + 100)//椭圆窗口消息
#define WM_PENTAGONWND (WM_USER + 101)//五角形窗口消息
(2)在窗口过程设定以下静态变量:static int iClick;//标记鼠标点击的次数
static HRGN hRgnWnd;//窗口区域
static POINT pt[5];//五角形的五个点
static HBRUSH hBr;//背景刷
(3)在WM_SIZE消息中初始化五角形的五个点case WM_SIZE:
{
//获取客户区大小
int cxClient, cyClient;
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
//初始化五角形的五个点
pt[0].x = cxClient / 2;
pt[0].y = 0;
pt[1].x = 50;
pt[1].y = cyClient / 2;
pt[2].x = cxClient / 3;
pt[2].y = cyClient;
pt[3].x = cxClient * 2 / 3;
pt[3].y = cxClient;
pt[4].x = cxClient - 50;
pt[4].y = cyClient / 2;
}
return 0;
(4)通过鼠标消息来控制窗口的形状和颜色case WM_LBUTTONDOWN:
{
UINT msg;
COLORREF brColor;
iClick++;
//根据鼠标点击的次数来确定发送消息种类以及背景刷颜色
msg = iClick % 2 ? WM_ELLIPSEWND : WM_PENTAGONWND;
brColor = iClick % 2 ? RGB(36, 204, 40): RGB(254, 243, 39);//前者是绿色,后者是黄色
//创建背景刷
hBr = CreateSolidBrush(brColor);
//发送消息
SendMessage(hwnd, msg, wParam, lParam);
}
return 0;不难推理出,当窗口形状为椭圆的时候应该为绿色,当窗口形状为五角形时就为黄色
(5)在自定义消息中绘制相应窗口形状//绘制椭圆窗口
case WM_ELLIPSEWND:
hRgnWnd = CreateEllipticRgn(100, 100, 400, 400);
SetWindowRgn(hwnd, hRgnWnd, TRUE); //绘制五角形窗口
case WM_PENTAGONWND:
hRgnWnd = CreatePolygonRgn(pt, 5, WINDING);
SetWindowRgn(hwnd, hRgnWnd, TRUE);
//重绘窗口背景
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
{
RECT rect;
GetClientRect(hwnd, &rect);
FillRect(hdc, &rect, hBr);
}
EndPaint(hwnd, &ps);
接下来,我们就来看看奇怪现象的产生(为了效果的显著,我一开始设定背景颜色为黑色):
(1)首先建立一个黑色背景的窗口
(2)点击一次鼠标后(你会发现,椭圆窗口颜色不是我们想要的绿色,而是原先的黑色)
(3)再点击一次鼠标(你会发现五角形窗口的颜色也有问题,虽然有黄色的部分,但左边一部分区域确是黑色)
(4)最后再来点击一次鼠标(这个和五角形的现象类似,你仔细瞧瞧,椭圆黑色的区域和五角形的黑色区域是同一个区域)
看到这儿,你一定会疑问了:是哪儿的代码出问题了吗?
其实不是代码的问题,主要是SetWindowRgn函数的特点决定的
还记得一开始说的这个函数最后一个参数吗——BOOL bRedraw
当为TRUE时,重绘窗口;否则,不重绘
而我们这里设定的是TRUE:SetWindowRgn(hwnd, hRgnWnd, TRUE);
你可能还是会有疑问:对啊,重绘了的啊,怎么还是会出现这个问题呢?
经过本人仔细的思考和测试,我得出以下结论(虽然不能保证100%的正确,但至少能解释他的原因):
这里设定了第三个参数为TRUE,当调用该函数的时候,windows的确会重绘当前区域,但是:
它会依然保存当前区域和上一次区域的交集,仅仅重绘当前区域中除开这个交集的部分
我只解释第一个,之后的三个是相同的,大家通过我讲的第一个就能明白了:
首先建立窗口时,这个区域是该窗口的大小
当点击第一次鼠标时,当前区域是这个椭圆,由于这个椭圆在原始窗口内部,因此这个椭圆区域与初始窗口的交集就是这个椭圆区域,那么,按照我总结的结论,这个椭圆区域不会被重绘,依然是黑色
……
到此,你是不是应该明白了
当然,明白之后,你还会想知道解决方法,这个其实很简单,因为windows在调用SetWindowRgn函数时,并不是重绘完整的当前区域,那么我们寻找一种方式来迫使windows完全重绘该区域,一种很简单的方式就是设定无效区域为整个原始窗口://这里必须调用InvalidateRect和InvalidateRgn效果是一样的,只不过第二个参数要为NULL,因为我们希望整个窗口都会重绘
InvalidateRgn(hwnd, NULL, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
……
我们还是来看看修改后的效果嘛:
呵呵,终于讲完了,希望鄙人的心得能给大家带来学习的方便^_^
点击下载完整代码和程序
我的邮箱:bluecoder@yeah.net 欢迎大家和我交流编程心得我的微博:BlueCoder_黎小华 欢迎光临^_^
SetWindowRgn这个函数比较好玩,它可以通过设定的区域(RGN)来制定该形状的窗口
先来看看函数原型:int SetWindowRgn(
HWND hWnd, // handle to window
HRGN hRgn, // handle to region
BOOL bRedraw // window redraw option
);由此可以看出我们需要先建立一个区域RGN,以此来设定窗口形状
这个不难,可以调用CreateEllipticRgn、CreatePolygonRgn等相关创建RGN的函数
关键是第三个参数bRedraw,它有点儿学问,我们先暂时放一下,待会儿细究……
今天写的程序,实现的功能为:
通过鼠标点击的次数来变换窗口的形状(为了简便起见,我只用了两种:椭圆形和五角形),同时变换窗口背景的颜色(待会儿你会看到奇怪的现象)
具体实现细节如下:
(1)首先建立两个自定义消息//自定义消息
#define WM_ELLIPSEWND (WM_USER + 100)//椭圆窗口消息
#define WM_PENTAGONWND (WM_USER + 101)//五角形窗口消息
(2)在窗口过程设定以下静态变量:static int iClick;//标记鼠标点击的次数
static HRGN hRgnWnd;//窗口区域
static POINT pt[5];//五角形的五个点
static HBRUSH hBr;//背景刷
(3)在WM_SIZE消息中初始化五角形的五个点case WM_SIZE:
{
//获取客户区大小
int cxClient, cyClient;
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
//初始化五角形的五个点
pt[0].x = cxClient / 2;
pt[0].y = 0;
pt[1].x = 50;
pt[1].y = cyClient / 2;
pt[2].x = cxClient / 3;
pt[2].y = cyClient;
pt[3].x = cxClient * 2 / 3;
pt[3].y = cxClient;
pt[4].x = cxClient - 50;
pt[4].y = cyClient / 2;
}
return 0;
(4)通过鼠标消息来控制窗口的形状和颜色case WM_LBUTTONDOWN:
{
UINT msg;
COLORREF brColor;
iClick++;
//根据鼠标点击的次数来确定发送消息种类以及背景刷颜色
msg = iClick % 2 ? WM_ELLIPSEWND : WM_PENTAGONWND;
brColor = iClick % 2 ? RGB(36, 204, 40): RGB(254, 243, 39);//前者是绿色,后者是黄色
//创建背景刷
hBr = CreateSolidBrush(brColor);
//发送消息
SendMessage(hwnd, msg, wParam, lParam);
}
return 0;不难推理出,当窗口形状为椭圆的时候应该为绿色,当窗口形状为五角形时就为黄色
(5)在自定义消息中绘制相应窗口形状//绘制椭圆窗口
case WM_ELLIPSEWND:
hRgnWnd = CreateEllipticRgn(100, 100, 400, 400);
SetWindowRgn(hwnd, hRgnWnd, TRUE); //绘制五角形窗口
case WM_PENTAGONWND:
hRgnWnd = CreatePolygonRgn(pt, 5, WINDING);
SetWindowRgn(hwnd, hRgnWnd, TRUE);
//重绘窗口背景
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
{
RECT rect;
GetClientRect(hwnd, &rect);
FillRect(hdc, &rect, hBr);
}
EndPaint(hwnd, &ps);
接下来,我们就来看看奇怪现象的产生(为了效果的显著,我一开始设定背景颜色为黑色):
(1)首先建立一个黑色背景的窗口
(2)点击一次鼠标后(你会发现,椭圆窗口颜色不是我们想要的绿色,而是原先的黑色)
(3)再点击一次鼠标(你会发现五角形窗口的颜色也有问题,虽然有黄色的部分,但左边一部分区域确是黑色)
(4)最后再来点击一次鼠标(这个和五角形的现象类似,你仔细瞧瞧,椭圆黑色的区域和五角形的黑色区域是同一个区域)
看到这儿,你一定会疑问了:是哪儿的代码出问题了吗?
其实不是代码的问题,主要是SetWindowRgn函数的特点决定的
还记得一开始说的这个函数最后一个参数吗——BOOL bRedraw
当为TRUE时,重绘窗口;否则,不重绘
而我们这里设定的是TRUE:SetWindowRgn(hwnd, hRgnWnd, TRUE);
你可能还是会有疑问:对啊,重绘了的啊,怎么还是会出现这个问题呢?
经过本人仔细的思考和测试,我得出以下结论(虽然不能保证100%的正确,但至少能解释他的原因):
这里设定了第三个参数为TRUE,当调用该函数的时候,windows的确会重绘当前区域,但是:
它会依然保存当前区域和上一次区域的交集,仅仅重绘当前区域中除开这个交集的部分
我只解释第一个,之后的三个是相同的,大家通过我讲的第一个就能明白了:
首先建立窗口时,这个区域是该窗口的大小
当点击第一次鼠标时,当前区域是这个椭圆,由于这个椭圆在原始窗口内部,因此这个椭圆区域与初始窗口的交集就是这个椭圆区域,那么,按照我总结的结论,这个椭圆区域不会被重绘,依然是黑色
……
到此,你是不是应该明白了
当然,明白之后,你还会想知道解决方法,这个其实很简单,因为windows在调用SetWindowRgn函数时,并不是重绘完整的当前区域,那么我们寻找一种方式来迫使windows完全重绘该区域,一种很简单的方式就是设定无效区域为整个原始窗口://这里必须调用InvalidateRect和InvalidateRgn效果是一样的,只不过第二个参数要为NULL,因为我们希望整个窗口都会重绘
InvalidateRgn(hwnd, NULL, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
……
我们还是来看看修改后的效果嘛:
呵呵,终于讲完了,希望鄙人的心得能给大家带来学习的方便^_^
点击下载完整代码和程序
相关文章推荐
- <Win32_10>子窗口的应用——翻转窗口
- <Win32_3>Bitmap位图应用2 ------ 键盘控制人物走动
- <Win32_2>Bitmap位图应用1 ------ Win32的数字时钟
- <Win32_3>Bitmap位图应用2 ------ 键盘控制人物走动
- <转载>Win32控制台工程中创建窗口
- <Android 应用之路> 聚闻 ~ 一个聚合数据新闻客户端
- win32应用禁止改变窗口大小方法
- <转载>C#中父窗口和子窗口之间实现控件互操作
- ibatis学习之道:ibatis的<[CDATA]>dynamic属性跟#$的应用
- <Win32_12>位图的透明效果——AlphaBlend函数的用法
- 闲聊桌面应用开发[Win16->Win32->ATL/WTL/MFC->WinForm->WPF/Silverlight/WinRT]
- <转>用户画像构建策略及应用实践
- WPF与Win32完成窗口及各个子控件的绘制的对比
- <<大数据分析在流量调度的应用>>孙子荀
- <IOS>IOS应用内支付IAP从零开始详解,让你少踩坑!
- <9> 函 数
- <识数寻踪:WinHex应用与数据恢复开发秘籍>推荐序一
- <转>安卓应用测试checklist
- win32应用禁止改变窗口大小方法
- <JAVA学习笔记9>——网络之Socket的简单介绍