您的位置:首页 > 其它

用GDI+制作不规则窗体

2011-11-10 10:48 190 查看
1.
#define TRANS_COLOR         (ALPHA_MASK | RGB(255, 0, 255))
BOOL CMyDialog::OnInitDialog()

{

    CDialog::OnInitDialog();
    CRgn rgn;

    CreateRgnByImage(_T("MyImage.png"), rgn);

    SetWindowRgn(rgn, TRUE);
    return TRUE;

}
void CMyDialog::CreateRgnByImage(const CString &imageName, CRgn &rgn)

{

    Bitmap img(imageName);

    ASSERT(PixelFormat32bppARGB == img.GetPixelFormat());
    Rect rect(0, 0, img.GetWidth(), img.GetHeight());

    BitmapData data;

    img.LockBits(&rect, ImageLockModeRead, PixelFormat32bppARGB, &data);

    UINT *pData = static_cast<UINT*>(data.Scan0);
    rgn.CreateRectRgn(0, 0, 0, 0);
    CRgn tempRgn;

    for (UINT h = 0; h < data.Height; ++ h)

    {

        UINT w = 0;

        while(w < data.Width)

        {

            UINT leftX;

            while (w ++ < data.Width && TRANS_COLOR == *pData ++);

            leftX = w;

            while (w ++ < data.Width && TRANS_COLOR != *pData ++);
            tempRgn.CreateRectRgn(leftX, h, w - 1, h + 1);

            rgn.CombineRgn(&rgn, &tempRgn, RGN_OR);

            tempRgn.DeleteObject();

        }

    }
    img.UnlockBits(&data);

}

2.

如果使用一幅位图,通过挖图的方式来做成一个不规则的窗体,是很累人的一件事。
  而使用GDI+,可以直接用PNG图片,通过图片本身的透明度,自动创建不规则窗体。

  比如,你手中有个美女图,通过PhotoShop等工具,把美女的身体抠出来,保存为PNG格式的图片,除了美女的身体,图片的其他部门都是透明的。后面的工作就是,写一个windows小程序,加载这幅美女图,让她成为我们程序的界面。

 

  Win32程序的框架我就懒得贴了,直接贴关键代码了。

 view
plain#include<GdiPlus.h>  

using namespace Gdiplus;  

  

#define MAX_LOADSTRING 100  

//Gdiplus start up params  

ULONG_PTR m_gdiplusToken;  

GdiplusStartupInput m_gdiplusStartupInput;  

//rendering prarams  

BLENDFUNCTION m_Blend;  

//images  

Bitmap * m_BackgoundImage;  

int WINAPI WinMain(HINSTANCE hInstance,  

                   HINSTANCE hPrevInstance,  

                   LPSTR    lpCmdLine,  

                   int       nCmdShow)  

{  

    //....  

}  

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  

{  

   //...  

   return TRUE;  

}  

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  

{  

    switch (message)  

    {  

    case WM_CREATE:  

        {  

            GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);  

            m_Blend.BlendOp     = AC_SRC_OVER;  

            m_Blend.AlphaFormat = AC_SRC_ALPHA;  

            m_Blend.BlendFlags  = 0;  

            m_Blend.SourceConstantAlpha = 255;  

            m_BackgoundImage = Bitmap::FromFile(L"meinv.png");  

            if(m_BackgoundImage == NULL)  

            {  

                MessageBox(hWnd, (LPCSTR)"it is null", (LPCSTR)"OO", 0);  

                exit(0);  

            }  

   

            int DesktopWidth  = GetSystemMetrics(SM_CXSCREEN);  

            int DesktopHeight = GetSystemMetrics(SM_CYSCREEN);  

      

            g_WindowWidth  = m_BackgoundImage->GetWidth();  

            g_WindowHeight = m_BackgoundImage->GetHeight();  

              

            int StartX = (DesktopWidth - g_WindowWidth)/2;  

            int StartY = (DesktopHeight - g_WindowHeight)/2;  

            SetWindowPos(hWnd, HWND_TOP, StartX, StartY ,g_WindowWidth, g_WindowHeight, SWP_DRAWFRAME);  

        }  

        break;  

    case WM_PAINT:  

        {  

            UpdateWindowView(hWnd);  

        }  

        break;  

        case WM_NCHITTEST:  

        {  

            PostMessage(hWnd, WM_LBUTTONDOWN, wParam, lParam);  

            return HTCAPTION;  

        }  

        break;  

    case WM_DESTROY:  

            GdiplusShutdown(m_gdiplusToken);  

        PostQuitMessage(0);  

            break;  

    default:  

        return DefWindowProc(hWnd, message, wParam, lParam);  

    }  

    return 0;  

}  

void UpdateWindowView(HWND hWnd)  

{  

    //window position  

    RECT rct;  

    GetWindowRect(hWnd, &rct);  

    POINT ptWinPos = {rct.left,rct.top};  

    SIZE szWinSize = {g_WindowWidth - 1, g_WindowHeight - 1};  

      

    HDC dcScreen = GetDC(hWnd);  

    HDC dcmemory = CreateCompatibleDC(dcScreen);  

   

    HBITMAP canvas = CreateCompatibleBitmap(dcScreen, g_WindowWidth, g_WindowHeight);  

      

    SelectObject(dcmemory, canvas);  

      

    Graphics * graphics = Graphics::FromHDC(dcmemory);  

      

    Point points[] =   

    {   

        Point(0, 0),   

    Point(g_WindowWidth, 0),   

    Point(0, g_WindowHeight)  

    };  

    graphics->DrawImage(m_BackgoundImage, points, 3);  

      

    POINT ptSrc = {0, 0};  

     

 
 //0x80000 是指WS_EX_LAYERED 宏值 ,下边两句可用 ModifyStyleEx(0, WS_EX_LAYERED);代替

    DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);  

    if((dwExStyle&0x80000) != 0x80000)  

    {  

        SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle^0x80000);  

    }  

    BOOL res = UpdateLayeredWindow(hWnd, dcScreen, &ptWinPos, &szWinSize, dcmemory, &ptSrc, 0, &m_Blend, ULW_ALPHA);  

    DWORD dw = GetLastError();  

    delete graphics;  

      

    DeleteObject(canvas);  

    canvas = NULL;  

      

    //Create出来的dc要用DeleteDC来释放,Get到的要用ReleaseDC释放  

    DeleteDC(dcmemory);      

    ReleaseDC(hWnd, dcScreen);  

    /*最后的这些资源一定记得释放,不然内存泄漏很严重,窗体在拖动的时候很慢。*/  

}  

 
  不过呢,这么做也有个不爽的地方,你使用的PNG图片必须也和你的程序一起发布,不能隐藏在程序代码中。当然了一般的游戏都是有专门的资源包,并且做了加密的。我看剑侠叁的启动界面应该就是使用GDI+来做的,很漂亮。

另:
//可实现透明效果, 
ModifyStyleEx(0, WS_EX_LAYERED);
SetLayeredWindowAttributes(0,220,LWA_ALPHA);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: