站内搜索

不用Hook也能实现方便快捷的换肤功能

  大家都知道如果你想用一个好看的按钮,你通常的做法是两种:1 映射按钮变量 2 .h定义

  CExButton m_btn;然后m_btn.SubclassDlgItem 。这两种做法对于小程序,小工程没有问题但是当工程一大,做起来特别费劲而且容易出错,如果你想去掉这些换一种界面无疑是一场噩梦!下面介绍方法原理简单,实用而且方便。

  首先:

  添加一个辅助类CLxpSkin
  class CXPButton;
  class CEditEx;
  class CLineStatic;
  class CFlatComboBox;
  class CExCheckBox;
  class CExGroupBox;

  class CLxpSkin
  {
  public:

   CLxpSkin(HWND hDlg);  //一个类的实例对应一个对话框

   ~CLxpSkin();

  public: 

   CList<CXPButton*,CXPButton *>m_btnList;//对应一个窗口下面所有的 button 链表 

   CList<CEditEx *,CEditEx *>m_edtList;//对应一个窗口下面所有的 edit 链表 

   CList<CLineStatic *,CLineStatic *>m_lineList;//对应一个窗口下面所有   static 链表

  CList<CFlatComboBox *,CFlatComboBox *>m_cmbList;//对应一个窗口下面所有 ComboBox 链表

  CList<CExCheckBox *,CExCheckBox *>m_chkList;//对应一个窗口下面所有   CheckBox 链表 

  CList<CExGroupBox *,CExGroupBox *>m_grpList;//对应一个窗口下面所有   CheckBox 链表

  private: HWND m_hDlg;

  
  public:
   //记录系统中所有每一个对话框窗口和其对应的LxpSkin类
   static CMap< HWND, HWND, CLxpSkin* , CLxpSkin*>m_mapSkin;

   static BOOL InstallSkin(HWND hDlg);    

   static void UnInstallSkin(HWND hDlg);
  };

  使用方法如下:
  当做完上面的类之后你要做的就是在每个Dialog的OnInitDialog里面写上:CLxpSkin::InstallSkin(

  m_hWnd)
  在OnDestroy()里面写上CLxpSkin::UnInstallSkin(m_hWnd);

  对应的Cpp文件如下:
  CMap< HWND, HWND, CLxpSkin*, CLxpSkin*>CLxpSkin::m_mapSkin;
  CLxpSkin::CLxpSkin(HWND hDlg):m_btnList(10),m_hDlg(hDlg)
  { 
 
  }
  CLxpSkin::~CLxpSkin()
  {
   POSITION pos=m_btnList.GetHeadPosition();
   while(pos != NULL)
   {
    delete m_btnList.GetNext(pos);
   }
   pos=m_edtList.GetHeadPosition();
   while(pos != NULL)
   {
    delete m_edtList.GetNext(pos);
   }
   pos=m_lineList.GetHeadPosition();
   while(pos != NULL)
   {
    delete m_lineList.GetNext(pos);
   }
   pos=m_cmbList.GetHeadPosition();
   while(pos != NULL)
   {
    delete m_cmbList.GetNext(pos);
   }
   pos=m_chkList.GetHeadPosition();

   while(pos != NULL)
   {
    delete m_chkList.GetNext(pos);
   }
   pos=m_grpList.GetHeadPosition();
   while(pos != NULL)
   {
    delete m_grpList.GetNext(pos);
   }
  }
  BOOL CLxpSkin::InstallSkin(HWND hDlg)
  {
   ASSERT(::IsWindow(hDlg));
 
   TCHAR szBuf[256];
   HWND hWnd;
   int  nIdFirst;
   DWORD dwStyle;

   CLxpSkin * pSkin=new CLxpSkin(hDlg);

   //将每一个对话框的句柄和每一个类实例映射起来
   if(pSkin != NULL)
    m_mapSkin.SetAt(hDlg,pSkin);

   hWnd=GetWindow(hDlg,GW_CHILD); 
   if(hWnd == NULL || !::IsWindow(hWnd))
    return FALSE;
   nIdFirst=GetDlgCtrlID(hWnd);

   do
   {
    GetClassName(hWnd,szBuf,256);

    //Edit子类化

    if( _tcsicmp(szBuf,_T("Edit")) == 0)
    {
     //验证是否已经被永久映射
     if(CWnd::FromHandlePermanent(hWnd) == NULL)
     {
   
     CEditEx *pEdit=new CEditEx();
     if(pEdit == NULL)
    return FALSE;
    pSkin->m_edtList.AddTail(pEdit);

    //子类化此窗口
    pEdit->SubclassWindow(hWnd);
   }

  }

  //button子类化

  if(_tcsicmp(szBuf,_T("Button")) == 0)
  {
   dwStyle = GetWindowLong(hWnd,GWL_STYLE);
   if((dwStyle & SS_TYPEMASK) == BS_DEFPUSHBUTTON)
    dwStyle = BS_PUSHBUTTON;
   if((dwStyle & SS_TYPEMASK) == BS_AUTOCHECKBOX)
    dwStyle = BS_CHECKBOX;

   TCHAR szBuf[256];
   GetWindowText(hWnd,szBuf,256);

   //PushButton子类化

   if( (dwStyle & SS_TYPEMASK) == BS_PUSHBUTTON)
   {
    if(CWnd::FromHandlePermanent(hWnd) == NULL)
    {
     CXPButton *pBtn=new CXPButton();
     if(pBtn == NULL)
      return FALSE;
     pSkin->m_btnList.AddTail(pBtn);
     pBtn->SubclassWindow(hWnd);
    }
   }

   //Checkbox子类化

   else if( (dwStyle & SS_TYPEMASK) == BS_CHECKBOX ) 
   {
    if(CWnd::FromHandlePermanent(hWnd) == NULL)
    {
     CExCheckBox *pChk=new CExCheckBox();
     if(pChk == NULL)
      return FALSE;
     pSkin->m_chkList.AddTail(pChk);
     pChk->SubclassWindow(hWnd);

    }
   }
   else if( ( dwStyle & SS_TYPEMASK) == BS_GROUPBOX)
   {
    if(CWnd::FromHandlePermanent(hWnd) == NULL)
    {
     CExGroupBox *pGrp=new CExGroupBox();
     if(pGrp == NULL)
      return FALSE;
     pSkin->m_grpList.AddTail(pGrp);
     pGrp->SubclassWindow(hWnd);
    }
    
   }
  }

  //static子类化

   if( (_tcsicmp(szBuf,_T("Static")) == 0)
   && (GetWindowLong(hWnd,GWL_STYLE) & SS_ETCHEDHORZ) ==

  SS_ETCHEDHORZ)
  { 
   if(CWnd::FromHandlePermanent(hWnd) == NULL)
   {
    CLineStatic * pLine=new CLineStatic();
    if(pLine == NULL)
     return FALSE;
    pSkin->m_lineList.AddTail(pLine);
    pLine->SubclassWindow(hWnd);
   }   
    }

    //ComboBox子类化

  if( _tcsicmp(szBuf,_T("ComboBox")) == 0)
  {
   if(CWnd::FromHandlePermanent(hWnd) == NULL)

  {
    CFlatComboBox *pCmb=new CFlatComboBox();
    if(pCmb == NULL)
     return FALSE;
    pSkin->m_cmbList.AddTail(pCmb);
    pCmb->SubclassWindow(hWnd);
   }
   
  } 

  //etc

  hWnd=GetWindow(hWnd,GW_HWNDNEXT);
  if(!::IsWindow(hWnd) || hWnd==NULL)
   break;

 }while(nIdFirst != GetDlgCtrlID(hWnd));

  return TRUE;

  }
  void CLxpSkin::UnInstallSkin(HWND hDlg)
  {
   CLxpSkin * pSkin=NULL;
   if(m_mapSkin.Lookup(hDlg,pSkin))
   {
    delete pSkin;
    pSkin=NULL;
   }
   return;
  }

  优点:这个类不仅仅可以换界面还可以将工程当中的某些控件功能轻易的改变和还原.

  • 上一篇:VC实现录音,放音,保存,打开功能
  • 下一篇:利用VC从DLL传递消息到EXE