用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);
#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);
相关文章推荐
- 使用GDI+实现漂亮的不规则窗体制作
- 详解使用C#制作不规则窗体的方法
- 用Borland C# Builder制作不规则窗体
- 用C#.net轻松制作不规则窗体
- C# 制作不规则窗体的两种解决方案
- QT制作不规则窗体
- C# winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题)
- C# 制作不规则窗体的两种解决方案
- [转]用C# Builder制作不规则窗体
- GDI+实现不规则窗体
- 用C#.net轻松制作不规则窗体
- 用PNG透明图片和GDI+做不规则透明窗体
- C# winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题)
- C# winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题)
- C# winform中不规则窗体制作的解决方案
- C# winform中不规则窗体制作的解决方案
- C# winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题)
- C# winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题)
- MFC制作不规则窗体
- 用PNG透明图片和GDI+做不规则透明窗体"异形窗口"