[转贴]Skin技术实现框架(四)

来源:互联网 发布:无法删除打印机端口 编辑:程序博客网 时间:2024/05/21 12:47

 

今天有点空了,继续写。上次我们已经得出了基本的设计,由此确定了每种窗口必须有一个类来与之对应,这里所说的窗口种类是按照窗口的windows class名称来区分的,class名称相同的就认为是一种窗口。这种分类方法和我们看到的窗口种类可能有一些差异,例如,普通按钮,单选按钮和复选框的类名都是“Button”,对于这种情况,我们仍然用一个类来对应这些窗口,而在类内部区分对待这些不同的窗口。
这样,我们要为每种需要改变外观的控件窗口编写一个类,根据面向对象的思想,我们很自然的想到提取出它们的公共基类,这就是CWidgetHookBase,所有控件窗口处理类的公共基类,实际上是一个C++接口,因为它只包含一个纯虚函数,下面是它的定义:

///////////////////////////////////////////////////////////////////

/// Abstract base class for widget hook

class CWidgetHookBase

{

public:

     virtual void Install(HWND hWidget) = 0; //implemented in CWidgetHook

    

};

 


这个接口中唯一的Install函数用来实现把对象链接到窗口的功能,也就是SubclassWindow,这会在继承类实现,后面我们再说怎么实现它。今天要讲的实际上是控件类工厂,也就是CWidgetFactory及其继承类。下面是CWidgetFactory的完整声明和实现:

/////////////////////////////////////////////////////////////////////////////////////

/// Abstract factory class for widget hooks. create hook instances

class CWidgetFactory

{

protected:

     static CWidgetFactory* m_pInstance;

public:

     // initialize the instance

     CWidgetFactory()

     {

         ATLASSERT(m_pInstance==NULL);

         m_pInstance = this;

     }

     // Get the singleton instance

     static CWidgetFactory* Instance()

     {

         return m_pInstance;

     }

     virtual CWidgetHookBase*    CreateWidget(LPCTSTR szClass) = 0;

};

 

CWidgetFactory* CWidgetFactory::m_pInstance = NULL;


CWidgetFactory使用了两个设计模式,Singleton模式和Abstract Factory模式,实际上还包括Factory Method模式。
首先看抽象工厂模式,我们希望控件工厂根据窗口class的名字创建出不同的控件窗口消息处理类。对于模拟Mac的系统,这些控件窗口消息处理类包括CMacButton, CMacComboBox, CMacTrackBar等;而对于模拟KDE的系统,则是CKDEButton, CKDEComboBox等。这样,我们就可以定义两个CWidgetFactory的继承类,分别叫CMacFactory和CKDEFactory,分别产生这两个系列的对象。CWidgetFactory::CreateWidget就是用来产生这些对象的方法,它是个纯虚函数,必须在继承类中实现。CreateWidget接受窗口class的名字为参数,返回CWidgetHookBase指针,也就是所有控件类的基类。这样,每个对象工厂负责产生一系列对象,但对于一个应用程序来说,应该只有一种风格,也就是说,只能有一个工厂的实例,单件模式来了
这里使用了简化版的Singleton模式,需要声明一个继承类的实例,然后通过CWidgetFactory的静态函数Instance得到这个唯一实例。这里没有控制不能生成第二个实例,不过这不是大问题。
现在来看Factory的一个实现,CMacFactory,完整的代码如下:

class CMacFactory : public CWidgetFactory

{

public:

     virtual CWidgetHookBase*    CreateWidget(LPCTSTR szClass)

     {

         if (lstrcmpi(szClass, "Button") == 0 )

              return new CMacButton;

         else if (lstrcmpi(szClass, "#32770") == 0) //dialog

              return new CMacDialog;

         else if (lstrcmpi(szClass, "ListBox") == 0)

              return new CMacListBox;

         else if (lstrcmpi(szClass, WC_TABCONTROL) == 0)

              return new CMacTabCtrl;

         else if (lstrcmpi(szClass, "#32768") == 0) //menu

              return new CMacMenu;

         else if (lstrcmpi(szClass, "ComboBox") == 0) //combobox

              return new CMacCombo;

         else if (lstrcmpi(szClass, TRACKBAR_CLASS) == 0) //trackbar

              return new CMacTrackBar;

         return NULL;

     }

 

};


再看看消息钩子的代码,都很简单吧

LRESULT CALLBACK CMacSkin::HookProc(int nCode, WPARAM wParam, LPARAM lParam)

{

     CWPSTRUCT cwps;

    

     if( nCode == HC_ACTION )

     {

         CopyMemory(&cwps, (LPVOID)lParam, sizeof(CWPSTRUCT));

        

         switch(cwps.message)

         {

         case WM_CREATE:

              {

                   CHAR szClass[MAX_PATH];

                   GetClassName(cwps.hwnd, szClass, MAX_PATH);

 

                   CWidgetHookBase*   pWidget=NULL;

                  

                   pWidget = CWidgetFactory::Instance()->CreateWidget(szClass);

                   if (pWidget)

                       pWidget->Install(cwps.hwnd);

              }

              break;

         }

     }

    

     return CallNextHookEx((HHOOK)CMacSkin::m_hHook, nCode, wParam, lParam);

}


不管对于CMacFactory还是其他的工厂实现,以及不同的控件类系列,钩子函数的实现都是一样的。CWidgetFactory继承类的实现也非常相似,只是替换一些类名而已。
今天把工厂类和钩子都讲完了,可能不是很清楚,那也只能这样了,其实看代码最清楚了。下次讲怎么实现控件吧,包括如何利用ATL/WTL的基础架构,那是我最喜欢的部分了
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 银行卡绑定的手机号码换了怎么办 支付宝手机号码换了怎么办 淘宝账号被注销了怎么办 注销淘宝号绑定的手机号怎么办 淘宝账号不小心注销了怎么办 淘宝旧密码忘了怎么办 淘宝登录原始密码忘记了怎么办 微信原始密码忘记了怎么办 优酷会员重复交费怎么办 微信解绑手机号密码忘了怎么办 闪银呼呼逾期5天怎么办 忘记淘宝账号和密码怎么办 蘑菇街账号忘了怎么办 台式电脑密码忘记了怎么办 单位社保登陆密码忘记了怎么办 12306的登录密码忘了怎么办 网银支付密码忘了怎么办 邮政网银密码忘了怎么办 12306新注册待核验怎么办 建行网银盾密码忘了怎么办 建行网银登陆密码忘了怎么办 建行网银密码忘了怎么办 建行手机网银密码忘了怎么办 移动宽带账号密码忘了怎么办 移动宽带忘记账号密码怎么办 宽带账号密码忘了怎么办 不知道宽带账号密码怎么办 宽带的账号密码忘记了怎么办 wifi登录名忘记了怎么办 苹果手机微信图纸打不开怎么办 手机qq邮箱文件打不开怎么办 12360忘记用户名和密码怎么办 刚开店铺没生意怎么办 淘宝账户不符合注销条件怎么办 网易邮箱登录密码忘记了怎么办 q号密码忘记了怎么办 志愿者注册忘记密码和用户名怎么办 w10电脑语言栏不见了怎么办 w10美式键盘没了怎么办 xp电脑开机密码忘记了怎么办 电脑开机密码到期忘记改怎么办