mfc简单换肤

本文介绍了一种基于MFC的简单换肤方案,通过WH_CBT钩子实现在窗口创建和销毁时进行子类化处理,以改变窗口的外观。文章详细展示了如何通过自定义绘图函数为按钮、编辑框等控件定制样式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


mfc简单换肤

分类: c++   237人阅读  评论(0)  收藏  举报

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

MySkin.h

[cpp]  view plain copy
  1. #pragma warning(disable:4786)  
  2. #include <map>  
  3. #ifndef ULONG_PTR  
  4. //#define ULONG_PTR unsigned long*  
  5. #include "GdiPlus.h"  
  6. using namespace Gdiplus;  
  7. #endif  
  8. #pragma comment(lib,"gdiplus.lib")  
  9. using namespace std;  
  10. void InitMySkin();  
  11. void UninitMySkin();  
  12. LRESULT CALLBACK  
  13. _MySkinHookFunc(int code, WPARAM wParam, LPARAM lParam);  
  14. LRESULT CALLBACK _MySkinListBoxProc(          HWND hwnd,  
  15.                                     UINT uMsg,  
  16.                                     WPARAM wParam,  
  17.                                     LPARAM lParam  
  18.                          );  
  19. LRESULT CALLBACK _MySkinDialogProc(          HWND hwnd,  
  20.                                    UINT uMsg,  
  21.                                    WPARAM wParam,  
  22.                                    LPARAM lParam  
  23.                          );  
  24. LRESULT CALLBACK _MySkinButtonProc(          HWND hwnd,  
  25.                                     UINT uMsg,  
  26.                                     WPARAM wParam,  
  27.                                     LPARAM lParam  
  28.                          );  
  29. LRESULT CALLBACK _MySkinStaticProc(          HWND hwnd,  
  30.                                    UINT uMsg,  
  31.                                    WPARAM wParam,  
  32.                                    LPARAM lParam  
  33.                          );  
  34. LRESULT CALLBACK _MySkinEditProc(          HWND hwnd,  
  35.                                    UINT uMsg,  
  36.                                    WPARAM wParam,  
  37.                                    LPARAM lParam  
  38.                          );  

      MySkin.cpp

