讀者朋友們可能天天使用Visual C++這個強大的工具來開發應用程序,不知道注意到沒有,Visual C++每次裝載一個項目的時候,為了使項目加載過程不至於太單調,會在狀態欄的左半部分會出現一個裝載進度條,用來即時顯示Visual C++裝載項目的進度,當項目裝載完畢後,進度條隱藏。那麼這個功能是如何實現的呢?為了說明該功能的實現原理,本例提供了一個范例程序prgsbar,它演示了在編輯視圖裡顯示文本文件,在加載文本文件時,在界面的狀態條中的進度指示器仿真顯示文件的加載過程,當文本裝載完畢後,進度條隱藏。由於該程序在裝載文件顯示的進度條時無法進行拷屏操作,所以這裡沒有給出狀態條中顯示進度條的界面效果圖,讀者可以運行本書所帶光盤中的程序代碼觀看相應的效果。
一、實現方法
雖然Visual C++中的MFC類提供了標准的進度指示器控件(progress control),但是我們不能在狀態欄裡直接使用這個控件,要解決這個問題,可以創建一個可重用C++類CProgStatusBar,這個類從CStatusBar派生,用來來實現狀態條中的進度指示。整個實現過程不是很難,思路是在狀態欄創建一個進度指示器控制,把它作為子窗口來對待,然後根據不同的狀態來顯示或者隱藏進度指示器。
在具體實現CProgStatusBar類的過程中,首先在CProgStatusBar派生類中加了一個CProgressCtrl類型的數據成員--m_wndProgBar,然後重載CstatusBar類的二個重要成員函數:OnCreate()、OnSize(),最後還要在該類中添加一個自定義成員函數OnProgress()。在上述三個函數中, OnCreate()負責在狀態欄第一次被創建時接收控制,繼而創建進度指示器並將它初始化為一個子窗口,它的實現代碼如下:
int CProgStatusBar::OnCreate(LPCREATESTRUCT lpcs)
{
lpcs->style |= WS_CLIPCHILDREN;
VERIFY(CStatusBar::OnCreate(lpcs)==0);
VERIFY(m_wndProgBar.Create(WS_CHILD, CRect(), this, 1));
m_wndProgBar.SetRange(0,100);
return 0;
}
OnCreate()函數在狀態欄的式樣中加了一個WS_CLIPCHILDREN,它告訴Windows不要繪制子窗口以下的狀態欄區域,這樣可以減少屏幕閃爍。接著OnCreate()函數創建進度指示器控件並將它的范圍設置成[0,100]。注意在這裡創建進度指示器控件時沒有用WS_VISIBLE,因為我們要實現的目標是僅僅當裝載文件時進度條才顯現,其余時間內應用程序都隱藏它。
熟悉Windows編程的人都清楚,無論何時,只要在某個窗口裡添加子窗口,那麼一定要負責管理它的大小尺寸,也就是說,當父窗口大小改變後,子窗口的大小也要跟著作相應的改變。一般來說,這個工作由父窗口的WM_SIZE消息處理函數OnSize()來作,所以我們也要處理該類的OnSize()函數。
void CProgStatusBar::OnSize(...)
{
CStatusBar::OnSize(...);
CRect rc;
GetItemRect(0, &rc);//獲取狀態條的第一個窗口的尺寸;
m_wndProgBar.MoveWindow(&rc,FALSE);//移動進度條到狀態條的第一個窗口;
}
從上述代碼可以看出,CProgStatusBar::OnSize()將進度指示器放在了狀態欄的第一個窗格,這個窗格通常用來顯示程序的"就緒"信息和命令提示信息。注意這裡不論進度指示器是處於可見狀態還是隱藏狀態,MoveWindow都照樣起作用--所以即便是進度指示器處於隱藏狀態,其窗口大小同樣是可調的。
調整好進度指示器的窗口大小後,下面要作的就是進度指示器的顯示,進度指示器當前進度狀態的顯示在CProgStatusBar::OnProgress中完成。它有一個類型為UINT的入口參數:參數值的范圍從0到100,表示進度百分比,0表示進度沒開始,100表示全部完成。如果這個參數的值大於0,則OnProgress顯示進度控制並設置指示器的位置;如果參數值等於0,則 OnProgress隱藏進度控制。
雖然子窗口控件通常都是放在父窗口能繪制的區域的最上面,但這樣做在繪制方面是有一定風險的。在隱藏/顯示進度控制時尤其如此,這時候會出現兩個問題:第一,因為進度指示器顯示在狀態欄的第一個窗格位置,所以如果進度條指示器顯示時已經顯示有狀態信息,那麼進度指示器和狀態信息文本就會有沖突,相互干擾。之所以會這樣,是因為進度控制假設其繪制背景是干淨的,並且只繪制進度控制的著色部分。解決這個問題最簡單的方法是調用CStatusBar::SetWindowText(NULL)函數在顯示進度指示器之前打掃一下環境衛生,清除以前的文本。
對於狀態欄來說,SetWindowText函數的作用是設置狀態欄第一個窗格的文本。反之,當調用OnProgress(0)清除進度控制時也存在類似的問題,CProgStatusBar::OnProgress 隱藏進度控制後,狀態欄第一個窗格該顯示什麼信息呢?一般顯示"就緒"或其它的提示信息。當應用程序不做任何事情時,MFC程序總是在這個位置顯示資源串AFX_IDS_IDLEMESSAGE表示的文本,其缺省值為"就緒",當然讀者朋友們可以在當前項目的RC文件中任意修改這個值,不管怎樣,在MFC程序的狀態欄中顯示"就緒"信息很容易,需要作的就是在CProgStatusBar::OnProgress()函數中調用語句GetParent()->PostMessage(WM_SETMESSAGESTRING,AFX_IDS_IDLEMESSAGE)向父窗口發送一個WM_SETMESSAGESTRING消息就可以了,需要注意的是,使用消息WM_SETMESSAGESTRING時必須包含它的定義文件"afxpriv.h",否則程序會報告編譯錯誤。
上述CprogStatusBar類實現了狀態欄中包含進度條控件,該類的使用方法很簡單,首先在應用程序的CmainFrame類中用CProgStatusBar代替CStatusBar聲明實例,然後在任何想要顯示進度控制指示的地方調用CProgStatusBar::OnProgress。本例中定義了一個消息MYWM_PROGRESS,它將進度條當前的進度作為WPARAM參數傳遞到CProgStatusBar::OnProgress()函數。
經過上述處理,想要使用進度指示的任何對象都可以通過發送一個消息到主框架來調用狀態欄進行進度條的顯示。例如,在例子程序中,文檔的Serialize()函數在加載文本文件時,利用Sleep()函數仿真耗時加載,每隔150毫秒報告一次進度狀態。如果你不想從文檔發送Windows消息,可以用MFC的視圖更新機制來做。你可以發明一個"暗示"代碼以及一個小結構來保存進度百分比數據,並通過向框架發送MYWM_PROGRESS消息調用暗示信息。這是從文檔到視圖/框架傳遞進度控制信息的最省事的方式。
二、編程步驟
1、 啟動Visual C++6.0,生成一個單文檔應用程序prgsbar,項目的視圖類的基類選擇CEdit類;
2、 在程序的Resource.h文件中添加自定義消息的定義:
#define MYWM_PROGRESS (WM_USER+1)
3、 在程序的主框架窗口CMainFrame類的頭文件中聲明MYWM_PROGRESS的消息響應函數afx_msg LRESULT OnProgress(WPARAM wp, LPARAM lp),在該類的實現中添加消息映射ON_MESSAGE(MYWM_PROGRESS,OnProgress);
4、 將CMainFrame類中的工具條對象改為CProgStatusBar m_wndStatusBar;
5、 重載CPrgsbarDoc::Serialize(CArchive& ar)函數,
[1] [2] 下一頁