windows sdk编程系列文章 ---- 利用镂空制作特效界面

来源:互联网 发布:网络变压器 好坏 编辑:程序博客网 时间:2024/04/27 16:14
关于背景颜色的rgb值,我们可以通过GetPixel函数来得到。也可以使用一些小工具得到。windows sdk中将窗口设置为不规则形状的函数只有一个,如下:

int SetWindowRgn( HWND hWnd, // handle to windowHRGN hRgn, // handle to region BOOL bRedraw // window redraw option );

从这个函数参数看,想要创建一个不规则的窗口,关键是需要一个不规则的区域。
得到不规则区域的办法,比较简单。步骤是:
1)使用CreateRectRgn函数,创建一个为0的区域。
HRGN wndRgn = ::CreateRectRgn(0,0,0,0);
2)根据平面图的长度和宽度,逐行扫描图,遇到需要非底色的颜色,则创建一个像素的区域。
    //创建一个包含起点与终点间高为1像素的临时“region”
     rgnTemp = CreateRectRgn(iLeftX, y, iX, y+1);
3)将该区域合并1)创建的区域上。
    CombineRgn(wndRgn,wndRgn,rgnTemp, RGN_OR);
4)重复2的步骤,继续扫描,扫描完成后,就得到了我们想要得区域。

上面的步骤贴个代码如下:
void SetupRegion(HDC hDC, HBITMAP &cBitmap, COLORREF TransColor)
{

    //创建与传入DC兼容的临时DC
    HDC memDC= ::CreateCompatibleDC(hDC);
   
    HBITMAP hOldMemBmp(0);
    //将位图选入临时DC
    hOldMemBmp = (HBITMAP)::SelectObject(memDC,cBitmap);
   
    //创建总的窗体区域,初始region为0
    HRGN wndRgn = ::CreateRectRgn(0,0,0,0);
   
   
    BITMAP bit;
    GetObject(cBitmap,sizeof(BITMAP),&bit);//取得位图参数,这里要用到位图的长和宽  
   
    int y;
    for(y=0;y<=bit.bmHeight ;y++)
    {
        HRGN rgnTemp; //保存临时region
       
        int iX = 0;
        do
        {
            //跳过透明色找到下一个非透明色的点.
            while (iX <= bit.bmWidth && GetPixel(memDC,iX, y) == TransColor)
                iX++;
           
            //记住这个起始点
            int iLeftX = iX;
           
            //寻找下个透明色的点
            while (iX <= bit.bmWidth && GetPixel(memDC,iX, y) != TransColor)
                ++iX;
           
            //创建一个包含起点与终点间高为1像素的临时“region”
            rgnTemp = CreateRectRgn(iLeftX, y, iX, y+1);
           
            //合并到主"region".
            CombineRgn(wndRgn,wndRgn,rgnTemp, RGN_OR);
           
            //删除临时"region",否则下次创建时和出错
            DeleteObject(rgnTemp);
        }while(iX <bit.bmWidth );
        iX = 0;
    }
   
    if(hOldMemBmp)
        SelectObject(memDC,hOldMemBmp);
   
    HWND hWnd = WindowFromDC(hDC);
    SetWindowRgn(hWnd,wndRgn,TRUE);
    SetForegroundWindow(hWnd);        
}

本篇例子,我们直接有了这个区域文件,我们把这个区域文件加载到rc中。
我们使用ExtCreateRegion函数,根据rc中加载的rgn资源,来创建一个HRGN.

而我们例子怎样生成一个rgn文件呢,这里给出一个链接,里面给出了一个工具。 http://www.codeproject.com/KB/GDI/rgncreator.aspx

代码:见光盘cws

#include "windows.h"
/************************************************************/
#define ButtonID 1000
#define PictureW 300
#define PictureH 300

HWND g_hwndButton;
HWND g_hWnd;
HRSRC g_RsrcHand;
HGLOBAL g_RsrcPoint;
DWORD g_RsrcSize;