[cpp]  view plain copy
  1. #include "StdAfx.h"  
  2. #include "MySkin.h"  
  3. map<HWND,WNDPROC> g_mOldFunc;  
  4. HHOOK g_hMySkinHook;  
  5. GdiplusStartupInput g_gdiplusStartupInput;  
  6.  ULONG_PTR g_pGdiToken;  
  7. #define WM_MYDRAWITEM WM_USER+1  
  8. #define  WM_MYCTLCOLOR WM_USER+2  
  9. #define  WM_MYMEASUREITEM WM_USER+3  
  10.  #define  WM_GIFSTOP WM_USER+3  
  11. void InitMySkin()  
  12. {  
  13.     g_hMySkinHook=SetWindowsHookEx(WH_CBT,_MySkinHookFunc,0,GetCurrentThreadId());  
  14.     GdiplusStartup(&g_pGdiToken,&g_gdiplusStartupInput,NULL);  
  15. }  
  16. void UninitMySkin()  
  17. {  
  18.     UnhookWindowsHookEx(g_hMySkinHook);  
  19.     GdiplusShutdown(g_pGdiToken);  
  20. }  
  21. LRESULT CALLBACK  
  22. _MySkinHookFunc(int code, WPARAM wParam, LPARAM lParam)  
  23. {  
  24.     if(code==HCBT_CREATEWND)  
  25.     {  
  26.         HWND hWin=(HWND)wParam;  
  27.         CBT_CREATEWND* s=(CBT_CREATEWND*)lParam;  
  28.         TCHAR szClass[255]={0};  
  29.         GetClassName(hWin,szClass,255);  
  30.           
  31.         if(_tcsicmp(szClass,"listbox")==0)  
  32.         {  
  33.             int nStyle=GetWindowLong(hWin,GWL_STYLE);  
  34.             if(!(nStyle & LBS_OWNERDRAWFIXED))  
  35.             {  
  36.                 SetWindowLong(hWin,GWL_STYLE,GetWindowLong(hWin,GWL_STYLE)|LBS_OWNERDRAWFIXED|LBS_HASSTRINGS);  
  37.                 g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinListBoxProc);  
  38.             }  
  39.       
  40.         }else if(_tcsicmp(szClass,_T("#32770"))==0)  
  41.         {  
  42.             SetWindowLong(hWin,GWL_STYLE,GetWindowLong(hWin,GWL_STYLE)&~WS_SYSMENU);  
  43.             g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinDialogProc);  
  44.               
  45.         }else   if(_tcsicmp(szClass,_T("button"))==0)  
  46.         {  
  47.             int nStyle=GetWindowLong(hWin,GWL_STYLE);  
  48.             if(!(nStyle & BS_OWNERDRAW))  
  49.             {  
  50.                 nStyle=(GetWindowLong(hWin,GWL_STYLE) & BS_TYPEMASK);  
  51.                 if(nStyle== BS_PUSHBUTTON || nStyle==BS_DEFPUSHBUTTON)  
  52.                 {  
  53.                     SetWindowLong(hWin,GWL_STYLE,GetWindowLong(hWin,GWL_STYLE)|BS_OWNERDRAW);  
  54.                     g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinButtonProc);  
  55.   
  56.                 }  
  57.             }  
  58.         }else   if(_tcsicmp(szClass,_T("static"))==0)  
  59.         {  
  60.             int nStyle=GetWindowLong(hWin,GWL_STYLE);  
  61.             if(!(nStyle & SS_OWNERDRAW))  
  62.             {  
  63.                 g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinStaticProc);  
  64.             }  
  65.         }else   if(_tcsicmp(szClass,_T("edit"))==0)  
  66.         {  
  67.                 g_mOldFunc[hWin]=(WNDPROC)SetWindowLong(hWin,GWL_WNDPROC,(long)_MySkinEditProc);  
  68.         }  
  69.         return 0;  
  70.     }  
  71.     else if(code==HCBT_DESTROYWND)  
  72.     {  
  73.         HWND hWin=(HWND)wParam;  
  74.         if(g_mOldFunc[hWin])  
  75.         {  
  76.             SetWindowLong(hWin,GWL_WNDPROC,(long)g_mOldFunc[hWin]);  
  77.             g_mOldFunc.erase(hWin);  
  78.         }  
  79.     }  
  80.     return CallNextHookEx(g_hMySkinHook,code,wParam,lParam);  
  81. }  
  82. LRESULT CALLBACK _MySkinDialogProc(          HWND hwnd,  
  83.                                    UINT uMsg,  
  84.                                    WPARAM wParam,  
  85.                                    LPARAM lParam  
  86.                                    )  
  87. {  
  88.     if(uMsg==WM_MEASUREITEM)  
  89.     {  
  90.         LPMEASUREITEMSTRUCT ms=(LPMEASUREITEMSTRUCT)lParam;  
  91.         HWND hWin=GetDlgItem(hwnd,ms->CtlID);  
  92.         SendMessage(hWin,WM_MYMEASUREITEM,wParam,lParam);  
  93.         return 0;  
  94.     }  
  95.     else if(uMsg==WM_DRAWITEM)  
  96.     {  
  97.         LPDRAWITEMSTRUCT ds=(LPDRAWITEMSTRUCT)lParam;  
  98.         HWND h=GetDlgItem(hwnd,ds->CtlID);  
  99.         ::SendMessage(ds->hwndItem,WM_MYDRAWITEM,wParam,lParam);  
  100.         return 0;  
  101.     }  
  102.     else if(uMsg==WM_CTLCOLOREDIT)  
  103.     {  
  104.         HBRUSH b=(HBRUSH)::SendMessage(HWND(lParam),WM_MYCTLCOLOR,wParam,lParam);  
  105.         return (long)b;  
  106.     }else if(uMsg==WM_CTLCOLORDLG)  
  107.     {  
  108.         CDC dc;  
  109.         dc.Attach((HDC)wParam);  
  110.         static CBrush b;  
  111.         static bool bFont=false;  
  112.         b.DeleteObject();  
  113.         b.CreateSolidBrush(RGB(253,255,240));  
  114.         dc.Detach();  
  115.         return (long)(HBRUSH)b;  
  116.     }  
  117.     else if(uMsg==WM_NCPAINT)  
  118.     {  
  119.         HDC hdc=GetWindowDC(hwnd);  
  120.         CDC *dc=CDC::FromHandle(hdc);  
  121.         CRect r1,r2,rLeft,rTop,rRight,rBottom;  
  122.         GetWindowRect(hwnd,r1);  
  123.           
  124.         GetClientRect(hwnd,&r2);  
  125.         CWnd::FromHandle(hwnd)->ClientToScreen(&r2);  
  126.         rLeft.left=0;  
  127.         rLeft.top=0;  
  128.         rLeft.right=r2.left-r1.left;  
  129.         rLeft.bottom=r1.Height();  
  130.         rTop.left=0;  
  131.         rTop.top=0;  
  132.         rTop.right=r1.Width();  
  133.         rTop.bottom=r2.top-r1.top;  
  134.         rRight.left=r2.left-r1.left+r2.Width();  
  135.         rRight.top=0;  
  136.         rRight.right=r1.Width();  
  137.         rRight.bottom=r1.Height();  
  138.         rBottom.left=0;  
  139.         rBottom.top=r2.top-r1.top+r2.Height();  
  140.         rBottom.right=r1.Width();  
  141.         rBottom.bottom=r1.Height();  
  142.         dc->FillSolidRect(&rLeft,RGB(113,113,113));  
  143.         dc->FillSolidRect(&rTop,RGB(113,113,113));  
  144.         dc->FillSolidRect(&rRight,RGB(113,113,113));  
  145.         dc->FillSolidRect(&rBottom,RGB(113,113,113));  
  146.         CRect rClose;  
  147.         rClose.left=r1.Width()-30;  
  148.         rClose.right=r1.Width()-10;  
  149.         rClose.top=3;  
  150.         rClose.bottom=28;  
  151.         dc->Draw3dRect(&rClose,RGB(250,250,250),RGB(250,250,250));  
  152.         dc->SetBkMode(TRANSPARENT);  
  153.         dc->SetTextColor(RGB(250,250,250));  
  154.         dc->DrawText(_T("X"),&rClose,DT_CENTER|DT_VCENTER|DT_SINGLELINE);  
  155.         HWND hPar=GetParent(hwnd);  
  156.         if(hPar==GetDesktopWindow() || IsWindowEnabled(hPar) || hwnd==AfxGetMainWnd()->m_hWnd)  
  157.         {  
  158.             CRect rMini;  
  159.             rMini.left=rClose.left-25;  
  160.             rMini.right=rClose.left-5;  
  161.             rMini.top=3;  
  162.             rMini.bottom=28;  
  163.             dc->Draw3dRect(&rMini,RGB(250,250,250),RGB(250,250,250));  
  164.             dc->DrawText(_T("_"),&rMini,DT_CENTER|DT_VCENTER|DT_SINGLELINE);  
  165.         }  
  166.         TCHAR szTitle[_MAX_PATH]={0};  
  167.         GetWindowText(hwnd,szTitle,_MAX_PATH);  
  168.         dc->TextOut(5,10,szTitle);  
  169.         ReleaseDC(hwnd,hdc);  
  170.         return 0;  
  171.     }else if(uMsg==WM_NCLBUTTONDOWN)  
  172.     {  
  173.         CPoint p;  
  174.         GetCursorPos(&p);  
  175.         CRect r,r1,r2;  
  176.         GetWindowRect(hwnd,&r);  
  177.         CRect rClose;  
  178.         rClose.left=r.Width()-30;  
  179.         rClose.right=r.Width()-10;  
  180.         rClose.top=3;  
  181.         rClose.bottom=28;  
  182.         r1=rClose;  
  183.         CRect rMini;  
  184.         rMini.left=rClose.left-25;  
  185.         rMini.right=rClose.left-5;  
  186.         rMini.top=3;  
  187.         rMini.bottom=28;  
  188.         r2=rMini;  
  189.         r1.OffsetRect(r.TopLeft());  
  190.         r2.OffsetRect(r.TopLeft());  
  191.         if(PtInRect(&r1,p))  
  192.         {  
  193.             PostMessage(hwnd,WM_SYSCOMMAND,SC_CLOSE,MAKELPARAM(p.x,p.y));  
  194.             return 0;  
  195.         }  
  196.         HWND hPar=GetParent(hwnd);  
  197.         if(hPar==GetDesktopWindow() || IsWindowEnabled(hPar) || hwnd==AfxGetMainWnd()->m_hWnd)  
  198.         {  
  199.             if(PtInRect(&r2,p))  
  200.             {  
  201.                 PostMessage(hwnd,WM_SYSCOMMAND,SC_MINIMIZE,MAKELPARAM(p.x,p.y));  
  202.                 return 0;  
  203.         }  
  204.         }  
  205.     }else if(uMsg==WM_NCACTIVATE)  
  206.     {  
  207.         SendMessage(hwnd,WM_NCPAINT,0,0);  
  208.         return 1;  
  209.     }else if(uMsg==WM_SETTEXT)  
  210.     {  
  211.         CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);  
  212.         SendMessage(hwnd,WM_NCPAINT,0,0);  
  213.         return 1;  
  214.     }  
  215.     return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);  
  216.       
  217. }  
  218. LRESULT CALLBACK _MySkinListBoxProc(          HWND hwnd,  
  219.                                     UINT uMsg,  
  220.                                     WPARAM wParam,  
  221.                                     LPARAM lParam  
  222.                                     )  
  223. {  
  224.         if(uMsg==WM_ERASEBKGND)  
  225.         {  
  226.             CDC dc;  
  227.             dc.Attach((HDC)wParam);  
  228.             CRect r;  
  229.             GetClientRect(hwnd,&r);  
  230.             dc.FillSolidRect(&r,RGB(255,255,176));  
  231.             dc.Detach();  
  232.             return 0;  
  233.         }  
  234.         else if(uMsg==WM_MYMEASUREITEM)  
  235.         {  
  236.             LPMEASUREITEMSTRUCT ms=(LPMEASUREITEMSTRUCT)lParam;  
  237.             ms->itemHeight=30;  
  238.             return 0;  
  239.         }  
  240.         else if(uMsg==WM_MYDRAWITEM)  
  241.         {  
  242.             LPDRAWITEMSTRUCT ds=(LPDRAWITEMSTRUCT)lParam;  
  243.             CDC dc;  
  244.             dc.Attach(ds->hDC);  
  245.             CRect r=ds->rcItem;  
  246.             if( (ds->itemState & ODS_SELECTED))  
  247.             {  
  248.                 dc.FillSolidRect(r.left,r.top,r.Width(),r.Height(),RGB(227,251,251));  
  249.                 dc.DrawEdge(&r,EDGE_SUNKEN,BF_BOTTOM);  
  250.             }  
  251.             else/* if((ds->itemAction & ODA_DRAWENTIRE)  || !(ds->itemState & ODS_SELECTED))*/  
  252.             {  
  253.                 dc.FillSolidRect(r.left,r.top,r.Width(),r.Height(),RGB(255,255,176));  
  254.                 dc.DrawEdge(&r,EDGE_RAISED,BF_BOTTOM);  
  255.             }  
  256.             CPen p;  
  257.             p.CreatePen(PS_SOLID,2,RGB(92,92,92));  
  258.             CPen *oldPen=dc.SelectObject(&p);  
  259.             dc.MoveTo(r.left,r.bottom-1);  
  260.             dc.LineTo(r.right,r.bottom-1);  
  261.             dc.SelectObject(oldPen);  
  262.             TCHAR txt[255]={0};  
  263.             SendMessage(ds->hwndItem,LB_GETTEXT,ds->itemID,(long)txt);  
  264.             dc.SetBkMode(TRANSPARENT);  
  265.             //  dc.SetBkColor(RGB(222,22,2));  
  266.             dc.SetTextColor(RGB(111,111,11));  
  267.             CFont f;  
  268.             f.CreatePointFont(120,_T("微软雅黑"));  
  269.             CFont *oldFont=dc.SelectObject(&f);  
  270.             dc.DrawText(txt,strlen(txt),&(ds->rcItem),DT_CENTER|DT_VCENTER|DT_SINGLELINE);  
  271.             dc.SelectObject(oldFont);  
  272.             dc.Detach();  
  273.             return 0;  
  274.         }  
  275.     return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);  
  276. }  
  277. LRESULT CALLBACK _MySkinButtonProc(          HWND hwnd,  
  278.                                    UINT uMsg,  
  279.                                    WPARAM wParam,  
  280.                                    LPARAM lParam  
  281.                          )  
  282. {  
  283.         if(uMsg==WM_MYDRAWITEM)  
  284.         {  
  285.             LPDRAWITEMSTRUCT ds=(LPDRAWITEMSTRUCT)lParam;  
  286.             CDC dc;  
  287.             CRect r=ds->rcItem;  
  288.             dc.Attach(ds->hDC);  
  289.             dc.Draw3dRect(&ds->rcItem,RGB(2,25,25),RGB(10,0,10));   
  290.              dc.FillSolidRect(&ds->rcItem,RGB(143,143,216));//Here you can define the required color to appear on the Button.  
  291.              UINT state=ds->itemState; //This defines the state of the Push button either pressed or not.   
  292.              if((state & ODS_SELECTED))  
  293.              {  
  294.                  dc.DrawEdge(&ds->rcItem,EDGE_SUNKEN,BF_RECT);              
  295.              }  
  296.              else  
  297.              {  
  298.                  dc.DrawEdge(&ds->rcItem,EDGE_RAISED,BF_RECT);     
  299.              }  
  300.              dc.SetBkMode(TRANSPARENT);  
  301.              dc.SetTextColor(RGB(0,0,0));     //Setting the Text Color  
  302.                
  303.              TCHAR buffer[MAX_PATH];           //To store the Caption of the button.  
  304.              ZeroMemory(buffer,MAX_PATH );     //Intializing the buffer to zero  
  305.              ::GetWindowText(ds->hwndItem,buffer,MAX_PATH); //Get the Caption of Button Window   
  306.                
  307.     dc.DrawText(buffer,&ds->rcItem,DT_CENTER|DT_VCENTER|DT_SINGLELINE);//Redraw the Caption of Button Window   
  308.     dc.Detach();  
  309.                 return 0;  
  310.         }  
  311. return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);  
  312. }  
  313. LRESULT CALLBACK _MySkinStaticProc(          HWND hwnd,  
  314.                                    UINT uMsg,  
  315.                                    WPARAM wParam,  
  316.                                    LPARAM lParam  
  317.                          )  
  318. {  
  319.     if(uMsg==WM_PAINT)  
  320.     {  
  321.         HWND hPar=GetParent(hwnd);  
  322.         HDC pDc=GetDC(hPar);  
  323.         COLORREF color=GetBkColor(pDc);  
  324.         ReleaseDC(hPar,pDc);  
  325.         CPaintDC dc(CWnd::FromHandle(hwnd));  
  326.         CRect r;  
  327.         GetClientRect(hwnd,&r);  
  328.         dc.FillSolidRect(&r,color);  
  329.         TCHAR szText[_MAX_PATH]={0};  
  330.         GetWindowText(hwnd,szText,_MAX_PATH);  
  331.         CFont *ff=dc.GetCurrentFont();  
  332.         LOGFONT lf;  
  333.         memset(&lf, 0, sizeof(LOGFONT));  
  334.         lf.lfCharSet = DEFAULT_CHARSET;  
  335.         ff->GetLogFont(&lf);  
  336.         if(lf.lfHeight+2>r.Height())  
  337.         {  
  338.             lf.lfHeight=r.Height()+2;  
  339.         }  
  340.         else  
  341.         {  
  342.             lf.lfHeight=lf.lfHeight+2;  
  343.         }  
  344.         _tcscpy(lf.lfFaceName,_T("微软雅黑"));  
  345.         CFont f;  
  346.         f.CreateFontIndirect(&lf);  
  347.     //  f.CreatePointFont(90,_T("微软雅黑"));  
  348.         CFont *oldFont=dc.SelectObject(&f);  
  349.         dc.SetBkMode(TRANSPARENT);  
  350.         dc.SetTextColor(RGB(7,126,152));  
  351.         int height=dc.DrawText(szText,&r,DT_EDITCONTROL|DT_WORDBREAK|DT_CALCRECT);   
  352.         //r.DeflateRect(0,height);  
  353.         dc.DrawText(szText,&r,DT_EDITCONTROL|DT_WORDBREAK);   
  354.         dc.SelectObject(oldFont);  
  355.         return 0;  
  356.     }  
  357.     return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);  
  358. }  
  359. LRESULT CALLBACK _MySkinEditProc(          HWND hwnd,  
  360.                                  UINT uMsg,  
  361.                                  WPARAM wParam,  
  362.                                  LPARAM lParam  
  363.                          )  
  364. {  
  365.     if(uMsg==WM_MYCTLCOLOR)  
  366.     {  
  367.         CDC dc;  
  368.         dc.Attach((HDC)wParam);  
  369.         static CBrush b;  
  370.         static bool bFont=false;  
  371.         b.DeleteObject();  
  372.         b.CreateSolidBrush(RGB(181,207,230));  
  373.         dc.SetBkMode(TRANSPARENT);  
  374.         dc.SetBkColor(RGB(181,207,230));  
  375.         dc.SetTextColor(RGB(88,3,46));  
  376.         dc.Detach();  
  377.         if(!bFont)  
  378.         {  
  379.             static CFont f;  
  380.             f.CreatePointFont(120,_T("微软雅黑"));  
  381.             SendMessage(hwnd,WM_SETFONT,(WPARAM)(HFONT)f,MAKELPARAM(1,0));  
  382.             bFont=1;  
  383.         }  
  384.         return (long)(HBRUSH)b;  
  385.     }  
  386.     return CallWindowProc(g_mOldFunc[hwnd],hwnd,uMsg,wParam,lParam);  
  387. }  


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

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

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

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值