MFC進度條編程控制

1. 進度條的主要功能
 進度條控制(Progress Control)主要用來進行數據讀寫、文件拷貝和磁盤格式等操作時的工作進度提示情況,如安裝程序等,伴隨工作進度的進展,進度條的矩形區域從左到右利用當前活動窗口標題條的顏色來不斷填充。
 進度條控制在MFC類庫中的封裝類爲CProgressCtrl,通常僅作爲輸出類控制,所以其操作主要是設置進度條的範圍和當前位置,並不斷地更新當前位置。進度條的範圍用來表示整個操作過程的時間長度,當前位置表示完成情況的當前時刻。SetRange()函數用來設置範圍,初始範圍爲0-100, SetPos()函數用來設置當前位置,初始值爲0,SetStep()函數用來設置步長,初始步長爲10,StepIt()函數用來按照當前步長更新位置,OffsetPos()函數用來直接將當前位置移動一段距離。如果範圍或位置發生變化,那麼進度條將自動重繪進度區域來及時反映當前工作的進展情況。
 進度條的對象結構
 進度條控制的建立方法
 CProgressCtrl &ProgressCtrl 建立進度條控制對象結構
 Create 建立進度條控制對象並綁定對象
 進度條控制類CprogressCtrl::Create的調用格式如下:
 BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
 其中參數dwStyle用來確定進度條控制的控制風格;參數rect用來確定進度條控制的大小和位置;參數pParentWnd用來確定進度條父窗口指針;參數nID用來確定進度條控制的控制符ID值。
 2 進度條控制的類屬性
 進度條控制的類屬性包括設置進度條最大最小控制範圍SetRange、設置進度條當前位置 SetPos、設置進度條當前位置偏移值OffsetPos和設置進度條控制增量值SetStep。
 3 進度條控制的操作方法
 進度條控制的操作方法主要是使進度條控制並重繪進度條的StepIt函數。
 進度條控制的應用技巧示例
 1、利用應用程序嚮導AppWizard生成基於對象框的應用程序CProgDlg;
 2、在對話框中設置進度條和靜態文本控制,其ID分別爲IDC_PROG和IDC_PERCENT;
 在對話框初始代碼中增加控制的範圍和位置:
 在ProgDlg.h中設置兩個數據成員,用來表示進度條的最大值和步長:
 //ProgDlg.h
 class CProgDlg:public Cdialog
 { ......//其它代碼
 public:
 int m_nMax,m_nStep;
 ...... //其它代碼
 }
 (2)在ProgDlg.cpp中設置初始狀態
 BOOL CProgDlg::OnInitDialog()
 { 
 Cdialog::OnInitDialog();
 ......//其它代碼
 //TODO:Add extra initialization here
 CProgressCtrl *pProgCtrl=(CProgressCtrl*)GetDlgItem(IDC_PROG);
 pProgCtrl->SetRange(0,200);//設置進度條範圍
 ......//其它代碼
 m_nMax=200;
 m_nStep=10;
 SetTimer(1,1000,NULL);//設置進度條更新時鐘
 return TRUE;
 }
 (3)完善WM_TIMER消息處理,使進度條按照當前步長進行更新,同時完成進度條的百分比顯示:
 void CProgDlg::OnTimer(UINT nIDEvent)
 { //TODO:Add your message handler
 CProgressCtrl *pProgCtrl=(CProgressCtrl*)GetDlgItem(IDC_PROG);
 int nPrePos=pProgCtrl->StepIt();//取得更新前位置
 char test[10];
 int nPercent=(int)(((nPrePos+m_nStep)/m_nMax*100+0.5);//可修改
 wsprintf(test,"%d",nPercent);
 GetDlgItem(IDC_PERCENT)->SetWindowText(test);
 Cdialog::OnTimer(nIDEvent);
 
}
 



---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
vc 進度條控件(一)
 方法1:
 單線程方式。
 將你的任務分成多個部分,每運行一部分,就更新一下進度條。
 這種方法就是很煩人。
 

方法2:
 雙線程方式。
 主線程負責完成你想要的工作。副線程負責更新進度條。
 更新進度條可以按照計時方法,或者根據主線程完成任務的狀態來更新。
 因此,你的主線程在完成任務時,還得用一個臨界區隨時報告任務的完成狀態。
 

方法3:
 雙線程方式
 主線程負責更新進度條,並且創建副線程完成任務的某部分工作。但這和單線程很像。
 

在VC程序的狀態欄中實現進度條
 

  讀者朋友們可能天天使用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)函數,用來處理讀取文件時的進度條仿真;
 