HINSTANCE g_hInstance;
char ClassName[] = "cws_class";
char DisplayName[] = "custom windows shape";
char RsrcName[] = "RANGE";
char RsrcType[] = "RGN";
char ButtonClassName[] = "button";
char ButtonText[] = "Click Me!";
char Text[] = "good bye...";
/************************************************************/
LRESULT CALLBACK WindowProc(          HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
    switch(uMsg)
    {
    case WM_CREATE:
        g_RsrcHand = FindResource(g_hInstance,RsrcName,RsrcType);
        g_RsrcPoint = LoadResource(g_hInstance,g_RsrcHand);
        g_RsrcSize = SizeofResource(g_hInstance,g_RsrcHand);
        g_RsrcPoint = LockResource(g_RsrcPoint);

        SetWindowRgn(hwnd,ExtCreateRegion(NULL,g_RsrcSize,(const struct _RGNDATA *)g_RsrcPoint),TRUE);
        g_hwndButton = CreateWindowEx(NULL,ButtonClassName,ButtonText,
            WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
            150,185,100,25,hwnd,(HMENU)ButtonID,g_hInstance,NULL);

        break;
    case WM_COMMAND:
        if(LOWORD(wParam) == ButtonID)
        {
            MessageBox(hwnd,Text,DisplayName,MB_OK);
            SendMessage(hwnd,WM_DESTROY,NULL,NULL);
        }
        break;
    case WM_LBUTTONDOWN:
        SendMessage(hwnd,WM_NCLBUTTONDOWN,HTCAPTION,lParam);
        break;
    case WM_DESTROY:
        PostQuitMessage(NULL);
        break;
    default:
        return DefWindowProc(hwnd,uMsg,wParam,lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
     WNDCLASSEX wc;
    MSG msg;
    g_hInstance = hInstance;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW |CS_BYTEALIGNWINDOW;
    wc.lpfnWndProc = WindowProc;
    wc.cbClsExtra = NULL;
    wc.cbWndExtra = NULL;
    wc.hInstance = hInstance;
    wc.hbrBackground = CreatePatternBrush(LoadBitmap(hInstance,MAKEINTRESOURCE(1000)));
    wc.lpszMenuName = NULL;
    wc.lpszClassName = ClassName;

    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL,IDC_CROSS);
    wc.hIconSm = NULL;
    RegisterClassEx(&wc);
   
    g_hWnd = CreateWindowEx(WS_EX_LEFT,
        ClassName,
        DisplayName,
        WS_POPUP,
        (GetSystemMetrics(SM_CXSCREEN) - PictureW)/2,
        (GetSystemMetrics(SM_CYSCREEN) - PictureH)/2,
        PictureW,
        PictureH,
        NULL,
        NULL,
        hInstance,
        NULL
        );

    ShowWindow(g_hWnd,SW_SHOWNORMAL);
    UpdateWindow(g_hWnd);

    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

分析:

首先,我们把要镂空处理的图作为背景画刷。
    wc.hbrBackground = CreatePatternBrush(LoadBitmap(hInstance,MAKEINTRESOURCE(1000)));
然后,在创建窗口的时候,我们从资源中加载rgn,并将窗口设置为不规则形状。
    case WM_CREATE:
        g_RsrcHand = FindResource(g_hInstance,RsrcName,RsrcType);
        g_RsrcPoint = LoadResource(g_hInstance,g_RsrcHand);
        g_RsrcSize = SizeofResource(g_hInstance,g_RsrcHand);
        g_RsrcPoint = LockResource(g_RsrcPoint);

        SetWindowRgn(hwnd,ExtCreateRegion(NULL,g_RsrcSize,(const struct _RGNDATA *)g_RsrcPoint),TRUE);

接下来,我们创建了一个按钮。
        g_hwndButton = CreateWindowEx(NULL,ButtonClassName,ButtonText,
            WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON,
            150,185,100,25,hwnd,(HMENU)ButtonID,g_hInstance,NULL);

        break;

为了让窗口能够拖动,我们模拟了 WM_NCLBUTTONDOWN消息。
case WM_LBUTTONDOWN:
        SendMessage(hwnd,WM_NCLBUTTONDOWN,HTCAPTION,lParam);
        break;
原创粉丝点击