GDI+用PNG圖片做半透明異型窗口

一、準備工作(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);
}
————————————————
版權聲明:本文爲CSDN博主「納木錯」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/neubuffer/article/details/16899949

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章