摘要:本文介紹了在對話方塊程式基礎上通過程式控制來動態添加工具條和狀態條的實現過程和方法。
一、 引言
對於不需要文檔/視圖結構支援的程式一般都採用對話方塊做為程式的基礎架構。雖然在對話方塊程式上可以通過修改其屬性來添加系統功能表,但對比SDI和MDI程式的工具條和狀態列未免使介面顯得簡單、單調。雖然在Visual Basic 中提供有獨立的工具條和狀態列標準控制項可以直接在對話方塊上使用,但Visual C++ 6.0所提供的26種基本Windows標準控制項卻沒有將它們包含其中。因此要在對話方塊程式中實現工具條和狀態列只能通過編程來動態實現。
二、 工具條的實現過程
MFC對於工具條和狀態列分別提供了CToolBar和CStatusBar兩個基本類庫,但由於在實現時MFC對其做了過多的封裝,以至無法瞭解內部的一些核心技術。因此本文在實現過程中放棄了相對比較方便的CToolBar和CStatusBar類的使用,而是通過SDK(Software Developers Kit,軟體開發工具箱)式的WinAPI應用程式介面來實現的。在API函數中經常需要用到對話方塊的視窗控制代碼和當前的執行個體控制代碼,在SDK程式設計中以上兩個控制代碼可以直接從入口函數WinMain()中引出,而在MFC下也對其做了封裝,不能直接擷取。但MFC也為其留有介面:CWnd視窗類別提供的GetSafeHwnd()可以返回對話方塊的視窗控制代碼;函數AfxGetInstanceHandle()則可以擷取當前應用程式的執行個體控制代碼。由於對話方塊和狀態列屬於程式介面的一部分,需要程式啟動時就顯示出來,因此擷取控制代碼的代碼和後面建立顯示工具條、狀態列的全部代碼都應當放在對話方塊初始化訊息WM_INITDIALOG的響應函數OnInitDialog()中進行:
HWND hDlg=GetSafeHwnd();
HINSTANCE hInstance=AfxGetInstanceHandle();
對於待添加的工具條按鈕可以根據情況細分為兩種:
一種是Windows標準的一些工具條按鈕比如開啟檔案、預覽列印、線上協助等等,這類工具條按鈕可以直接使用預定義好的按鈕表徵圖的ID號,在VC內建的CommCtrl.h標頭檔中有詳細定義;
另一種就是使用者自己添加的工具列按鈕,只能由使用者在資源檢視中為其指定相應的表徵圖。不論是那種工具條按鈕的建立都是通過對TBBUTTON結構的設定來決定每一個工具條按鈕的狀態,對於第一個填充好的工具條按鈕可以用CreateToolbarEx()來直接將其加入到工具條上,並返回指向工具條的視窗控制代碼,而對於以後工具條按鈕的添加則只能通過向工具條發送TB_ADDBUTTONS訊息來實現:
……
//填充工具條按鈕結構:
TBBUTTON ptoolbar[30]={{STD_HELP, //指定Windows的標準協助表徵圖
MU_ONE, //工具條按鈕的ID
TBSTATE_ENABLED, //可用狀態
TBSTYLE_BUTTON, //指定建立一個可以下按的按鈕
0, //保留,由應用程式定義該參數意義
0}, //按鈕字串索引
//建立一個分割按鈕用的豎線
{0,0,TBSTATE_ENABLED,TBSTYLE_SEP,0,0}};
//在對話方塊上動態建立工具條,並添加工具條按鈕:
HWND hToolsWindow=::CreateToolbarEx(hDlg, //指定對話方塊為父視窗,將工具條建立在對話方塊上
WS_CHILD|WS_VISIBLE|TBSTYLE_WRAPABLE|TBSTYLE_TOOLTIPS|
TBSTYLE_FLAT|CCS_ADJUSTABLE,//指定工具條的建立風格
IDB_TOOLBAR,//預定義的工具條資源ID
30,HINST_COMMCTRL, //包含圖片資源的可執行檔的執行個體控制代碼
IDB_STD_SMALL_COLOR,//圖片的資源ID
ptoolbar, //待添加的按鈕
2, //加入到工具條的按鈕的個數
0,0,0,0,sizeof(TBBUTTON));
……
//從IDR_TOOLBAR1資源中裝載按鈕表徵圖到對話方塊的工具條上
TBADDBITMAP tab;
tab.hInst=hInstance;
tab.nID=IDR_TOOLBAR1;
iBmp=::SendMessage(hToolsWindow,TB_ADDBITMAP,(WPARAM)3,(LPARAM)&tab);
向工具條添加工具條按鈕的關鍵在於對TBBUTTON資料結構的填充,該資料結構也是在CommCtrl.h標頭檔中定義的,原形為:
typedef struct _TBBUTTON {
int iBitmap;
int idCommand;
BYTE fsState;
BYTE fsStyle;
DWORD dwData;
int iString;
} TBBUTTON, NEAR* PTBBUTTON, FAR* LPTBBUTTON;
該結構的資料成員包含了處在工具條裡的按鈕的相關資訊:成員iBitmap是從0開始記數的按鈕圖象的索引;idCommand標識了匹配的按鈕,當按鈕被按下產生WM_COMMAND訊息的時候會用到該標識;fsState指定了按鈕的狀態標誌,可以是以下8種標誌的邏輯組合TBSTATE_CHECKED、TBSTATE_ELLIPSES、TBSTATE_ENABLED、TBSTATE_HIDDEN、TBSTATE_INDETERMINATE、TBSTATE_MARKED、TBSTATE_PRESSED、TBSTATE_WRAP。至於以上各標誌的具體含義在MSDN的線上協助中有詳細說明;fsStyle成員指定了按鈕的風格;dwData是應用程式定義的值,通常為0;iString為從0開始技術的按鈕字串的索引。下面這段代碼用於向工具條添加自訂的工具條按鈕:
TBBUTTON tb;
tb.iBitmap=iBmp+0;
tb.idCommand=MU_TWO;
tb.fsState=TBSTATE_ENABLED;
tb.fsStyle=TBSTYLE_BUTTON;
tb.dwData=0;
tb.iString=0;
完成對TBBUTTON結構的設定後可以通過視窗控制代碼hToolsWindow向工具條發送TB_ADDBUTTONS訊息來添加按鈕到工具條,如想添加按鈕之間的分割條,只需將TBBUTTON結構的fsStyle成員變數取值為TBSTYLE_SEP即可:
::SendMessage(hToolsWindow,TB_ADDBUTTONS,(WPARAM)1,(LPARAM)&tb);
三、 狀態列的實現
狀態列的實現與工具條的實現相比非常簡單,只需在CreateStatusWindow()函數中對其參數進行設定即可實現:
HWND hStatusWindow=CreateStatusWindow(WS_CHILD|WS_VISIBLE|WS_BORDER,
TEXT("狀態列"),//顯示在狀態列上的資訊
hDlg, //父視窗控制代碼
IDS_STATUS); //預定義的資源ID
此時建立的狀態列只是一個位於對話方塊底部的長條,如需要將其分割為幾部分可以在數組中設定好分割點的X座標,然後通過向狀態列發送SB_SETPARTS訊息即可,該訊息的wParam參數指定了要將狀態列分割為幾部分,lParam參數指定了各分割點的座標值:
int pint[4]={110,250,300,-1};//110,250,300設定間隔
::SendMessage(hStatusWindow,SB_SETPARTS,4,(LPARAM)pint);
如需向分割後的狀態列內填寫資訊,可以通過hStatusWindow向狀態條發送訊息SB_SETTEXT來完成,該訊息的兩個參數分別用來標識在第幾個窗格顯示和待顯示的資訊內容:
::SendMessage(hStatusWindow,SB_SETTEXT,1,(LPARAM)TEXT("資訊一"));
……
小結:本文以SDK的方式實現了在MFC對話方塊程式下工具條和狀態列的動態添加,使普通的對話方塊程式也可以象SDI和MDI程式一樣擁有自訂風格的工具條和狀態列。全部實現過程的重點是在對相關結構的設定和訊息的發送以及控制項的動態建立。至於本文所涉及到的結構和函數的詳細內容請參閱Microsoft 的MSDN Library 6.0。本文所述程式在Windows 98下,由Microsoft Visual C++ 6.0編譯通過。