您的位置:首页 > 编程语言

Windows界面编程第三篇 异形窗体 普通版

2013-03-15 20:09 387 查看
 上一篇《Windows界面编程第二篇
半透明窗体》介绍了先使用SetWindowLong为窗体加上WS_EX_LAYERED属性,再使用SetLayeredWindowAttributes调整窗体的透明度。本篇将使用这二个函数来完成另一个实用的功能——异形窗口(异形窗体)。
异形窗口的原理很简单,首先加载一张位图画刷作窗口背景,然后设置透明色就可以使得窗口由矩形变成任意形状。这样使得窗口的显示更加美观。

    下面先简单介绍下Win32 SDK方式创建窗口的流程(按《Windows程序设计》中的大体流程):

1.设置WNDCLASS类型的变量,这个变量将描述窗口的风格、窗口消息处理函数、程序图标、光标、窗口背景画刷等待。

2.使用RegisterClass将WNDCLASS类型的变量注册下。

3.使用CreateWindow或CreateWindowEx创建窗口,这里可以设置窗口的初始位置、初始大小、扩展属性等等。

4.通过ShowWindow和UpdateWindow将窗口显示出来。

5.窗口显示完成后,在WinMain()函数中添加消息处理:   

       MSGmsg;
      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):

[cpp]view plaincopyprint?

//   异形窗口1  窗口背景使用位图画刷再指定透明色 
//By MoreWindows-(http://blog.csdn.net/MoreWindows) 
#include <windows.h> 
 
constchar 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; 

    staticHBRUSH 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; 


//   异形窗口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界面编程第四篇 异形窗体 高富帅版》将介绍窗口大小可以指定的异形窗口。欢迎继续浏览。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Windows界面编程 VC MFC