用GDI+制作不规则窗体

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>  

  1. using namespace Gdiplus;  
  2.   
  3. #define MAX_LOADSTRING 100  
  4. //Gdiplus start up params  
  5. ULONG_PTR m_gdiplusToken;  
  6. GdiplusStartupInput m_gdiplusStartupInput;  
  7. //rendering prarams  
  8. BLENDFUNCTION m_Blend;  
  9. //images  
  10. Bitmap * m_BackgoundImage;  
  11. int WINAPI WinMain(HINSTANCE hInstance,  
  12.                    HINSTANCE hPrevInstance,  
  13.                    LPSTR    lpCmdLine,  
  14.                    int       nCmdShow)  
  15. {  
  16.     //....  
  17. }  
  18. BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)  
  19. {  
  20.    //...  
  21.    return TRUE;  
  22. }  
  23. LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
  24. {  
  25.     switch (message)  
  26.     {  
  27.     case WM_CREATE:  
  28.         {  
  29.             GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);  
  30.             m_Blend.BlendOp     = AC_SRC_OVER;  
  31.             m_Blend.AlphaFormat = AC_SRC_ALPHA;  
  32.             m_Blend.BlendFlags  = 0;  
  33.             m_Blend.SourceConstantAlpha = 255;  
  34.             m_BackgoundImage = Bitmap::FromFile(L"meinv.png");  
  35.             if(m_BackgoundImage == NULL)  
  36.             {  
  37.                 MessageBox(hWnd, (LPCSTR)"it is null", (LPCSTR)"OO", 0);  
  38.                 exit(0);  
  39.             }  
  40.    
  41.             int DesktopWidth  = GetSystemMetrics(SM_CXSCREEN);  
  42.             int DesktopHeight = GetSystemMetrics(SM_CYSCREEN);  
  43.       
  44.             g_WindowWidth  = m_BackgoundImage->GetWidth();  
  45.             g_WindowHeight = m_BackgoundImage->GetHeight();  
  46.               
  47.             int StartX = (DesktopWidth - g_WindowWidth)/2;  
  48.             int StartY = (DesktopHeight - g_WindowHeight)/2;  
  49.             SetWindowPos(hWnd, HWND_TOP, StartX, StartY ,g_WindowWidth, g_WindowHeight, SWP_DRAWFRAME);  
  50.         }  
  51.         break;  
  52.     case WM_PAINT:  
  53.         {  
  54.             UpdateWindowView(hWnd);  
  55.         }  
  56.         break;  
  57.         case WM_NCHITTEST:  
  58.         {  
  59.             PostMessage(hWnd, WM_LBUTTONDOWN, wParam, lParam);  
  60.             return HTCAPTION;  
  61.         }  
  62.         break;  
  63.     case WM_DESTROY:  
  64.             GdiplusShutdown(m_gdiplusToken);  
  65.         PostQuitMessage(0);  
  66.             break;  
  67.     default:  
  68.         return DefWindowProc(hWnd, message, wParam, lParam);  
  69.     }  
  70.     return 0;  
  71. }  
  72. void UpdateWindowView(HWND hWnd)  
  73. {  
  74.     //window position  
  75.     RECT rct;  
  76.     GetWindowRect(hWnd, &rct);  
  77.     POINT ptWinPos = {rct.left,rct.top};  
  78.     SIZE szWinSize = {g_WindowWidth - 1, g_WindowHeight - 1};  
  79.       
  80.     HDC dcScreen = GetDC(hWnd);  
  81.     HDC dcmemory = CreateCompatibleDC(dcScreen);  
  82.    
  83.     HBITMAP canvas = CreateCompatibleBitmap(dcScreen, g_WindowWidth, g_WindowHeight);  
  84.       
  85.     SelectObject(dcmemory, canvas);  
  86.       
  87.     Graphics * graphics = Graphics::FromHDC(dcmemory);  
  88.       
  89.     Point points[] =   
  90.     {   
  91.         Point(0, 0),   
  92.     Point(g_WindowWidth, 0),   
  93.     Point(0, g_WindowHeight)  
  94.     };  
  95.     graphics->DrawImage(m_BackgoundImage, points, 3);  
  96.       
  97.     POINT ptSrc = {0, 0};  
  98.      
  99.    //0x80000 是指WS_EX_LAYERED 宏值 ,下边两句可用 ModifyStyleEx(0, WS_EX_LAYERED);代替
  100.     DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);  
  101.     if((dwExStyle&0x80000) != 0x80000)  
  102.     {  
  103.         SetWindowLong(hWnd, GWL_EXSTYLE, dwExStyle^0x80000);  
  104.     }  

  105.     BOOL res = UpdateLayeredWindow(hWnd, dcScreen, &ptWinPos, &szWinSize, dcmemory, &ptSrc, 0, &m_Blend, ULW_ALPHA);  
  106.     DWORD dw = GetLastError();  
  107.     delete graphics;  
  108.       
  109.     DeleteObject(canvas);  
  110.     canvas = NULL;  
  111.       
  112.     //Create出来的dc要用DeleteDC来释放,Get到的要用ReleaseDC释放  
  113.     DeleteDC(dcmemory);      
  114.     ReleaseDC(hWnd, dcScreen);  
  115.     /*最后的这些资源一定记得释放,不然内存泄漏很严重,窗体在拖动的时候很慢。*/  
  116. }  
 

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

另:

//可实现透明效果, 
ModifyStyleEx(0, WS_EX_LAYERED);
SetLayeredWindowAttributes(0,220,LWA_ALPHA);


你可能感兴趣的:(windows,框架,加密,null,Blend,GDI+)