mfc简单换肤

来源:互联网 发布:得力33068软件 编辑:程序博客网 时间:2024/05/04 13:44

      mfc程序的界面一向是大家所诟病的,我之前在写微笔记的时候一直痛心界面的丑陋,所以我下定决定自己写一个换肤的库,虽然有不少bug,但是毕竟是自己的成果,还是蛮开心的。

MySkin.h

#pragma warning(disable:4786)#include <map>#ifndef ULONG_PTR//#define ULONG_PTR unsigned long*#include "GdiPlus.h"using namespace Gdiplus;#endif#pragma comment(lib,"gdiplus.lib")using namespace std;void InitMySkin();void UninitMySkin();LRESULT CALLBACK_MySkinHookFunc(int code, WPARAM wParam, LPARAM lParam);LRESULT CALLBACK _MySkinListBoxProc(          HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam );LRESULT CALLBACK _MySkinDialogProc(          HWND hwnd,   UINT uMsg,   WPARAM wParam,   LPARAM lParam );LRESULT CALLBACK _MySkinButtonProc(          HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam );LRESULT CALLBACK _MySkinStaticProc(          HWND hwnd,   UINT uMsg,   WPARAM wParam,   LPARAM lParam );LRESULT CALLBACK _MySkinEditProc(          HWND hwnd,   UINT uMsg,   WPARAM wParam,   LPARAM lParam );

      MySkin.cpp

