引言
如果能在自己的程式中也具備動態更換皮膚的能力,將使軟體平添幾分亮點從而更易博得使用者的青睞。 具筆者瞭解,當前介紹這種技術的文章資料較少,與其流行程度很不協調,而且現有的少量資料也多是針對對話方塊進行的,無非是在對話方塊上覆蓋一層圖片,並通過更換圖片來實現程式的動態換膚。雖然這也是動態換膚的一種,但由於技術過於簡單,本文將著重介紹另外一種動態換膚技術--工具列的動態換膚技術,這也是ie瀏覽器等軟體所普遍採用的一種換膚技術。
程式支援動態換膚
由於換膚功能是對程式架構的擴充,所以相關處理代碼理所當然地要在主架構類中進行。為了使程式能具備換膚的能力,必須首先使程式具備換膚的基本條件。首先可以明確的是:處理對象為普通的工具條,其基類為ctoolbar。通過msdn協助可以瞭解到該類及其/"近親/"的繼承關係。通過對這幾個相關類的查閱,可以發現crebar類比較特殊,它本身並不用於顯示,而主要用於包容其他的工具條,例如,可以通過其成員函數addbar()將工具條(toolbar)、對話條(dialogbar)等類型的工具條加入到複合條(rebar),使工具列中可以顯示多個工具條。所以可以得出這樣的設計思路:程式架構的工具列不再直接以工具條來實現,而是以複合條為基礎,並通過crebar的addbar()函數將原先的工具條加入其中。皮膚則可以通過設定與crebar相關的rebarbandinfo結構而平鋪於複合條之上,由於有工具條覆於其上,因此必須在建立工具條時修改其風格(style),使其背景為透明,這樣才能透出位於下層的皮膚。
由於在程式設計時使用了crebar,在普通程式中實現起來比較麻煩,可以在建立工程時在第四步選中/"inte.net explorer rebars/"選項,這樣建立的工具列將在複合條上添加一個工具條和一個對話條。只需從主架構類的標頭檔和實現檔案的oncreate()函數裡將對話條cdialogbar的執行個體對象m_wnddlgbar的聲明部分和部分相關代碼去除即可。
接下來在工具條建立時需要特別指定tbstyle_transparent等視窗風格來使其背景透明,並在建立完複合條後通過addbar()函數將背景透明的工具條添加其中:
m_wndtoolbar.createex(this,
tbstyle_flattbstyle_transparent,
ws_childws_visiblecbrs_align_top,
crect(0,0,0,0),afx_idw_toolbar)
……
m_wndrebar.addbar(&m_wndtoolbar,
null,null,
rbbs_gripperalwaysrbbs_fixedbmprbbs_break)
經過上述幾步處理對程式的主架構作了改造,使其基本具備了動態換膚的必要條件。
皮膚的裝載與動態更換
皮膚一般是以外部資源的形式發布,在使用時再由程式動態裝載。皮膚載入到工具列的過程大致可分兩步:先將皮膚從檔案裝載到記憶體,然後再由記憶體位元影像直接繪製到複合條上去。對於第一步,可用api函數loadimage將外部檔案back.bmp從檔案按位元影像的格式裝載到記憶體,返回的控制代碼可通過強制轉換得到hbitmap型的位元影像控制代碼m_bmpback:
m_bmpback=(hbitmap)loadimage(afxgetinstancehandle(), //應用程式執行個體控制代碼
/"back.bmp/",image_bitmap,0,0,
lr_loadfromfilelr_createdibsection);
皮膚裝載到記憶體後,需要通過對rebarbandinfo結構進行設定,才能實現皮膚位元影像在複合條中的平鋪,該結構有二十多個成員變數,但在此只是用於設定背景位元影像的平鋪,因此只需設定fmask為rbbim_background以指定hbmback有效,並將前面裝載到記憶體的位元影像控制代碼m_bmpback傳遞給該成員變數就完成了對皮膚的裝載與顯示,下面就是這部分實現的詳細代碼:
crebarctrl& rc=m_wndrebar.getrebarctrl(); //擷取複合條控制項指標
rebarbandinfo info;
memset(&info,0,sizeof(rebarbandinfo)); //清零
info.cbsize=sizeof(info);
info.fmask=rbbim_background; //指定hbmback有效
//如果位元影像控制代碼不可用則仍為銀灰色背景,否則以此位元影像作為複合條的背景
info.hbmback=m_bmpback!=invalid_handle_value?m_bmpback:null;
rc.setbandinfo(0,&info); //進行設定
rc.updatewindow(); //更新視窗
當皮膚已經顯示到工具列上而對其進行動態更換,則只需要簡單的調用拷貝檔案函數將新的皮膚外掛程式以覆蓋的形式複製到back.bmp,並再次調用上述兩步對新的皮膚外掛程式進行重新裝載即可實現對程式的動態皮膚更換。拷貝檔案函數一般用api函數copyfile()來實現,該函數的前兩個參數分別為源檔案路徑和目的檔案路徑。最後一個布爾型參數指定檔案拷貝的方式,在此需要指定為false,即如果目的檔案已存在則對其覆蓋,否則將無法實現對皮膚的更換。
小結
本文通過對複合條及crebar類的使用實現了在vc下對應用程式的動態皮膚更換。crebar類的功能非常豐富,本文限於篇幅未能做深入的介紹,關於該類的詳細情況請參閱微軟公司的msdn協助。本文所述程式在windows 98下,由microsoft visual c++ 6.0編譯通過。