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()即可。
本文有不足之处,还望大家多多指正。
- mfc简单换肤
- mfc简单换肤
- BCGControlBar MFC对话框换肤
- BCGControlBar MFC对话框换肤
- BCGControlBar MFC对话框换肤
- MFC界面换肤美化
- 简单换肤
- 简单的换肤
- 关于MFC程序的换肤问题
- BCGControlBar MFC对话框换肤(续)
- MFC 利用 Codejock XtremeToolkitPro 换肤
- MFC 利用 Codejock XtremeToolkitPro 换肤
- MFC 利用 Codejock XtremeToolkitPro 换肤
- VS2013 Codejock 实现 MFC 换肤
- MFC 软件换肤使用 SkinMagic2.21
- MFC界面美化之换肤
- CSS换肤简单示例
- CSS换肤简单示例
- 对象使用之前初始化
- 买土豆的故事
- const
- 我的数据库学习“曲线”
- 数据库三大范式
- mfc简单换肤
- poj1017--贪心算法
- 李开复:我要找什么样的人一起创业?
- 一些CEdit使用方法
- 第十八章 如果再回到从前-备忘录模式(读书笔记)
- ubuntu/Linuxmint 下 电子辞典/词典/字典 总结
- 排序 : 1 交换排序
- 软件工程师的十个“不职业”行为
- JSP页面中Session对象详解