6、 添加代碼,編譯運行程序。
 

三、程序代碼
 

////////////////////////////////////////////CprogStatusBar類的頭文件;
 // Status bar with progress control.
 class CProgStatusBar : public CStatusBar {
 public:
 CProgStatusBar();
 virtual ~CProgStatusBar();
 CProgressCtrl& GetProgressCtrl() {
 return m_wndProgBar;
 }
 void OnProgress(UINT pct);
 protected:
 CProgressCtrl m_wndProgBar; // the progress bar
 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
 afx_msg void OnSize(UINT nType, int cx, int cy);
 DECLARE_MESSAGE_MAP()
 DECLARE_DYNAMIC(CProgStatusBar)
 };
 ///////////////////////////////////////////////////////////////////////////// CprogStatusBar類的實現文件;
 #include "StdAfx.h"
 #include "ProgBar.h"
 #ifdef _DEBUG
 #define new DEBUG_NEW
 #undef THIS_FILE
 static char THIS_FILE[] = __FILE__;
 #endif
 IMPLEMENT_DYNAMIC(CProgStatusBar, CStatusBar)
 BEGIN_MESSAGE_MAP(CProgStatusBar, CStatusBar)
 ON_WM_CREATE()
 ON_WM_SIZE()
 END_MESSAGE_MAP()
 ////////////////////////////////////////////////////////////////
 CProgStatusBar::CProgStatusBar()
 {} 
 CProgStatusBar::~CProgStatusBar()
 {}
 ////////////////////////////////////////創建狀態條時也創建進程條
 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;
 }
 ////////////////////////////////////////////////////使進程度條的尺寸與狀態條的尺寸同步變化;
 void CProgStatusBar::OnSize(UINT nType, int cx, int cy)
 {
 CStatusBar::OnSize(nType, cx, cy); 
 CRect rc; 
 GetItemRect(0, &rc); 
 m_wndProgBar.MoveWindow(&rc,FALSE);
 }
 ////////////////////////////////////////////////////////////根據pct的當前值對進程條進行設置
 void CProgStatusBar::OnProgress(UINT pct)
 {
 CProgressCtrl& pc = m_wndProgBar;
 DWORD dwOldStyle = pc.GetStyle();
 DWORD dwNewStyle = dwOldStyle;
 if (pct>0) //如果pct>0,將顯示進度條
 dwNewStyle |= WS_VISIBLE;
 else //否則隱藏進度條;
 dwNewStyle &= ~WS_VISIBLE;
 if (dwNewStyle != dwOldStyle) {
 SetWindowText(NULL); //顯示進度條前清空狀態條;
 SetWindowLong(pc.m_hWnd, GWL_STYLE, dwNewStyle); 
 //設置進度條處於顯示狀態;
 }
 // 設置進度條的當前位置;
 pc.SetPos(pct);
 if (pct==0)
 // 如果pct等於0,通知主框架窗口顯示空閒信息;
 GetParent()->PostMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
 }
 /////////////////////////////////////////////////////////////////////////文檔裝載處理函數;
 void CPrgsbarDoc::Serialize(CArchive& ar)
 {
 CWnd* pFrame = AfxGetMainWnd();
 if (!ar.IsStoring()) {
 for (int pct=10; pct<=100; pct+=10) {//對文檔裝載進行仿真處理;
 Sleep(150);
 if (pFrame)
 pFrame->SendMessage(MYWM_PROGRESS, pct);
 }
 }
 if (pFrame)
 pFrame->SendMessage(MYWM_PROGRESS, 0);
 ((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);//顯示文本文件的內容;
 }
 



四、小結
 

本例雖然是介紹的如何在狀態條中包含進度條,但是讀者朋友們可以從中受到啓發,開拓思路,將該思想應用到類似的應用當中去,例如在狀態條中實現顯示圖像等。
 

位圖進度條
 

圖一 例子效果
 

玩過破天的朋友知道,遊戲更新時進度是用位圖表示的,我覺的挺漂亮的,於是自己動手做了一個類來實現那種效果。
 

這個類的名字叫CBmpProgCtrl,繼承於CStatic,使用方法如下。
 1、首先要將BmpProgCtrl.h和BmpProgCtrl.cpp添加到工程中。
 

2、導入兩幅位圖,作爲前景和背景。資源標識分別爲IDB_FORE和IDB_BACK.
 

3、在對話框上,放置一個"Static Text"控件,修改其ID,只要不是默認的IDC_STATIC就可以了。
 

4、讓這個控件和一個Control類型的變量關聯,如變量名可以叫m_bmpprog。
 

5、找到該變量定義的地方,應該是CStatic m_bmpprog,修改CStatic爲CBmpProgCtrl。並將頭文件BmpProgCtrl.h包含進來。
 

6、調用該類的方法。
 

類成員方法介紹:
 

void GetRange(int &lower,int &upper)返回進度條範圍。
 int GetPos()獲得當前位置
 int StepIt( )以當前步長使進度條增長
 int SetStep( int nStep )設置步長
 int SetPos( int nPos )設置位置
 void SetRange( int nLower, int nUpper )設置進度條範圍。
 

具體的可以看源代碼。你可以修改它以符合自己的需要。你可能覺的這些方法很熟悉,是的,我參考了CProgressCtrl的方法名。
 

結束語
 

這個東西,比較簡單,你可以很容易就使用。
 

一條語句改變進度條顏色及去掉進度條邊框  
 

      改變進度條顏色
 

在VC裏想改變進度條顏色,在網上找了很多方法,都很麻煩,覺得很鬱悶。後來想起在用VB做時,增經用API實現過,很簡單。後來再一查,原來是SendMessage這個函數,幾經試驗,終於成功,高興,與大家分享!!!!
        代碼如下:    
       m_Progress1.SendMessage(PBM_SETBKCOLOR, 0, RGB(0, 0, 255));//背景色爲藍色
 m_Progress1.SendMessage(PBM_SETBARCOLOR, 0, RGB(255, 0, 0));//前景色爲紅色
        至於別的控件能不能按這種辦法來改變顏色,我還沒試過,大家可以試一試,如果可以,請留言告訴我,先謝謝了 。
 以下摘自《新編win32API大全》:
 函數功能:該函數將指定的消息發送到一個或多個窗口。此函數爲指定的窗口調用窗口程序,直到窗口程序處理完消息再返回。而函數PostMessage不同,將一個消息寄送到一個線程的消息隊列後立即返回。
 

     函數原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
 

     參數:
 

     hWnd:其窗口程序將接收消息的窗口的句柄。如果此參數爲HWND_BROADCAST,則消息將被髮送到系統中所有頂層窗口,包括無效或不可見的非自身擁有的窗口、被覆蓋的窗口和彈出式窗口,但消息不被髮送到子窗口。
 

     Msg:指定被髮送的消息。
 

     wParam:指定附加的消息指定信息。
 

     IParam:指定附加的消息指定信息。
 

     返回值:返回值指定消息處理的結果,依賴於所發送的消息。
 

     備註:需要用HWND_BROADCAST通信的應用程序應當使用函數RegisterWindowMessage來爲應用程序間的通信取得一個唯一的消息。
 

     如果指定的窗口是由調用線程創建的,則窗口程序立即作爲子程序調用。如果指定的窗口是由不同線程創建的,則系統切換到該線程並調用恰當的窗口程序。線程間的消息只有在線程執行消息檢索代碼時才被處理。發送線程被阻塞直到接收線程處理完消息爲止。
 

     Windows CE:Windows CE不支持Windows桌面平臺支持的所有消息。使用SendMesssge之前,要檢查發送的消息是否被支持。
 

     速 查:Windows NT:3.1及以上版本:Windows:95及以上版本;Windows CE:1.0及以上版本;頭文件:winuser.h;輸入庫:user32.lib;Unicode:在Windows NT環境下以Unicode和ANSI方式實現。
 以下摘自MSDN:
 RGB(red, green, blue)
 Arguments
 red
 Required. Number in the range 0-255 representing the red component of the color.
 green
 Required. Number in the range 0-255 representing the green component of the color.
 blue
 Required. Number in the range 0-255 representing the blue component of the color.
 二、         去掉進度條邊框
 m_Progress1.ModifyStyleEx(WS_EX_STATICEDGE,0);
 m_Progress.Invalidate(false);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章