#include "StdAfx.h"#include "MySkin.h"map<HWND,WNDPROC> g_mOldFunc;HHOOK g_hMySkinHook;GdiplusStartupInput g_gdiplusStartupInput; ULONG_PTR g_pGdiToken;#define WM_MYDRAWITEM WM_USER+1#define  WM_MYCTLCOLOR WM_USER+2#define  WM_MYMEASUREITEM WM_USER+3 #define  WM_GIFSTOP WM_USER+3void InitMySkin(){g_hMySkinHook=SetWindowsHookEx(WH_CBT,_MySkinHookFunc,0,GetCurrentThreadId());GdiplusStartup(&g_pGdiToken,&g_gdiplusStartupInput,NULL);}void UninitMySkin(){UnhookWindowsHookEx(g_hMySkinHook);GdiplusShutdown(g_pGdiToken);}LRESULT CALLBACK_MySkinHookFunc(int code, WPARAM wParam, LPARAM lParam){if(code==HCBT_CREATEWND){HWND hWin=(HWND)wParam;CBT_CREATEWND* s=(CBT_CREATEWND*)lParam;TCHAR szClass[255]={0};GetClassName(hWin,szClass,255);if(_tcsicmp(szClass,"listbox")==0){int nStyle=GetWindowLong(hWin,GWL_STYLE);if(!(nStyle & LBS_OWNERDRAWFIXED)){SetWindowLong(hWin,GWL_STYLE,GetWindowLong(hWin,GWL_STYLE)|LBS_OWNERDRAWFIXED|LBS_HASSTRINGS);g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinListBoxProc);}}else if(_tcsicmp(szClass,_T("#32770"))==0){SetWindowLong(hWin,GWL_STYLE,GetWindowLong(hWin,GWL_STYLE)&~WS_SYSMENU);g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinDialogProc);}else if(_tcsicmp(szClass,_T("button"))==0){int nStyle=GetWindowLong(hWin,GWL_STYLE);if(!(nStyle & BS_OWNERDRAW)){nStyle=(GetWindowLong(hWin,GWL_STYLE) & BS_TYPEMASK);if(nStyle== BS_PUSHBUTTON || nStyle==BS_DEFPUSHBUTTON){SetWindowLong(hWin,GWL_STYLE,GetWindowLong(hWin,GWL_STYLE)|BS_OWNERDRAW);g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinButtonProc);}}}else if(_tcsicmp(szClass,_T("static"))==0){int nStyle=GetWindowLong(hWin,GWL_STYLE);if(!(nStyle & SS_OWNERDRAW)){g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinStaticProc);}}else if(_tcsicmp(szClass,_T("edit"))==0){g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinEditProc);}return 0;}else if(code==HCBT_DESTROYWND){HWND hWin=(HWND)wParam;if(g_mOldFunc[hWin]){SetWindowLong(hWin,GWL_WNDPROC,(long)g_mOldFunc[hWin]);g_mOldFunc.erase(hWin);}}return CallNextHookEx(g_hMySkinHook,code,wParam,lParam);}LRESULT CALLBACK _MySkinDialogProc(          HWND hwnd,   UINT uMsg,   WPARAM wParam,   LPARAM lParam   ){if(uMsg==WM_MEASUREITEM){LPMEASUREITEMSTRUCT ms=(LPMEASUREITEMSTRUCT)lParam;HWND hWin=GetDlgItem(hwnd,ms->CtlID);SendMessage(hWin,WM_MYMEASUREITEM,wParam,lParam);return 0;}else if(uMsg==WM_DRAWITEM){LPDRAWITEMSTRUCT ds=(LPDRAWITEMSTRUCT)lParam;HWND h=GetDlgItem(hwnd,ds->CtlID);::SendMessage(ds->hwndItem,WM_MYDRAWITEM,wParam,lParam);return 0;}else if(uMsg==WM_CTLCOLOREDIT){HBRUSH b=(HBRUSH)::SendMessage(HWND(lParam),WM_MYCTLCOLOR,wParam,lParam);return (long)b;}else if(uMsg==WM_CTLCOLORDLG){CDC dc;dc.Attach((HDC)wParam);static CBrush b;static bool bFont=false;b.DeleteObject();b.CreateSolidBrush(RGB(253,255,240));dc.Detach();return (long)(HBRUSH)b;}else if(uMsg==WM_NCPAINT){HDC hdc=GetWindowDC(hwnd);CDC *dc=CDC::FromHandle(hdc);CRect r1,r2,rLeft,rTop,rRight,rBottom;GetWindowRect(hwnd,r1);GetClientRect(hwnd,&r2);CWnd::FromHandle(hwnd)->ClientToScreen(&r2);rLeft.left=0;rLeft.top=0;rLeft.right=r2.left-r1.left;rLeft.bottom=r1.Height();rTop.left=0;rTop.top=0;rTop.right=r1.Width();rTop.bottom=r2.top-r1.top;rRight.left=r2.left-r1.left+r2.Width();rRight.top=0;rRight.right=r1.Width();rRight.bottom=r1.Height();rBottom.left=0;rBottom.top=r2.top-r1.top+r2.Height();rBottom.right=r1.Width();rBottom.bottom=r1.Height();dc->FillSolidRect(&rLeft,RGB(113,113,113));dc->FillSolidRect(&rTop,RGB(113,113,113));dc->FillSolidRect(&rRight,RGB(113,113,113));dc->FillSolidRect(&rBottom,RGB(113,113,113));CRect rClose;rClose.left=r1.Width()-30;rClose.right=r1.Width()-10;rClose.top=3;rClose.bottom=28;dc->Draw3dRect(&rClose,RGB(250,250,250),RGB(250,250,250));dc->SetBkMode(TRANSPARENT);dc->SetTextColor(RGB(250,250,250));dc->DrawText(_T("X"),&rClose,DT_CENTER|DT_VCENTER|DT_SINGLELINE);HWND hPar=GetParent(hwnd);if(hPar==GetDesktopWindow() || IsWindowEnabled(hPar) || hwnd==AfxGetMainWnd()->m_hWnd){CRect rMini;rMini.left=rClose.left-25;rMini.right=rClose.left-5;rMini.top=3;rMini.bottom=28;dc->Draw3dRect(&rMini,RGB(250,250,250),RGB(250,250,250));dc->DrawText(_T("_"),&rMini,DT_CENTER|DT_VCENTER|DT_SINGLELINE);}TCHAR szTitle[_MAX_PATH]={0};GetWindowText(hwnd,szTitle,_MAX_PATH);dc->TextOut(5,10,szTitle);ReleaseDC(hwnd,hdc);return 0;}else if(uMsg==WM_NCLBUTTONDOWN){CPoint p;GetCursorPos(&p);CRect r,r1,r2;GetWindowRect(hwnd,&r);CRect rClose;rClose.left=r.Width()-30;rClose.right=r.Width()-10;rClose.top=3;rClose.bottom=28;r1=rClose;CRect rMini;rMini.left=rClose.left-25;rMini.right=rClose.left-5;rMini.top=3;rMini.bottom=28;r2=rMini;r1.OffsetRect(r.TopLeft());r2.OffsetRect(r.TopLeft());if(PtInRect(&r1,p)){PostMessage(hwnd,WM_SYSCOMMAND,SC_CLOSE,MAKELPARAM(p.x,p.y));return 0;}HWND hPar=GetParent(hwnd);if(hPar==GetDesktopWindow() || IsWindowEnabled(hPar) || hwnd==AfxGetMainWnd()->m_hWnd){if(PtInRect(&r2,p)){PostMessage(hwnd,WM_SYSCOMMAND,SC_MINIMIZE,MAKELPARAM(p.x,p.y));return 0;}}}else if(uMsg==WM_NCACTIVATE){SendMessage(hwnd,WM_NCPAINT,0,0);return 1;}else if(uMsg==WM_SETTEXT){CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);SendMessage(hwnd,WM_NCPAINT,0,0);return 1;}return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);}LRESULT CALLBACK _MySkinListBoxProc(          HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam){if(uMsg==WM_ERASEBKGND){CDC dc;dc.Attach((HDC)wParam);CRect r;GetClientRect(hwnd,&r);dc.FillSolidRect(&r,RGB(255,255,176));dc.Detach();return 0;}else if(uMsg==WM_MYMEASUREITEM){LPMEASUREITEMSTRUCT ms=(LPMEASUREITEMSTRUCT)lParam;ms->itemHeight=30;return 0;}else if(uMsg==WM_MYDRAWITEM){LPDRAWITEMSTRUCT ds=(LPDRAWITEMSTRUCT)lParam;CDC dc;dc.Attach(ds->hDC);CRect r=ds->rcItem;if( (ds->itemState & ODS_SELECTED)){dc.FillSolidRect(r.left,r.top,r.Width(),r.Height(),RGB(227,251,251));dc.DrawEdge(&r,EDGE_SUNKEN,BF_BOTTOM);}else/* if((ds->itemAction & ODA_DRAWENTIRE)  || !(ds->itemState & ODS_SELECTED))*/{dc.FillSolidRect(r.left,r.top,r.Width(),r.Height(),RGB(255,255,176));dc.DrawEdge(&r,EDGE_RAISED,BF_BOTTOM);}CPen p;p.CreatePen(PS_SOLID,2,RGB(92,92,92));CPen *oldPen=dc.SelectObject(&p);dc.MoveTo(r.left,r.bottom-1);dc.LineTo(r.right,r.bottom-1);dc.SelectObject(oldPen);TCHAR txt[255]={0};SendMessage(ds->hwndItem,LB_GETTEXT,ds->itemID,(long)txt);dc.SetBkMode(TRANSPARENT);//dc.SetBkColor(RGB(222,22,2));dc.SetTextColor(RGB(111,111,11));CFont f;f.CreatePointFont(120,_T("微软雅黑"));CFont *oldFont=dc.SelectObject(&f);dc.DrawText(txt,strlen(txt),&(ds->rcItem),DT_CENTER|DT_VCENTER|DT_SINGLELINE);dc.SelectObject(oldFont);dc.Detach();return 0;}return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);}LRESULT CALLBACK _MySkinButtonProc(          HWND hwnd,   UINT uMsg,   WPARAM wParam,   LPARAM lParam ){if(uMsg==WM_MYDRAWITEM){LPDRAWITEMSTRUCT ds=(LPDRAWITEMSTRUCT)lParam;CDC dc;CRect r=ds->rcItem;dc.Attach(ds->hDC);dc.Draw3dRect(&ds->rcItem,RGB(2,25,25),RGB(10,0,10));  dc.FillSolidRect(&ds->rcItem,RGB(143,143,216));//Here you can define the required color to appear on the Button. UINT state=ds->itemState; //This defines the state of the Push button either pressed or not.  if((state & ODS_SELECTED)) { dc.DrawEdge(&ds->rcItem,EDGE_SUNKEN,BF_RECT);  } else { dc.DrawEdge(&ds->rcItem,EDGE_RAISED,BF_RECT); } dc.SetBkMode(TRANSPARENT); dc.SetTextColor(RGB(0,0,0));     //Setting the Text Color  TCHAR buffer[MAX_PATH];           //To store the Caption of the button. ZeroMemory(buffer,MAX_PATH );     //Intializing the buffer to zero ::GetWindowText(ds->hwndItem,buffer,MAX_PATH); //Get the Caption of Button Window      dc.DrawText(buffer,&ds->rcItem,DT_CENTER|DT_VCENTER|DT_SINGLELINE);//Redraw the Caption of Button Window dc.Detach();return 0;}return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);}LRESULT CALLBACK _MySkinStaticProc(          HWND hwnd,   UINT uMsg,   WPARAM wParam,   LPARAM lParam ){if(uMsg==WM_PAINT){HWND hPar=GetParent(hwnd);HDC pDc=GetDC(hPar);COLORREF color=GetBkColor(pDc);ReleaseDC(hPar,pDc);CPaintDC dc(CWnd::FromHandle(hwnd));CRect r;GetClientRect(hwnd,&r);dc.FillSolidRect(&r,color);TCHAR szText[_MAX_PATH]={0};GetWindowText(hwnd,szText,_MAX_PATH);CFont *ff=dc.GetCurrentFont();LOGFONT lf;memset(&lf, 0, sizeof(LOGFONT));lf.lfCharSet = DEFAULT_CHARSET;ff->GetLogFont(&lf);if(lf.lfHeight+2>r.Height()){lf.lfHeight=r.Height()+2;}else{lf.lfHeight=lf.lfHeight+2;}_tcscpy(lf.lfFaceName,_T("微软雅黑"));CFont f;f.CreateFontIndirect(&lf);//f.CreatePointFont(90,_T("微软雅黑"));CFont *oldFont=dc.SelectObject(&f);dc.SetBkMode(TRANSPARENT);dc.SetTextColor(RGB(7,126,152));int height=dc.DrawText(szText,&r,DT_EDITCONTROL|DT_WORDBREAK|DT_CALCRECT); //r.DeflateRect(0,height);dc.DrawText(szText,&r,DT_EDITCONTROL|DT_WORDBREAK); dc.SelectObject(oldFont);return 0;}return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);}LRESULT CALLBACK _MySkinEditProc(          HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ){if(uMsg==WM_MYCTLCOLOR){CDC dc;dc.Attach((HDC)wParam);static CBrush b;static bool bFont=false;b.DeleteObject();b.CreateSolidBrush(RGB(181,207,230));dc.SetBkMode(TRANSPARENT);dc.SetBkColor(RGB(181,207,230));dc.SetTextColor(RGB(88,3,46));dc.Detach();if(!bFont){static CFont f;f.CreatePointFont(120,_T("微软雅黑"));SendMessage(hwnd,WM_SETFONT,(WPARAM)(HFONT)f,MAKELPARAM(1,0));bFont=1;}return (long)(HBRUSH)b;}return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);}


       这个换肤是挂钩WH_CBT钩子,这个钩子会在窗口的创建前和销毁前响应,正好适合我们在这里子类化来修改新窗口的消息处理函数,我们把修改的窗口保存到一个map里,然后当窗口销毁时还原原来的消息处理函数,在绘制的过程中,CStatic我用的是wm_paint消息,而其他的控件我用的是owner draw。在这里我发现一点,就是在一个窗体owner draw之前会判断当前有没有无效区,也就是调用beginpaint函数,要是调用了,就不会owner draw,因为子窗体在wm_paint里已经自我绘制了,就不需要交给父窗体来帮他绘制。

        换肤很简单,在mfc的InitInstance中,主窗体doModal前调用InitMySkin()即可,释放在ExitInstance中调用UninitMySkin()即可。

        本文有不足之处,还望大家多多指正。
   

    
原创粉丝点击