上一篇《
Windows
界面编程第二篇
半透明窗体
》介绍了先使用
SetWindowLong
为窗体加上
WS_EX_LAYERED
属性,再使用
SetLayeredWindowAttributes
调整窗体的透明度。本篇将使用这二个函数来完成另一个实用的功能——异形窗口(异形窗体)。
异形窗口的原理很简单,首先加载一张位图画刷作窗口背景,然后设置透明色就可以使得窗口由矩形变成任意形状。这样使得窗口的显示更加美观。
下面先简单介绍下Win32 SDK方式创建窗口的流程(按《Windows程序设计》中的大体流程):
1.设置
WNDCLASS
类型的变量,这个变量将描述窗口的风格、窗口消息处理函数、程序图标、光标、窗口背景画刷等待。
2.使用
RegisterClass
将
WNDCLASS
类型的变量注册下。
3.使用
CreateWindow
或
CreateWindowEx
创建窗口,这里可以设置窗口的初始位置、初始大小、扩展属性等等。
4.通过
ShowWindow
和
UpdateWindow
将窗口显示出来。
5.窗口显示完成后,在WinMain()函数中添加消息处理:
MSG
msg
;
while (
GetMessage
(&
msg
,
NULL
,
0, 0))
TranslateMessage
(&
msg
);
DispatchMessage
(&
msg
);
通过这五步就完成了一个窗口的创建了。
对于窗口消息函数,一般只要在
WM_DESTROY
消息中调用下
PostQuitMessage
(0);
其它的消息都可以使用默认消息处理函数
DefWindowProc
。
对于异形窗口,可以在
WM_CREATE
即窗口初始化时设置好透明色就完成了窗口形状的改变,不过为了支持鼠标对窗口的拖曳,还要在
WM_LBUTTONDOWN
消息中加入:
PostMessage
(
hwnd
,
WM_SYSCOMMAND
,
SC_MOVE
|
HTCAPTION
, 0);
这样,异形窗口就可以在屏幕上像普通窗口一样的移动了。
完整的源代码如下所示(下载地址:
http://download.csdn.net/download/morewindows/4966815
):
#include <windows.h>
const
char
szAppName[] =
"异形窗口1 MoreWindows-(http://blog.csdn.net/MoreWindows)"
;
void
GetWindowSize(
HWND
hwnd,
int
*pnWidth,
int
*pnHeight);
BOOL
InitBitmapWindow(
HINSTANCE
hinstance,
HBITMAP
hBitmap,
int
nCmdshow);
LRESULT
CALLBACK BitmapWindowWndPrco(
HWND
hwnd,
UINT
message,
WPARAM
wParam,
LPARAM
lParm);
int
APIENTRY WinMain(
HINSTANCE
hInstance,
HINSTANCE
hPrevInstance,
LPSTR
lpCmdLine,
int
nCmdShow)
//设置窗口背景画刷为图片画刷,再指定透明颜色即可以创建透明区域。
HBITMAP
hBitmap;
hBitmap = (
HBITMAP
)LoadImage(NULL,
"Kitty.bmp"
, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if
(hBitmap == NULL)
{
MessageBox(NULL,
"位图加载失败"
,
"Error"
, MB_ICONERROR);
return
0;
}
if
(!InitBitmapWindow(hInstance, hBitmap, nCmdShow))
return
0;
MSG msg;
while
(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DeleteObject(hBitmap);
return
msg.wParam;
}
BOOL
InitBitmapWindow(
HINSTANCE
hinstance,
HBITMAP
hBitmap,
int
nCmdshow)
{
HWND
hwnd;
WNDCLASS wndclass;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = BitmapWindowWndPrco;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hinstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = CreatePatternBrush(hBitmap);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if
(!RegisterClass(&wndclass))
{
MessageBox(NULL,
"Program Need Windows NT!"
,
"Error"
, MB_ICONERROR);
return
FALSE;
}
BITMAP bm;
GetObject(hBitmap,
sizeof
(bm), &bm);
hwnd = CreateWindowEx(WS_EX_TOPMOST,
szAppName,
szAppName,
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
bm.bmWidth,
bm.bmHeight,
NULL,
NULL,
hinstance,
NULL);
if
(hwnd == NULL)
return
FALSE;
ShowWindow(hwnd, nCmdshow);
UpdateWindow(hwnd);
return
TRUE;
}
LRESULT
CALLBACK BitmapWindowWndPrco(
HWND
hwnd,
UINT
message,
WPARAM
wParam,
LPARAM
lParm)
static
HDC
s_hdcMem;
static
HBRUSH
s_hBackBrush;
switch
(message)
{
case
WM_CREATE:
{
// 设置分层属性
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
COLORREF
clTransparent = RGB(0, 0, 0);
SetLayeredWindowAttributes(hwnd, clTransparent, 0, LWA_COLORKEY);
}
return
0;
case
WM_KEYDOWN:
switch
(wParam)
{
case
VK_ESCAPE:
SendMessage(hwnd, WM_DESTROY, 0, 0);
return
0;
}
break
;
case
WM_LBUTTONDOWN:
PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);
return
0;
case
WM_DESTROY:
PostQuitMessage(0);
return
0;
}
return
DefWindowProc(hwnd, message, wParam, lParm);
}
void
GetWindowSize(
HWND
hwnd,
int
*pnWidth,
int
*pnHeight)
{
RECT rc;
GetWindowRect(hwnd, &rc);
*pnWidth = rc.right - rc.left;
*pnHeight = rc.bottom - rc.top;
}
// 异形窗口1 窗口背景使用位图画刷再指定透明色
//By MoreWindows-(http://blog.csdn.net/MoreWindows)
#include <windows.h>
const char szAppName[] = "异形窗口1 MoreWindows-(http://blog.csdn.net/MoreWindows)";
* 函数名称: GetWindowSize
* 函数功能: 得到窗口的宽高
* hwnd 窗口句柄
* pnWidth 窗口宽
* pnHeight 窗口高
void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight);
* 函数名称: InitBitmapWindow
* 函数功能: 位图窗口初始化
* hinstance 进程实例
* hBitmap 位图句柄
* nCmdshow 显示方式-与ShowWindow函数的第二个参数相同
BOOL InitBitmapWindow(HINSTANCE hinstance, HBITMAP hBitmap, int nCmdshow);
// 位图窗口消息处理函数
LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
//设置窗口背景画刷为图片画刷,再指定透明颜色即可以创建透明区域。
HBITMAP hBitmap;
hBitmap = (HBITMAP)LoadImage(NULL, "Kitty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (hBitmap == NULL)
MessageBox(NULL, "位图加载失败", "Error", MB_ICONERROR);
return 0;
if (!InitBitmapWindow(hInstance, hBitmap, nCmdShow))
return 0;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
DeleteObject(hBitmap);
return msg.wParam;
BOOL InitBitmapWindow(HINSTANCE hinstance, HBITMAP hBitmap, int nCmdshow)
HWND hwnd;
WNDCLASS wndclass;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = BitmapWindowWndPrco;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hinstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = CreatePatternBrush(hBitmap);//位图画刷
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
MessageBox(NULL, "Program Need Windows NT!", "Error", MB_ICONERROR);
return FALSE;
BITMAP bm;
GetObject(hBitmap, sizeof(bm), &bm);
hwnd = CreateWindowEx(WS_EX_TOPMOST,
szAppName,
szAppName,
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
bm.bmWidth,
bm.bmHeight,
NULL,
NULL,
hinstance,
NULL);
if (hwnd == NULL)
return FALSE;
ShowWindow(hwnd, nCmdshow);
UpdateWindow(hwnd);
return TRUE;
LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm)
static HDC s_hdcMem;
static HBRUSH s_hBackBrush;
switch (message)
case WM_CREATE:
// 设置分层属性
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// 设置透明色
COLORREF clTransparent = RGB(0, 0, 0);
SetLayeredWindowAttributes(hwnd, clTransparent, 0, LWA_COLORKEY);
return 0;
case WM_KEYDOWN:
switch (wParam)
case VK_ESCAPE: //按下Esc键时退出
SendMessage(hwnd, WM_DESTROY, 0, 0);
return 0;
break;
case WM_LBUTTONDOWN: //当鼠标左键点击时可以拖曳窗口
PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
return DefWindowProc(hwnd, message, wParam, lParm);
void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight)
RECT rc;
GetWindowRect(hwnd, &rc);
*pnWidth = rc.right - rc.left;
*pnHeight = rc.bottom - rc.top;
运行结果如下:
现在总结下异形窗口的创建,先通过创建位图画刷来做窗口的背景画刷,再通过SetWindowLong为窗体加上WS_EX_LAYERED属性,然后使用SetLayeredWindowAttributes指定窗口的透明色来完成窗口形状的调整。为了支持鼠标的拖曳,在WM_LBUTTONDOWN消息中作了特殊处理,使得异形窗口可以像普通窗口一样在屏幕上移动。
本篇程序中的异形窗口的大小是无法设置的,只能和位图一样。下一篇《Windows界面编程第四篇 异形窗体 高富帅版》将介绍窗口大小可以指定的异形窗口。欢迎继续浏览。