在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添加到工程中