引言
如果能在自己的程序中也具備動(dòng)態(tài)更換皮膚的能力,將使軟件平添幾分亮點(diǎn)從而更易博得用戶的青睞。具筆者了解,當(dāng)前介紹這種技術(shù)的文章資料較少,與其流行程度很不協(xié)調(diào),而且現(xiàn)有的少量資料也多是針對(duì)對(duì)話框進(jìn)行的,無非是在對(duì)話框上覆蓋一層圖片,并通過更換圖片來實(shí)現(xiàn)程序的動(dòng)態(tài)換膚。雖然這也是動(dòng)態(tài)換膚的一種,但由于技術(shù)過于簡單,本文將著重介紹另外一種動(dòng)態(tài)換膚技術(shù)--工具欄的動(dòng)態(tài)換膚技術(shù),這也是IE瀏覽器等軟件所普遍采用的一種換膚技術(shù)。
程序支持動(dòng)態(tài)換膚
由于換膚功能是對(duì)程序框架的擴(kuò)展,所以相關(guān)處理代碼理所當(dāng)然地要在主框架類中進(jìn)行。為了使程序能具備換膚的能力,必須首先使程序具備換膚的基本條件。首先可以明確的是:處理對(duì)象為普通的工具條,其基類為CToolBar。通過MSDN幫助可以了解到該類及其"近親"的繼承關(guān)系如圖所示。通過對(duì)這幾個(gè)相關(guān)類的查閱,可以發(fā)現(xiàn)CReBar類比較特殊,它本身并不用于顯示,而主要用于包容其他的工具條,例如,可以通過其成員函數(shù)AddBar()將工具條(ToolBar)、對(duì)話條(DialogBar)等類型的工具條加入到復(fù)合條(ReBar),使工具欄中可以顯示多個(gè)工具條。所以可以得出這樣的設(shè)計(jì)思路:程序框架的工具欄不再直接以工具條來實(shí)現(xiàn),而是以復(fù)合條為基礎(chǔ),并通過CReBar的AddBar()函數(shù)將原先的工具條加入其中。皮膚則可以通過設(shè)置與CReBar相關(guān)的REBARBANDINFO結(jié)構(gòu)而平鋪于復(fù)合條之上,由于有工具條覆于其上,因此必須在創(chuàng)建工具條時(shí)修改其風(fēng)格(Style),使其背景為透明,這樣才能透出位于下層的皮膚。
由于在程序設(shè)計(jì)時(shí)使用了CReBar,在普通程序中實(shí)現(xiàn)起來比較麻煩,可以在創(chuàng)建工程時(shí)在第四步選中"Internet Explorer ReBars"選項(xiàng),這樣創(chuàng)建的工具欄將在復(fù)合條上添加一個(gè)工具條和一個(gè)對(duì)話條。只需從主框架類的頭文件和實(shí)現(xiàn)文件的OnCreate()函數(shù)里將對(duì)話條CDialogBar的實(shí)例對(duì)象m_wndDlgBar的聲明部分和部分相關(guān)代碼去除即可。
接下來在工具條創(chuàng)建時(shí)需要特別指定TBSTYLE_TRANSPARENT等窗口風(fēng)格來使其背景透明,并在創(chuàng)建完復(fù)合條后通過AddBar()函數(shù)將背景透明的工具條添加其中:
m_wndToolBar.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT, WS_CHILD|WS_VISIBLE|CBRS_ALIGN_TOP, CRect(0,0,0,0),AFX_IDW_TOOLBAR) …… m_wndReBar.AddBar(&m_wndToolBar, NULL,NULL, RBBS_GRIPPERALWAYS|RBBS_FIXEDBMP|RBBS_BREAK) |
經(jīng)過上述幾步處理對(duì)程序的主框架作了改造,使其基本具備了動(dòng)態(tài)換膚的必要條件。
皮膚的裝載與動(dòng)態(tài)更換
皮膚一般是以外部資源的形式發(fā)布,在使用時(shí)再由程序動(dòng)態(tài)裝載。皮膚加載到工具欄的過程大致可分兩步:先將皮膚從文件裝載到內(nèi)存,然后再由內(nèi)存位圖直接繪制到復(fù)合條上去。對(duì)于第一步,可用API函數(shù)LoadImage將外部文件back.bmp從文件按位圖的格式裝載到內(nèi)存,返回的句柄可通過強(qiáng)制轉(zhuǎn)換得到HBITMAP型的位圖句柄m_bmpBack:
m_bmpBack=(HBITMAP)LoadImage(AfxGetInstanceHandle(), //應(yīng)用程序?qū)嵗浔?br>"back.bmp",IMAGE_BITMAP,0,0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); |
皮膚裝載到內(nèi)存后,需要通過對(duì)REBARBANDINFO結(jié)構(gòu)進(jìn)行設(shè)置,才能實(shí)現(xiàn)皮膚位圖在復(fù)合條中的平鋪,該結(jié)構(gòu)有二十多個(gè)成員變量,但在此只是用于設(shè)置背景位圖的平鋪,因此只需設(shè)置fMask為RBBIM_BACKGROUND以指定hbmBack有效,并將前面裝載到內(nèi)存的位圖句柄m_bmpBack傳遞給該成員變量就完成了對(duì)皮膚的裝載與顯示,下面就是這部分實(shí)現(xiàn)的詳細(xì)代碼:
CReBarCtrl& rc=m_wndReBar.GetReBarCtrl(); //獲取復(fù)合條控件指針 REBARBANDINFO info; memset(&info,0,sizeof(REBARBANDINFO)); //清零 info.cbSize=sizeof(info); info.fMask=RBBIM_BACKGROUND; //指定hbmBack有效 //如果位圖句柄不可用則仍為銀灰色背景,否則以此位圖作為復(fù)合條的背景 info.hbmBack=m_bmpBack!=INVALID_HANDLE_VALUE?m_bmpBack:NULL; rc.SetBandInfo(0,&info); //進(jìn)行設(shè)置 rc.UpdateWindow(); //更新窗口 |
當(dāng)皮膚已經(jīng)顯示到工具欄上而對(duì)其進(jìn)行動(dòng)態(tài)更換,則只需要簡單的調(diào)用拷貝文件函數(shù)將新的皮膚插件以覆蓋的形式復(fù)制到back.bmp,并再次調(diào)用上述兩步對(duì)新的皮膚插件進(jìn)行重新裝載即可實(shí)現(xiàn)對(duì)程序的動(dòng)態(tài)皮膚更換??截愇募瘮?shù)一般用API函數(shù)CopyFile()來實(shí)現(xiàn),該函數(shù)的前兩個(gè)參數(shù)分別為源文件路徑和目的文件路徑。最后一個(gè)布爾型參數(shù)指定文件拷貝的方式,在此需要指定為FALSE,即如果目的文件已存在則對(duì)其覆蓋,否則將無法實(shí)現(xiàn)對(duì)皮膚的更換。
小結(jié)
本文通過對(duì)復(fù)合條及CReBar類的使用實(shí)現(xiàn)了在VC下對(duì)應(yīng)用程序的動(dòng)態(tài)皮膚更換。CReBar類的功能非常豐富,本文限于篇幅未能做深入的介紹,關(guān)于該類的詳細(xì)情況請參閱微軟公司的MSDN幫助。本文所述程序在Windows 98下,由Microsoft Visual C++ 6.0編譯通過。