用PNG透明图片和GDI+做不规则透明窗体
一、准备工作(PNG图片透空窗体)
1、图片资源准备工作。首先在Photoshop中编辑所用图片,将这些图片保存成为带透明通道的.png格式(GDI+调用显示时能够透明调背景)。这样程序中图片资源就准备好了。
2、下面开始做好展开此项工作的基本准备工作。
创建一个对话框应用程序,名称为Gdi+PNG
在VC6.0下的设置:
(1)、下载gdiplus forVC6.0的SDK,(总共两兆多)
(2)、在C盘建立文件夹“GDI+”将开发包拷贝在里面,亦即建立如下路径,以便例子代码顺利编译(当然你可以放到任意你喜欢的地方,只要在你的Project中正确包含路径即可!)。
(也可以将gdiplus.h放在你的VC6.0的include路径,gdiplus.lib放在你的lib路径,将gdiplus.dll放到你的system32目路下,windows2000以前的版本需要gdiplus.dll文件)
C:\GDI+\Includes
C:\GDI+\Lib
C:\GDI+\gdiplus.dll
(3)在stdAfx.h中添加对GDI+环境的设置 #define UNICODE
#ifndef ULONG_PTR // 在VC2003上可无
#define ULONG_PTR unsigned long* // 在VC2003上可无(实为无附号4字节)
#endif // 在VC2003上可无
#include <comdef.h> //初始化COM口
#include "c:\gdi+\includes\gdiplus.h" // 请修改为你的头文件路径
using namespace Gdiplus; // 名称空间
#pragma comment(lib, "c:\\gdi+\\lib\\gdiplus.lib") // 请修改为你的.lib文件路径
在VC2003中如下设置:
(1)VS2003.net中打开“项目”---“属性”---“链接器”---“输入”---“附加依赖项”,输入“gdiplus.lib”。
(2)在“stdafx.h”文件中输入
#include <comdef.h> //初始化COM口
#include <gdiplus.h> // GDI+头文件
using namespace Gdiplus; // 命名空间
(3)VS2003中已经带有GDI+库了。
在应用程序的主头文件(Gdi+PNG.h)里面,在应用程序项目的应用类中,添加一个成员变量,如下列代码:
ULONG_PTR m_pGdiToken; // 其中,ULONG_PTR是一个DWORD数据类型,
// 该成员变量用来保存GDI+被初始化后在应用程序中的GDI+标识,
// 以便能在应用程序退出后,引用该标识来调用Gdiplus:: GdiplusShutdown来关闭GDI+
在应用程序的类行为(Gdi+PNG.cpp)InitInstance()初始化函数里加入如下代码:
CWinApp::InitInstance(); // 这个函数后面
GdiplusStartupInput m_gdiplusStartupInput;
GdiplusStartup(&m_pGdiToken,&m_gdiplusStartupInput,NULL);
//在对话框程序结束后,在应用类中添加ExitInstance的重载,并添加下列代码用来关闭GDI+,
//关闭gdiplus的环境
应用程序的类行为的ExitInstance()函数里加入:
GdiplusShutdown(m_pGdiToken);
return CWinApp::ExitInstance(); // 这个语句前
二、程序的实现过程
1、在Gdi+PNGDlg.h中定义所有类成员变量,包括所有图片的指针和图片的长宽尺寸信息。
// 自定义数据
Image *m_pImageBack; // 背景图像指针,Image是一个图像类。
HDC m_hdcMemory;
int m_BakWidth; // 背景图像宽
int m_BakHeight; // 背景图像高
BLENDFUNCTION m_Blend;
HINSTANCE hFuncInst;
typedef BOOL (WINAPI*MYFUNC)(HWND,HDC,POINT*,SIZE*,HDC,POINT*, COLORREF,BLENDFUNCTION*,DWORD);
MYFUNC UpdateLayeredWindow;
在这一步中需要特别说明的是,在创建透明窗口式需要调用一个Windows API函数UpdateLayeredWindow(),该函数在.net以上的版本的SDK中有申明,但是在VC6.0下要调用要么下载200多兆的高版本SDK,要么从动态链接库“User32.dll”中调用,这里选择从“User32.dll”中调用。以上定义中后三项就是为此作准备的。
UpdateLayeredWindow(hwnd:HWND; // 窗口句柄
hdcDst:HDC; // 目标 DC
ptDst:pPoint; // 目标的 TopLeft
Size:pSize; // 显示 Size
hdcSrc:HDC; // 源 DC
ptSrc:pPoint; // 源 DC 的 TopLeft
crKey:COLORREF; // 透明颜色值
Blend:pBlendFunction; // Alpha 混合函数
dwFlags:DWord // 一组标志位常量
);
2、在对话框的OnCreate()中添加如下代码:对函数和成员变量进行初始化!(其中ImageFromIDResource()函数为从资源中载入Png图像的一个方法!)
int CGDIPClockDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
hFuncInst = LoadLibrary("User32.DLL");
if(hFuncInst)
UpdateLayeredWindow=(MYFUNC)GetProcAddress(hFuncInst, "UpdateLayeredWindow");
else
{
AfxMessageBox("User32.dll ERROR!");
exit(0);
}
//初始化gdiplus的环境
// Initialize GDI+.
m_Blend.BlendOp=0; //theonlyBlendOpdefinedinWindows2000
m_Blend.BlendFlags=0; //nothingelseisspecial...
m_Blend.AlphaFormat=1; //...
m_Blend.SourceConstantAlpha=255;//AC_SRC_ALPHA // 透明度
using namespace Gdiplus; // 名称空间
m_pImageBack = Gdiplus::Image::FromFile(L"F:\\abc.png"); // 直接读取文件,注意是双“\\”斜杠
// ImageFromIDResource(IDR_PNG2, "PNG", m_pImageBack); // 读取资源中的PNG图片, 为自订义类形“PNG”
// 这里Image没有提供字节调用资源中图像的函数,
// ImageFromIDResource()是通过资源名称"PNG"和资源ID号将图像的Image指针传递给指针应用。来完成的。
// 这个函数是摘自网上
// ImageFileMe("F:\\abc.png", m_pImageBack); // 读取二进制文件
m_BakWidth = m_pImageBack->GetWidth(); // 返回图片宽度
m_BakHeight = m_pImageBack->GetHeight(); // 返回图片高度
// 以下是实现窗口在最上面。
::SetWindowPos(m_hWnd, HWND_TOPMOST,0,0,m_BakWidth,m_BakHeight,SWP_NOSIZE|SWP_NOMOVE);
return 0;
}
3、在OnDestroy()里输入删除图像的代码
void CMfcGdi1Dlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: 在此处添加消息处理程序代码
delete m_pImageBack;
m_pImageBack = NULL;
}
5、在OnPaint() 中输入以下代码, m_Blend.SourceConstantAlpha表示整个窗体的透明度
HDC hdcTemp = GetDC()->m_hDC;
m_hdcMemory = CreateCompatibleDC(hdcTemp);
HBITMAP hBitMap = CreateCompatibleBitmap(hdcTemp, m_BakWidth, m_BakHeight);
SelectObject(m_hdcMemory, hBitMap);
// m_Blend.SourceConstantAlpha=100; // 窗口透明度最大为255,最小为0
HDC hdcScreen = ::GetDC(m_hWnd);
RECT rct;
GetWindowRect(&rct);
POINT ptWinPos = {rct.left, rct.top};
Graphics graph(m_hdcMemory);
Point points[] = { Point(0, 0),
Point(m_BakWidth, 0),
Point(0, m_BakHeight)};
static bool bFly = false;
graph.DrawImage(m_pImageBack, points,3);
SIZE sizeWindow={m_BakWidth,m_BakHeight};
POINT ptSrc={0,0};
DWORD dwExStyle=GetWindowLong(m_hWnd,GWL_EXSTYLE);
if((dwExStyle&0x80000)!=0x80000)
SetWindowLong(m_hWnd,GWL_EXSTYLE,dwExStyle^0x80000);
UpdateLayeredWindow(m_hWnd, hdcScreen, &ptWinPos, &sizeWindow, m_hdcMemory, &ptSrc, 0, &m_Blend, 2);
graph.ReleaseHDC(m_hdcMemory);
::ReleaseDC(m_hWnd,hdcScreen);
hdcScreen=NULL;
::ReleaseDC(m_hWnd,hdcTemp);
hdcTemp=NULL;
DeleteObject(hBitMap);
DeleteDC(m_hdcMemory);
m_hdcMemory=NULL;
以下为自订义的读取资源函数,如果图片不在资源里可以不用输入。
BOOL CGDIPClockDlg::ImageFromIDResource(UINT nID, LPCTSTR sTR,Image * &pImg)
{
HINSTANCE hInst = AfxGetResourceHandle();
HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(nID),sTR); // type
if (!hRsrc)
return FALSE;
// load resource into memory
DWORD len = SizeofResource(hInst, hRsrc);
BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);
if (!lpRsrc)
return FALSE;
// Allocate global memory on which to create stream
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
memcpy(pmem,lpRsrc,len);
IStream* pstm;
CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);
// load from stream
pImg=Gdiplus::Image::FromStream(pstm);
// free/release stuff
GlobalUnlock(m_hMem);
pstm->Release();
FreeResource(lpRsrc);
}
BOOL CMfcGdi1Dlg::ImageFileMe(LPCTSTR filename, Image * &pImg) //我自已加入的用来读二进制文件的。可以不用输
{
// Allocate global memory on which to create stream
HFILE filehwnd;
OFSTRUCT fileopenbuff;
filehwnd = OpenFile(filename, &fileopenbuff, OF_READ);
if (filehwnd == HFILE_ERROR)
return FALSE;
int len = GetFileSize((HANDLE)filehwnd, 0);
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
_lread(filehwnd, m_hMem, len);
IStream* pstm;
CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);
// load from stream
pImg=Gdiplus::Image::FromStream(pstm);
// free/release stuff
GlobalUnlock(m_hMem);
pstm->Release();
_lclose(filehwnd);
}
以下为可以拖动窗口。
void CGDIPClockDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
//禁止显示移动矩形窗体框
::SystemParametersInfo(SPI_SETDRAGFULLWINDOWS,TRUE,NULL,0);
//非标题栏移动整个窗口
SendMessage(WM_SYSCOMMAND,0xF012,0);
// PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x,point.y));
CDialog::OnLButtonDown(nFlags, point);
}