在C++builder中为无边框窗口添加阴影
TShadow.h内容如下:
#ifndef __TSHADOW__
#define __TSHADOW__
#include <Forms.hpp>
#include <math.hpp>
#include <algorithm>
#include <map>
using std::min;
using std::max;
#include <gdiplus.h>
using namespace Gdiplus;
using namespace std;
class TShadow : public TCustomForm
{
private:
int m_left,m_top,m_width,m_height;
BLENDFUNCTION m_Blend;
ULONG_PTR m_GdiplusToken;
Gdiplus::GdiplusStartupInput m_GdiplusStartupInput;
HDC m_hdcMemory;
Gdiplus::Image *m_Image;
//新的外部窗口过程
void __fastcall myWindowProc(Messages::TMessage &msg);
//旧的窗口过程指针
Classes::TWndMethod OldWindowProc;
//外部窗口指针
TForm * m_pForm;
//外部TApplication查找主窗口
TApplication * m_App;
protected:
Image * __stdcall GDIGetImageFromResource(HMODULE HInstance, char * RES_ID);
void __stdcall GdiDrawImageFromRes(HMODULE HInstance,char * RES_ID,int left,int top,int width,int height);
void __fastcall CreateParams(Controls::TCreateParams &Params);
public:
__fastcall TShadow(Classes::TComponent* AOwner, int Dummy);
__fastcall ~TShadow();
int __fastcall SetTransparent(int nTran);
void __fastcall SetSize(int left,int top,int width,int height,TForm * AForm);
void SetOutTForm(TForm * fm);
void SetOutApplication(TApplication * outApp);
__published:
__property Width;
__property Height;
__property Left;
__property Top;
__property BorderStyle;
__property AlphaBlend;
__property AlphaBlendValue;
__property Visible;
};
#endif
TShadow.cpp内容如下:
#define STRICT
#include <windows.h>
#include "TShadow.h"
using namespace std;
__fastcall TShadow::TShadow(Classes::TComponent* AOwner, int Dummy):TCustomForm(AOwner,Dummy)
{
GdiplusStartup(&m_GdiplusToken, &m_GdiplusStartupInput, NULL);
//
m_Blend.BlendOp = 0; // the only BlendOp defined in Windows 2000
m_Blend.BlendFlags = 0; // nothing else is special ...
m_Blend.AlphaFormat = 1; // ...
m_Blend.SourceConstantAlpha = 255; // AC_SRC_ALPHA
SetWindowLong(this->Handle,GWL_EXSTYLE, GetWindowLong(this->Handle,GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE);
long dwExStyle = GetWindowLong(this->Handle, GWL_EXSTYLE);
dwExStyle &= ~WS_EX_TOPMOST;
SetWindowLong(this->Handle, GWL_EXSTYLE, dwExStyle);
}
__fastcall TShadow::~TShadow()
{
m_pForm->WindowProc = OldWindowProc;
GdiplusShutdown(m_GdiplusToken); //关闭GDI+
}
int __fastcall TShadow::SetTransparent(int nTran)
{
// Use GDI+ load image
//WideString f =lpSkinFile;
m_Image = GDIGetImageFromResource(HInstance,"SHADOW");//Gdiplus::Image::FromFile(f.c_bstr());
//Change Form size
Width = m_pForm->Width +11;//m_Image->GetWidth();
Height = m_pForm->Height+11;//m_Image->GetHeight();
// Create Compatible Bitmap
HDC hdcTemp = GetDC(0);
m_hdcMemory = CreateCompatibleDC(hdcTemp);
HBITMAP hBitMap = CreateCompatibleBitmap(hdcTemp,Width,Height);
SelectObject(m_hdcMemory, hBitMap);
// Alpha Value
if (nTran<0 || nTran >100)
nTran = 100;
m_Blend.SourceConstantAlpha = int(nTran * 2.55); // 1~255
HDC hdcScreen = ::GetDC(0);
RECT rct;
GetWindowRect(Handle, &rct);
POINT ptWinPos = {rct.left, rct.top};
Gdiplus::Graphics graph(m_hdcMemory);
graph.DrawImage(m_Image, 0, 0, Width, Height);
SIZE sizeWindow = {this->Width, this->Height};
POINT ptSrc = {0, 0};
// Set Window style
DWORD dwExStyle = GetWindowLong(Handle, GWL_EXSTYLE);
if((dwExStyle & 0x80000) != 0x80000)
SetWindowLong(Handle, GWL_EXSTYLE, dwExStyle ^ 0x80000);
//perform the alpha blend
BOOL bRet = UpdateLayeredWindow(Handle, hdcScreen, &ptWinPos,
&sizeWindow, m_hdcMemory, &ptSrc, 0, &m_Blend, 2);
graph.ReleaseHDC(m_hdcMemory);
ReleaseDC(0, hdcScreen);
hdcScreen = NULL;
ReleaseDC(0, hdcTemp);
hdcTemp = NULL;
DeleteObject(hBitMap);
DeleteDC(m_hdcMemory);
m_hdcMemory = NULL;
m_Image = NULL;
return bRet;
}
void __fastcall TShadow::SetSize(int left ,int top,int width,int height,TForm * AForm)
{
m_left = left;
m_top = top;
m_width = width + 11;
m_height = height + 11;
this->Left = m_pForm->Left -5;
this->Top = m_pForm->Top -5;
this->Width = m_pForm->Width +11;
this->Height = m_pForm->Height+11;
SetTransparent(120);
SetWindowPos(this->Handle,HWND_TOP,left-5,top-5,width+12,height+11,SWP_NOMOVE|SWP_NOSIZE);
}
void __fastcall TShadow::myWindowProc(Messages::TMessage &msg)
{
switch(msg.Msg)
{
case WM_ERASEBKGND:
case WM_PAINT:
case WM_MOVE:
case WM_ACTIVATE:
case WM_NCACTIVATE:
{
if (::IsWindowVisible(this->Handle))
{
this->Left = m_pForm->Left - 5;
this->Top = m_pForm->Top - 5;
this->Width = m_pForm->Width + 11;
this->Height = m_pForm->Height+ 11;
}
break;
}
case WM_DESTROY:
{
// Destroy the shadow window.
//this->Hide();
break;
}
case WM_NCDESTROY:
{
// Remove shadow window from map.
//this->Hide();
break;
}
case WM_CLOSE:
{
if(this != m_App->MainForm)
this->Hide();
else
this->Close();
break;
}
case WM_SYSCOMMAND:
{
if(msg.WParam == 0xf020)
{
ShowWindow(this->Handle,SW_HIDE);
}
break;
}
case WM_SHOWWINDOW:
{
// the window is being hidden
if (!msg.WParam)
{
ShowWindow(this->Handle,SW_HIDE);
}
else
{
SetSize(m_left,m_top,m_width,m_height,m_pForm);
ShowWindow(this->Handle,SW_SHOW);
m_pForm->BringToFront();
}
break;
}
default:
{
break;
}
}
OldWindowProc(msg);
}
void TShadow::SetOutTForm(TForm * fm)
{
m_pForm = fm;
OldWindowProc = fm->WindowProc;
fm->WindowProc = myWindowProc;
}
//从资源中加载图片
Image * __stdcall TShadow::GDIGetImageFromResource(HMODULE HInstance, char * RES_ID)
{
//LPCTSTR pResourceName = MAKEINTRESOURCE(nResourceID);
//HMODULE hInstance = ahInstance;
HRSRC hResource = FindResource(HInstance,_T(RES_ID),RT_RCDATA);
if(!hResource)
{
Application->MessageBox("未找到资源","提示",0);
return NULL;
}
//取得资源大小
DWORD dwResourceSize = SizeofResource(HInstance, hResource);
if(!dwResourceSize)
{
return NULL;
}
const void* pResourceData = LockResource(LoadResource(HInstance, hResource));
if(!pResourceData)
{
return NULL;
}
HGLOBAL hResourceBuffer = GlobalAlloc(GMEM_MOVEABLE, dwResourceSize);
if(!hResourceBuffer)
{
GlobalFree(hResourceBuffer);
return NULL;
}
void* pResourceBuffer = GlobalLock(hResourceBuffer);
if(!pResourceBuffer)
{
GlobalUnlock(hResourceBuffer);
GlobalFree(hResourceBuffer);
return NULL;
}
//把资源拷贝到分配的内存中
CopyMemory(pResourceBuffer, pResourceData, dwResourceSize);
IStream* pIStream = NULL;
if(CreateStreamOnHGlobal(hResourceBuffer, FALSE, &pIStream)==S_OK)
{
Image *pImage = Gdiplus::Image::FromStream(pIStream);
pIStream->Release();
GlobalUnlock(hResourceBuffer);
GlobalFree(hResourceBuffer);
return pImage;
}
return NULL;
}
//从资源中显示图片
//资源类型:Icon,Cursor,Bitmap,String,Accelerators,Menu,Dialog,RCData,Version info
void __stdcall TShadow::GdiDrawImageFromRes(HMODULE HInstance,char * RES_ID,int left,int top,int width,int height)
{
Image *img = GDIGetImageFromResource(HInstance,RES_ID);
}
void TShadow::SetOutApplication(TApplication * outApp)
{
m_App = outApp;
}
void __fastcall TShadow::CreateParams(Controls::TCreateParams &Params)
{
TCustomForm::CreateParams(Params);
Params.WndParent = GetDesktopWindow();
}
在无边框窗口的构造函数中,调用如下:
#include <vcl.h>
#include <windows.h>
#include "TShadow.h"
__fastcall TfrmShowMessage::TfrmShowMessage(TComponent* Owner)
: TForm(Owner)
{
m_pShadow = new TShadow(Application,3);
m_pShadow->SetOutTForm(this);
m_pShadow->SetOutApplication(Application);
m_pShadow->SetSize(this->Left,this->Top,this->Width,this->Height,this);
}
在编译的时候,工程中须包含gdiplus.lib,同时还要包含一个资源文件,此资源文件中包含一幅有阴影的png图片.rc文件内容如下:
SHADOW RCDATA test.png
.rc文件编译成.res如下:
brcc32 -32 shadow.rc //在记事本中添加此行内容,并保为.bat为扩展名的文件,然后执行,产生相应的res文件,将此res添加到工程中