Windows 98的發(fā)布給熱衷于UI的用戶帶來(lái)了福音,它內(nèi)嵌的Plus!,動(dòng)態(tài) 彈出的菜單與ToolTip,更有那顏色漸變的Title Bar給我們?cè)鎏砹嗽S多的樂(lè)趣。 其實(shí)即便是在Windows 95下也能使你的程序的Title Bar更具有個(gè)人魅力,在 Norton Utilities for 95中就有了顏色漸變的Title Bar,在大量的Delphi 3.0 的第三方控件中更有提供了此類完整功能的控件。當(dāng)然用控件可以快速開(kāi)發(fā)漂亮的 程序,但對(duì)于爬鍵盤(pán)的人來(lái)說(shuō),了解程序內(nèi)核的機(jī)理并且做出更Cool的Title Bar 才是最爽的事!本文列舉了用代碼裝飾你的Title Bar的幾種方法。 1、修改Registry庫(kù)
在Windows 9x的桌面中,進(jìn)入Display Properties對(duì)話框中的Appearance屬性 頁(yè),可以修改Title Bar的字體的寬度與顏色。實(shí)際上所有這些更改都進(jìn)入了 Registry庫(kù)的HKEY-CURRENT-USER/Control Panel下。由于都是單純的數(shù)字, 對(duì)于字體是不好修改的,但若是單純修改顏色值,則在Control Panel的Colors下有 明顯的value Name與value Data的含義。例如在Windows 98中,value Name為 ActiveTitle,value Data為“0 0 128”;value Name為GradientActiveTitle, value Data為“168 200 240”,即表示活動(dòng)時(shí)的Title Bar顏色由深藍(lán)色漸變到淺 藍(lán)色。值的含義很明顯即為RGB的值。用Win32 SDK中的修改Registry庫(kù)的API修改各 項(xiàng)意義明顯的Color值,別忘了最后發(fā)送WM-SYSCOLORCHANGE消息給自己的窗口, 來(lái)驗(yàn)證改變后的效果。
此種方法的好處是思路簡(jiǎn)單,并且下次重啟Windows后,所有窗口均是改變后的 顏色,但是方法有些勉強(qiáng)且功能不強(qiáng)。
2、利用SetSystem Color函數(shù)
SetSystemColor的解釋請(qǐng)參考相應(yīng)手冊(cè),不再詳述。這里僅列出一段代碼片段, 示意將Windows背景改為黑色,將Windows中的文字改為綠色。
int aiDsp[2]; DWORD aRgb[2]; aiDsp[0]=COLOR-WINDOW; aRgb[0]=RGB(0, 0, 0); aiDsp[1]=COLOR-WINDOWTEXT; aRgb[1]=RGB(0, 255, 0); SetSysColors(2, aiDsp, aRgb);
SetSysColors會(huì)自動(dòng)給所有Windows發(fā)送WM-SYSCOLORCHANGE消息向所有Window 聲名系統(tǒng)顏色改變,但是并不改變注冊(cè)庫(kù),因?yàn)橄麓沃貑indows后,系統(tǒng)顏色又恢復(fù)原樣。
本方法實(shí)現(xiàn)簡(jiǎn)單,但影響了其他窗口特性,且功能太少。
3、拿起你的刷(brush),握住你的筆(pen),在DC上盡情地想畫(huà)什么就畫(huà)什么
在Windows 98下用VC 5.0生成小的Demo,在Windows 95下運(yùn)行也正常。 下面先了解一下Windows重畫(huà)非客戶區(qū)的過(guò)程。在處理WM-NCPAINT、WM-NCACTIVE、 WM-SYSCOMMAND、WM-SETTEXT消息之后,Windows調(diào)用缺省處理消息函數(shù)DefWindowProc, 在此函數(shù)中將對(duì)非客戶區(qū)進(jìn)行重畫(huà)操作,故而在CWnd的虛函數(shù)DefWindowProc中, 重畫(huà)Title Bar,就可以達(dá)到我們的目的,但是若不對(duì)消息進(jìn)行一定的過(guò)濾,勢(shì)必引 起過(guò)多的重畫(huà),我們假定Title Bar上沒(méi)有System Menu,即沒(méi)有最大、最小和關(guān)閉按 鈕在Title Bar上(見(jiàn)代碼片段1)。這樣可以簡(jiǎn)化操作。對(duì)消息的過(guò)濾與重畫(huà)操作見(jiàn) 代碼片段2。
代碼片段1:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { cs.style &=~WS-SYSMENU; //取消Title Bar上的按鈕 return CFrameWnd::PreCreateWindow(cs); }
代碼片段2:
LRESULT CMainFrame::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) { LRESULT lrst=CFrameWnd::DefWindowProc(message, wParam, lParam); if (!::IsWindow(m-h(huán)Wnd)) return lrst; if (message=WM-NCPAINT ||message=WM-NCACTIVATE ||message=WM-NOTIFY) { CDC pWinDC=GetWindowDC(); if (pWinDC) DrawTitleBar(pWinDC); ReleaseDC(pWinDC); } return lrst; }
在DrawTitleBar函數(shù)中,我們將采用乾坤大挪移,將Icon畫(huà)到了右邊,將最小、 最大、關(guān)閉按鈕畫(huà)到了左邊,并畫(huà)上了顏色漸變的Title Bar,在中間寫(xiě)了“My Own Cool Title Bar!!!”的標(biāo)題(見(jiàn)代碼片段3)。最后將最小、最大、關(guān)閉按鈕連上 了各自的消息(見(jiàn)代碼片段4)。
代碼片段3:
void CMainFrame::DrawTitleBar(CDC* pDC) { if (m-h(huán)Wnd) { CRect rtWnd, rtTitle, rtButtons; GetWindowRect(&rtWnd); //整個(gè)Window的相對(duì)于屏幕的矩形 //取得整個(gè)Title bar的矩形 rtTitle.left=GetSystemMetrics(SM-CXFRAME); rtTitle.top=GetSystemMetrics(SM-CYFRAME); rtTitle.right=rtWnd.right-rtWnd.left-GetSystemMetrics(SM-CXFRAME); rtTitle.bottom=rtTitle.top+GetSystemMetrics(SM-CYSIZE); //重畫(huà)顏色漸變的Title Bar;有DC,有矩形,想怎么畫(huà)就怎么畫(huà) DrawGradientBar(pDC, rtTitle); //此函數(shù)源碼因篇幅略去 //重畫(huà)icon HICON hIcon=(HICON)::GetClassLong(m-h(huán)Wnd, GCL-HICON); m-rtIcon.left=rtTitle.right-GetSystemMetrics(SM-CYSMICON); m-rtIcon.top=rtTitle.top+1; m-rtIcon.right=m-rtIcon.left+GetSystemMetrics(SM-CXSMICON); m-rtIcon.bottom=m-rtIcon.top+GetSystemMetrics(SM-CYSMICON); ::DrawIconEx(pDC->m-h(huán)DC, m-rtIcon.left, m-rtIcon.top,hIcon, GetSystemMetrics (SM-CXSMICON), GetSystemMetrics(SM-CYSMICON), 0, NULL, DI-NORMAL); m-rtIcon.OffsetRect(rtWnd.TopLeft()); //記錄Icon屏幕位置 //重畫(huà)最小button int nButtHeight=GetSystemMetrics(SM-CYSMSIZE)-3; rtButtons.left=rtTitle.left; rtButtons.top=rtTitle.top+(GetSystemMetrics(SM-CYSIZE)-nButtHeight)/2; rtButtons.right=rtButtons.left+GetSystemMetrics(SM-CXSMSIZE); rtButtons.bottom=rtButtons.top+nButtHeight; pDC->DrawFrameControl(&rtButtons, DFC-CAPTION, DFCS-CAPTIONMIN); m-rtButtMin=rtButtons; m-rtButtMin.OffsetRect(rtWnd.TopLeft()); //記錄最小button屏幕位置 //重畫(huà)最大或恢復(fù)button rtButtons.left=rtButtons.right; rtButtons.right=rtButtons.left+GetSystemMetrics(SM-CXSMSIZE); pDC->DrawFrameControl(&rtButtons, DFC-CAPTION, IsZoomed() ? DFCS-CAPTIONRESTORE : DFCS-CAPTIONMAX); m-rtButtMax=rtButtons; m-rtButtMax.OffsetRect(rtWnd.TopLeft());//記錄button屏幕位置 //重畫(huà)關(guān)閉button rtButtons.left=rtButtons.right; rtButtons.right=rtButtons.left+GetSystemMetrics(SM-CXSMSIZE); pDC->DrawFrameControl(&rtButtons, DFC-CAPTION, DFCS-CAPTIONCLOSE); m-rtButtExit=rtButtons; m-rtButtExit.OffsetRect(rtWnd.TopLeft())//記錄關(guān)閉button屏幕位置; //重畫(huà)caption int nOldMode=pDC->SetBkMode(TRANSPARENT); COLORREF clOldText=pDC->SetTextColor(RGB(0, 0, 0)); pDC->SelectStockObject(ANSI-FIXED-FONT); rtTitle.right-=GetSystemMetrics (SM-CYSMICON); pDC->DrawText((LPSTR)″My Own Cool Title Bar!!!″, -1, &rtTitle, DT-CENTER); pDC->SetBkMode(nOldMode); pDC->SetTextColor(clOldText); } }
代碼片段4:
void CMainFrame::OnNcLButtonDown(UINT nHitTest, CPoint point) { //處理缺省操作,諸如雙擊Title Bar等其他動(dòng)作 Default(); //檢測(cè)最小,最大和關(guān)閉按鈕是否按到 if (m-rtButtExit.PtInRect(point)) SendMessage(WM-CLOSE); else if (m-rtButtMin.PtInRect(point)) SendMessage(WM-SYSCOMMAND, SC-MINIMIZE, MAKELPARAM(point.x, point.y) ); else if (m-rtButtMax.PtInRect(point)) { if (IsZoomed()) SendMessage(WM-SYSCOMMAND, SC-RESTORE, MAKELPARAM(point.x, point.y)); else SendMessage(WM-SYSCOMMAND, SC-MAXIMIZE, MAKELPARAM(point.x, point.y) ); } }
這里需要補(bǔ)充一點(diǎn),若要程序更健壯,需要監(jiān)視WM-WININICHANGED消息,因 為用戶可能在別處動(dòng)態(tài)地改變Title Bar的寬度及其他寬度,此時(shí)需要重新取得Title Bar的各項(xiàng)新值,使得Title Bar重畫(huà)。
實(shí)際上有了DC,有了矩形,的確是可以隨心所欲了,但是有了獨(dú)創(chuàng)就一定有付出。 要完成徹底的乾坤大挪移,還需要在移動(dòng)窗口后,更新最小、最大和關(guān)閉按鈕的位置; 模擬按鈕按下的動(dòng)作;點(diǎn)擊Icon后生成System Menu,并彈出,代價(jià)是大了一些。
有了這種方法后,就完全沒(méi)有必要非要和Windows對(duì)著干了,你可以設(shè)計(jì)自己的 Title Bar、自己的最小、最大和關(guān)閉按鈕,在Title Bar上貼上喜歡的位圖,使 Title Bar完全個(gè)性化。現(xiàn)在握住你的筆(pen),拿起你的刷(brush),盡情地裝飾你 的Title Bar吧!
|