CToolBar的使用介紹

轉載地址:http://blog.csdn.net/daijunhua/article/details/2393611


                                                                    <1>

CToolBar控件是MFC提供的一個類,實現了一般窗口應用中的工具條。通常用於SDI或者MDI程序中,對話框程序中通常不使用工具條。

一、代碼中的工具條

工具條是一個CToolBar類對象,通常作爲成員對象嵌入程序的CMainFrame類中,也就是說嵌入主框架窗口中。因此,MFC生成框架窗口的時候同時生成工具條,銷燬框架窗口的時候同時銷燬工具條。下面是一個多文檔 (MDI) 程序的代碼片斷,給出了工具條相關的代碼:

class CMainFrame : public CMDIFrameWnd
{
   // ...
protected:  // control bar embedded members
   CToolBar    m_wndToolBar;

protected:
   //{{AFX_MSG(CMainFrame)
   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()
};


工具條的創建過程發生在CMainFrame::OnCreate階段。MFC在創建框架窗口以後,在顯示窗口之前調用這個OnCreate函數,AppWizard通常在這個函數中做如下的工作:
1、調用CToolBar對象的Create成員函數,來生成內嵌的CToolBarCtrl對象。
2、調用LoadToolBar函數加載工具條資源。
3、調用函數來啓動工具條的停靠、浮動、提示等功能,具體詳見後面“停靠和浮動”的內容。這些調用的代碼是可選的,如果不需要這些功能,可以刪除它們。

二、編輯工具條資源
通過AppWizard生成的工具條是基於MFC4.0中定義的RT_TOOLBAR類型的資源。工具條的按鈕可以用工具條編輯器來修改,諸如添加、刪除、排列按鈕等操作。
要把一個工具條按鈕和一個命令相關聯,必須給按鈕一個命令ID,例如ID_MYCOMMAND,可以在工具條按鈕的屬性頁中添加這個命令,然後用ClassWizard生成命令的響應函數。

三、多個工具條
AppWizard僅僅提供了一個工具條,如果需要多個,則可以根據第一個工具條的代碼創建多個自己的工具條。首先創建工具條資源,然後在框架窗口類中嵌入新的CToolBar對象,最後在OnCreate函數中生成它。

四、工具條按鈕
通常工具條顯示一些代表不同命令的按鈕,工具條的按鈕和菜單項類似,都會產生命令,而且通常情況下工具條按鈕和菜單項的ID相同,兩者的功能相同,用戶可以在使用程序的時候,自願選擇。

五、停靠和浮動
MFC的工具條可以固定停靠在父窗口的一側,或者通過拖拉停靠在父窗口的任何一側,或者以小窗口的形式浮動在父窗口的上面。

1、允許停靠
要在一個框架窗口中停靠工具條,該窗口必須允許停靠,調用CFrameWnd::EnableDocking ,該函數通過一個DWORD參數給出框架窗口的那一側允許停靠。準備好停靠的目標以後,工具條也要做同樣的準備,調用CControlBar::EnableDocking 啓動工具條的停靠功能,給出可以停靠的邊。如果工具條允許停靠的邊和框架窗口允許停靠的邊沒有相同的,工具條就會浮動在框架窗口的上面。因此如果想永久的把工具條做成浮動的,就把參數設置成0,然後調用CFrameWnd::FloatControlBar。

準備好上述工作以後,框架調用CFrameWnd::DockControlBar 開始啓動工具條的停靠。可以在任何時候調用這個函數,但通常是在初始化階段調用。

一個停靠的工具條離開框架窗口的邊以後,就浮動的,也可以直接調用CFrameWnd::FloatControlBar 把工具條設置成浮動的。給出浮動的位置和樣子。當用戶把一個停靠的工具條拖拽離開框架窗口的邊的時候,框架也調用這個函數,和DockControlBar函數一樣,你也可以在初始化階段調用它。
MFC對停靠工具條不提供某些功能的支持,例如自定義工具條。

從Visual C++ 4.0版本之後,開始提供對動態改變工具條尺寸的支持,一般來講,工具條是一個水平的長條形,但是也可以改變它的形狀,例如垂直的長條,或者多行。工具條在生成的時候,有一個屬性:
CBRS_SIZE_DYNAMIC 或者 CBRS_SIZE_FIXED   。如果定義了前者,則工具條在浮動狀態的時候,可以通過拖拽它的邊改變它的形狀。如果定義了後者,則不論工具條是停靠狀態還是浮動狀態,它的形狀是不變的。

可以通過函數CToolBar::GetButtonStyle獲取工具條按鈕的狀態和屬性,屬性決定了按鈕如何響應用戶的單擊,狀態決定了按鈕的換行。比如說對於一個FIXED屬性的工具條,想讓它的按鈕分兩行顯示,從第三個按鈕(包括分割條)開始,可以這麼做:
在框架窗口的OnCreate函數中,生成工具條以後,加入下列代碼:
 //獲取第三個按鈕(或者分割條)的屬性
 UINT nStyle = m_wndToolBar.GetButtonStyle( 3 );
 //將它設置成換行
 nStyle |= TBBS_WRAPPED;
 m_wndToolBar.SetButtonStyle( 3, nStyle );

 // 將工具條屬性設置成 fixed
 m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
       CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_FIXED);


六、工具條提示
MFC的工具條還可以提供提示功能,就是當用戶把鼠標移動在工具條按鈕上面的時候,彈出一個小的窗口,給出描述該按鈕用途的一小段文字。用AppWizard生成的工具條,自動具備這個提示功能。
要在程序中激活提示功能,需要兩個條件:
1、在CToolBar::Create函數中明確給出CBRS_TOOLTIPS 風格,或者用SetBarStyle函數設置這個風格。
2、在資源裏面添加提示字符串,用/n隔開,字符串的ID和該按鈕的相同。或者在編輯工具條按鈕的時候,打開它們的屬性欄,在Properties 一欄輸入提示字符串。如果一個工具條包含子控件,只要控件的ID不是-1,而且字符串資源裏面有對應的字符串,子控件也可以有提示功能。

這裏要說一下 CBRS_FLYBY 屬性,一般來說當工具條的按鈕被按下的時候,狀態條就會顯示關於該按鈕的一個說明文字,如果定義了這個屬性,則當鼠標位於按鈕之上的時候,就會顯示這個提示,不用按下按鈕。

 

七、CToolBar類和CToolBarCtrl類的關係
一般通過CToolBar類管理工具條,從MFC4.0開始,CToolBar類就封裝了Windows提供的工具條控件,完全可以用該類的成員函數操作工具條,或者獲取一個內嵌的CToolBarCtrl對象的引用,調用它的函數。
要訪問CToolBar對象中的內嵌工具條控件,可以調用CToolBar::GetToolBarCtrl函數。返回一個CToolBarCtrl對象的引用。然後可以用這個引用對象調用CToolBarCtrl類的成員函數。

 

                                                              <2>

 

一、首先來看工具條類的派生關係

工具條類的派生關係如下:
//---------------------------
 CObject
          |_____CCmdTarget
                   |______CWnd
                            |____CControlBar
                                    |_____CToolBar
//----------------------------
由於這樣的繼承關係,工具條類具有下列的特點和功能:

(1)從CObject繼承來的功能
   a. 串行化支持
   b. 運行時刻的類信息
   c. 對象診斷輸出
   d. 兼容 collection 類
 
如果在繼承類的實現和聲明中,使用了一些預定義宏,則派生類就可以實現CObject類的許多優點,
包括:
   a.一級宏 DECLARE_DYNAMIC和IMPLEMENT_DYNAMIC。使用該宏,將允許在運行時刻訪問類的名字和它在繼承表中的位置,也就意味着可以用來進行診斷。
   b.二級宏 DECLARE_SERIAL 和 IMPLEMENT_SERIAL。該宏涵蓋了一級宏的所有功能,並允許對象可以通過archive進行串行化。

(2)從CCmdTarget繼承來的功能
CCmdTarget是MFC中所有具備消息循環的類的基類,主要包括CView, CWinApp, CDocument, CWnd, 和CFrameWnd。
除了消息循環,該類還提供了:
   a. 漏斗鼠標
   b. Dispatch映射,用於ole自動化中的IDispatch 函數,爲VB調用提供了接口
(3)從CWnd類繼承的功能
 CWnd類提供可所有MFC庫中窗口類的基本功能,CWnd類與windows下的窗口是有所區別的,但是兩者有緊密的聯繫:CWnd類的構造函數和析構函數生成和銷燬一個CWnd對象,窗口對象是CWnd類的Create函數生成的,在它的虛析構函數中銷燬窗口對象。 DestroyWindow 函數也可以銷燬窗口對象,但是不是CWnd對象。

 CWnd類以及它的消息映射機制隱藏了WndProc函數,所有Windows消息被自動通過消息映射錶轉發到相應的OnMessage成員函數。應該在派生類中重載OnMessage成員函數來處理某個特定的消息。這意味着工具條可以有自己的消息映射表。

 除此以外,CWnd還提供了很多功能,比如繪圖,輸出文字,設置菜單等等,但是某些功能在工具條中不能用,後面將通過剖析其源代碼進行分析。

(4)從CControlBar繼承的功能

 CControlBar 是控制條類的基類,包括 CStatusBar, CToolBar, CDialogBar, CReBar 和COleResizeBar. 一個控制條窗口通常位於一個框架窗口的左側或者右側。它可以包含一些子項,有些是
窗口控件,比如列表框和編輯框,負責產生和響應Windows 消息,有些是非窗口控件,比如狀態條面板和位圖由應用程序和框架負責管理。

 控制條窗口通常是一個框架窗口的子窗口,和客戶區視窗口或者MDI客戶區處於同一個地位。因此控制條
使用父窗口的客戶區矩形信息來定位自己。而且負責把剩餘的未使用的客戶區大小通知父窗口。

二、使用CToolBar類
 
 CToolbar對象具有一行位圖按鈕和可選的分割條,這些按鈕的行爲和下壓按鈕,check-box按鈕和單選按鈕一樣。CToolBar對象通常嵌入 CFrameWnd 或者 CMDIFrameWnd對象裏面。

 CToolBar類的成員函數GetToolBarCtrl允許你使用Windows通用控件支持的特性來設計工具條或者添加額外的功能。CToolBar的成員函數已經提供了Windows通用控件的大多數功能,如果你調用GetToolBarCtrl,會返回一個CToolBarCtrl對象的引用,利用它可以實現 Windows 95工具條的許多特性。

Visual C++ 提供了兩種生成工具條的方法:
要生成一個工具條,應該遵循下面的步驟:
1、生成一個工具條資源
2、構造工具條對象
3、調用 Create (或者 CreateEx) 函數生成一個工具條窗口,並把它關聯到 CToolBar對象。
4、調用 LoadToolBar 函數加載工具條的資源。

或則採用下面的步驟:
1、構造一個工具條對象。
2、調用 Create (或者 CreateEx) 函數生成一個工具條窗口,並把它關聯到 CToolBar對象。
3、調用 LoadBitmap 函數來加載包含工具條按鈕圖片的位圖。
4、調用 SetButtons 函數來設置工具條按鈕的樣式並且把每個按鈕與位圖中的某個圖片相關聯。

一個工具條中的所有圖片都來自於一個位圖,該位圖應該至少爲每個按鈕提供一個圖片,所有的圖片必需是相同的尺寸,缺省定義是 16 象素寬,15 象素高。在位圖中,圖片必需一個挨着一個。

 SetButtons 函數使用一個指向 控制ID的數組指針和一個給出id數目的整數。該函數把工具條每個按鈕的id設置成數組中對應的值,並且爲每個按鈕分配一個圖片。如果數組中包含ID_SEPARATOR的項,則不會給它關聯圖片。

 通常圖片的順序就是他們在屏幕上畫的順序,但是你可以通過函數SetButtonInfo來改變這個順序。

 一個工具條的所有按鈕都是相同的尺寸。缺省定義是 24 x 22 象素,迎合了 Windows 軟件設計接口規範的要求。在圖片和按鈕之外的其它多餘空間是用來生成一個邊框。

 每個按鈕有一個圖片。不同的按鈕狀態和屬性下 (壓下,擡起,禁用,激活,以及中間態)的圖片都從那個圖片產生。雖然圖片可以用任何顏色,但是帶有灰色陰影的黑色圖片效果最好。

 工具條上的按鈕初始狀態都是下壓按鈕。然而,它們可以改成check-box 按鈕或者單選按鈕。Check-box 按鈕具有三個狀態:選中,清除和中間態,單選按鈕只有兩個狀態:選中和清除。

 要設置一個按鈕或者分隔條的屬性,可以通過函數 GetButtonStyle獲得屬性,然後調用 SetButtonStyle進行設置,而不用SetButtons。 SetButtonStyle函數在運行時刻改變按鈕的屬性十分好用。

 要在按鈕上顯示文字,可以通過函數 GetButtonText獲取文字,調用 SetButtonText設置文字。

  要生成一個 check-box 按鈕,只需加上 TBBS_CHECKBOX屬性,或者在 ON_UPDATE_COMMAND_UI 處理函數中使用CCmdUI對象的SetCheck函數設置。只要調用SetCheck函數就會自動把下壓按鈕改變成爲check-box按鈕。

 要生成一個單選按鈕,可以在ON_UPDATE_COMMAND_UI處理函數中,調用CCmdUI對象的SetRadio函數。爲了提供一組單選按鈕的排它功能,你必須爲該組的所有按鈕都生成ON_UPDATE_COMMAND_UI處理函數。

三、關於通用控制條的認識(來自技術備忘錄31:控制條)

本文所論及的內容包括MFC中的控制條類:
 CControlBar, CStatusBar, CToolBar, CDialogBar, 和 CDockBar.
(一)CControlBar

 ControlBar 派生自 CWnd,通常定位於框架窗口的頂端或者底部。它可以包含窗口類的子項,比如 CDialogBar,或者非窗口類的子項,比如CToolBar和 CStatusBar。

 控制條支持的樣式包括:

 CBRS_TOP   (缺省的)位於頂部
 CBRS_BOTTOM  放置在底部
 CBRS_NOALIGN 在父窗口尺寸變化的時候,不要重新定位控制條

 從 CControlBar派生的類提供了更加有趣的功能:

 (a) 狀態條CStatusBar ,它的子項是包含文字的面板
 (b) 工具條CToolBar ,對於工具條來說,子項是排列成一行的位圖按鈕
 (c)  對話框條CDialogBar 象一個框架一樣的工具條,包括標準windows控件 (從一個對話框模板資源生成)
 (d)  CDockBar,可以認爲它是爲其它控制條類提供對接區域的一個區域。該類的成員函數和變量在將來可能還要變化。

  記住:所有的控制條對象必需是某個框架窗口的子窗口。通常它們被作爲框架客戶區(例如,一個MDI客戶區或者一個視窗口)的同級窗口。對於一個控制條來說,它的子窗口ID是非常重要的。僅僅當它的ID的值位於AFX_IDW_CONTROLBAR_FIRST和AFX_IDW_CONTROLBAR_LAST之間時,控制條的缺省佈局才能起作用。

#define AFX_IDW_CONTROLBAR_FIRST        0xE800
#define AFX_IDW_CONTROLBAR_LAST         0xE8FF

注意,雖然一共有256個控制條ID,前面的32個是做特殊用途的,它們直接被打印預覽結構支持。

 CControlBar類提供了
 A.在框架窗口裏面定位工具條的標準實現。
 B.分配控制條項隊列
 C.支持派生類的實現

 C++ 控制條對象通常作爲成員嵌入一個CFrameWnd派生類對象中。而且當父窗口銷燬的時候,它也被清除。如果你想在堆中分配一個控制條對象,你可以將它的 m_bAutoDestruct成員設置成 TRUE,從而當HWND銷燬的時候允許它 “delete this”。

 重要提示:如果你派生了自己的控制條對象,則必須重載Create函數,在其中設置 m_dwStyle數據成員,例如:

// CMyControlBar is derived from CControlBar
BOOL CMyControlBar::Create( CWnd* pParentWnd, DWORD dwStyle, UINT nID )
{
   m_dwStyle = dwStyle;

   .
   .
   .
}

(二)控制條的佈局原理

 控制條的佈局原理非常簡單,框架窗口按照 Z-順序發送消息 WM_SIZEPARENT給所有控制條子窗口,並跟隨這個消息傳遞一個父窗口客戶區矩形的指針。控制條使用這個矩形信息來定位自己,並且把父窗口的客戶區尺寸減小,剩下的是正常的客戶區域,用於定位主要的客戶區窗口,通常是一個MDI客戶區,視或者拆分窗口。

 詳細情況可以參考 CWnd::RepositionBars 和 CFrameWnd::RecalcLayout 兩個函數。

 MFC 私有窗口消息,包括WM_SIZEPARENT,都在技術備忘錄24中說明。


(三)工具條

工具條支持兩種按鈕: 下壓按鈕和check box按鈕。通過使用check box按鈕組加上適當的ON_UPDATE_COMMAND_UI處理,可以得到單選按鈕組的功能。

工具條中的所有按鈕的圖片都取自同一個位圖。每個按鈕尺寸相同(缺省尺寸是24x22象素大小),每個按鈕的圖片尺寸相同而且相連, 圖片的缺省大小是16x15象素,所以如果一個工具條具有10個按鈕,則需要位圖的尺寸是160象素寬,15 象素高。

工具條按鈕的所有狀態的圖片都是通過一定的算法從那一個圖片中轉換得到。因此,雖然理論上按鈕圖片可以使用任何顏色,但是對於這個算法來說,如果原始圖片使用灰色陰影效果比較好。

項              Windows 顏色           缺省RGB值
工具條背景      COLOR_BTNFACE          RGB(192, 192, 192)
工具條左/上邊框 COLOR_BTNHIGHLIGHT     RGB(255, 255, 255)
工具條右/下邊框 COLOR_BTNSHADOW        RGB(128, 128, 128)

對工具條的 CCmdUI 支持:

工具條按鈕的更新是通過空閒時刻調用 ON_UPDATE_COMMAND_UI 完成的。通過這個函數可以:

1、允許/禁止工具條按鈕。
2、設置按鈕爲check狀態。注意調用SetCheck函數會把按鈕變成check box 按鈕。
3、SetRadio: 設置類似單選按鈕的功能。

工具條按鈕會象正常的按鈕一樣發送WM_COMMAND消息,通常被一個ON_COMMAND函數處理。

工具條按鈕一共有四種樣式(代表四種狀態):
TBBS_CHECKED
TBBS_INDETERMINATE
TBBS_DISABLED
TBBS_PRESSED

正式的按鈕狀態定義是六種,它們是:

Up = 0
Mouse Down = TBBS_PRESSED (| any other style)
Disabled = TBBS_DISABLED
Down = TBBS_CHECKED
Down Disabled = TBBS_CHECKED | TBBS_DISABLED
Indeterminate = TBBS_INDETERMINATE

 

                                                                    <3>

 

下面將通過研究工具條的源代碼探討幾個問題。
1、工具條類的數據
CToolBar類有下列數據成員,均爲保護成員。並在構造函數中設置它們的缺省值如下:
 CMapStringToPtr* m_pStringMap = NULL;  // used as CMapStringToUInt
 HRSRC m_hRsrcImageWell = NULL;  // 用於加載資源圖片
 HINSTANCE m_hInstImageWell= NULL;  // 加載圖片的進程句柄
 HBITMAP m_hbmImageWell = NULL;  // 保存已經加載的工具條位圖
 BOOL m_bDelayedButtonLayout = TRUE;  // 用於控制工具條按鈕佈局
//
// 注:
//
// 在工具條析構的時候會自動銷燬 m_hbmImageWell和 m_pStringMap兩個對象。
//

 CSize m_sizeImage;  //按鈕圖片的缺省大小
 m_sizeImage.cx = 16;
 m_sizeImage.cy = 15;

 CSize m_sizeButton; //按鈕的缺省尺寸
 m_sizeButton.cx = 23;
 m_sizeButton.cy = 22;

//下面的數據定義位於CControlBar類中,是public,可以改變它們的值,獲得邊界尺寸怪異的工具條
//方法是:從CToolBar 派生一個新的工具條類,然後在構造函數裏面改變這幾個數據的值。
//
// int m_cxLeftBorder, m_cxRightBorder;
// int m_cyTopBorder, m_cyBottomBorder;
//
//這裏僅改變兩個值 ,爲了更易於加把手
 m_cyTopBorder = 3;
 m_cyBottomBorder = 3;
}

2、 關於Create和CreateEx

工具條的缺省構造函數是CToolBar(),因此聲明一個對象以後要生成它。這兩種生成方式有什麼不同呢?

看它們的定義:

BOOL Create(CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP, UINT nID = AFX_IDW_TOOLBAR);
BOOL CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle = TBSTYLE_FLAT,
 DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP, CRect rcBorders = CRect(0, 0, 0, 0),
 UINT nID = AFX_IDW_TOOLBAR);

實際上 Create函數最終也是調用CreateEx:

BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
{
 return CreateEx(pParentWnd, 0, dwStyle,
  CRect(m_cxLeftBorder, m_cyTopBorder, m_cxRightBorder, m_cyBottomBorder), nID);
}

因此,我們看到如果用Create函數生成工具條,僅僅是風格稍有不同,後者採用了平滑按鈕,不畫底邊。:

#define TBSTYLE_BUTTON          0x0000
#define TBSTYLE_FLAT            0x0800

#define CBRS_TOP            (CBRS_ALIGN_TOP|CBRS_BORDER_BOTTOM)

類似的按鈕樣式還包括:

#define TBSTYLE_BUTTON          0x0000
#define TBSTYLE_SEP             0x0001
#define TBSTYLE_CHECK           0x0002
#define TBSTYLE_GROUP           0x0004
#define TBSTYLE_CHECKGROUP      (TBSTYLE_GROUP | TBSTYLE_CHECK)
#if (_WIN32_IE >= 0x0300)
#define TBSTYLE_DROPDOWN        0x0008
#endif
#if (_WIN32_IE >= 0x0400)
#define TBSTYLE_AUTOSIZE        0x0010 // automatically calculate the cx of the button
#define TBSTYLE_NOPREFIX        0x0020 // if this button should not have accel prefix
#endif

#define TBSTYLE_TOOLTIPS        0x0100
#define TBSTYLE_WRAPABLE        0x0200
#define TBSTYLE_ALTDRAG         0x0400
#if (_WIN32_IE >= 0x0300)
#define TBSTYLE_FLAT            0x0800
#define TBSTYLE_LIST            0x1000
#define TBSTYLE_CUSTOMERASE     0x2000
#endif
#if (_WIN32_IE >= 0x0400)
#define TBSTYLE_REGISTERDROP    0x4000
#define TBSTYLE_TRANSPARENT     0x8000
#define TBSTYLE_EX_DRAWDDARROWS 0x00000001
#endif

另外一點要注意的是,從CreateEx函數中可以得知,工具條窗口的窗口類名字是:

"ToolbarWindow32"

3、關於改變按鈕的尺寸,改變後所有按鈕還是同一個尺寸。

工具條類的SetSizes函數可以用來改變按鈕的尺寸,但是要注意:

 // button must be big enough to hold image
 //   + 7 pixels on x
 //   + 6 pixels on y
 ASSERT(sizeButton.cx >= sizeImage.cx + 7);
 ASSERT(sizeButton.cy >= sizeImage.cy + 6);

4、關於改變工具條的高度

工具條類的SetHeight函數可以用來改變整個工具條的高度,但是要注意的是,調用這個函數以後,工具條按鈕自動垂直居中,

如果前面設置了m_cyTopBorder 和 m_cyBottomBorder,它們的值將會改變。

5、關於LoadToolBar

通常,工具條對象Create完成以後,就會調用LoadToolBar函數加載工具條,例如:

 if (!m_wndToolBar.Create(this) ||
  !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
 {
  TRACE0("Failed to create toolbar/n");
  return -1; 
 }
這個加載過程有些細節很有意思,值得看看:

首先是一個結構,這個結構位於編譯後的工具條資源的開頭

struct CToolBarData
{
 WORD wVersion; //版本號 ==1
 WORD wWidth;
 WORD wHeight;
 WORD wItemCount; //給出後面有幾項
 //WORD aItems[wItemCount] 

 WORD* items()
  { return (WORD*)(this+1); }
};
注意,該結構沒有使用可變長度數組,而是添加了一個函數,直接返回指向結構數據後面一個字節的指針,這種方法值得借鑑。

BOOL CToolBar::LoadToolBar(LPCTSTR lpszResourceName)
{
 ASSERT_VALID(this);
 ASSERT(lpszResourceName != NULL);

 // 首先定位位圖資源
 HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_TOOLBAR);
 HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_TOOLBAR);
 if (hRsrc == NULL) return FALSE;
 //加載資源數據
 HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
 if (hGlobal == NULL) return FALSE;
 //鎖定資源,並強制轉化成結構指針
 CToolBarData* pData = (CToolBarData*)LockResource(hGlobal);
 if (pData == NULL) return FALSE;
 ASSERT(pData->wVersion == 1);

 //這裏,它不直接使用pData->items(),而是new了一塊內存,爲什麼?
 //另外,通過函數SetButtons的代碼,我們可以知道這一串WORD數據
 //給出的是每個按鈕的ID
 UINT* pItems = new UINT[pData->wItemCount];
 for (int i = 0; i < pData->wItemCount; i++)
  pItems[i] = pData->items()[i];
 BOOL bResult = SetButtons(pItems, pData->wItemCount);
 delete[] pItems;

 //設置按鈕的尺寸
 if (bResult)
 {
  // set new sizes of the buttons
  CSize sizeImage(pData->wWidth, pData->wHeight);
  //注意這裏,它都增加了7個象素
  CSize sizeButton(pData->wWidth + 7, pData->wHeight + 7);
  SetSizes(sizeButton, sizeImage);

  //這個時候才加載位圖資源,可見位圖資源和RT_TOOLBAR資源沒有在一起
  bResult = LoadBitmap(lpszResourceName);
 }

 UnlockResource(hGlobal);
 FreeResource(hGlobal);

 return bResult;
}

6、關於函數AfxLoadSysColorBitmap

這個函數是工具條類使用的,是一個未公開的API函數,定義如下:
HBITMAP AFXAPI AfxLoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc, BOOL bMono = FALSE);

LoadBitmap函數裏面使用這個函數加載工具條按鈕的位圖資源,然後調用AddReplaceBitmap設置資源句柄。在這個函數中
使用了位圖資源前面的16個系統顏色的調色板對位圖資源中的顏色做了一下處理,因此位圖資源不能超過256色,必須有調色板。
如果你已經有了自己的真彩色HBITMAP資源,直接可以通過函數SetBitmap設置也可以。但是要注意,你必須保證程序
運行期間,你的HBITMAP資源一直有效。因爲在函數SetBitmap中,做了如下的設置:

 m_hInstImageWell = NULL;
 m_hRsrcImageWell = NULL;
AddReplaceBitmap函數在添加新的位圖資源的同時,調用函數AfxDeleteObject刪除了原來的位圖資源。

7、關於SetButtonStyle

工具條按鈕定義了若干類型,分別是:
TBBS_BUTTON   標準下壓按鈕(缺省情況)
TBBS_SEPARATOR   分隔條
TBBS_CHECKBOX 自動複選框按鈕
TBBS_GROUP    開始一組按鈕
TBBS_CHECKGROUP   表示一組自動複選框按鈕的首個按鈕

8、細談SetButtonInfo函數及其用途。

SetButtonInfo用於設置某個按鈕,它的接口定義如下:
下面是它的幾個接口函數說明:

void CToolBar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)

注意CToolBarCtrl類也有這個函數,但是它們的定義是完全不同的,實際上,CToolBar::SetButtonInfo的代碼如下:

void CToolBar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)
{
 ASSERT_VALID(this);

 TBBUTTON button;
 _GetButton(nIndex, &button);
 TBBUTTON save;
 memcpy(&save, &button, sizeof(save));
 button.idCommand = nID;
 button.iBitmap = iImage;
 button.fsStyle = (BYTE)LOWORD(nStyle);
 button.fsState = (BYTE)HIWORD(nStyle);
 if (memcmp(&save, &button, sizeof(save)) != 0)
 {
  _SetButton(nIndex, &button);
  m_bDelayedButtonLayout = TRUE;
 }
}

msdn介紹說這個函數的功能是設置工具條按鈕的 ID, style, 以及圖片的編號。因此,通常這個函數有三個方面的用途:

(1)用於在工具條中添加其他控件

需要注意的是,當給出的nStyle是TBBS_SEPARATOR的時候,iImage是指它的寬度,而不是圖片的編號。這個功能在向工具條中添加其它控件(比如編輯控件、組合框控件)的時候非常有用,它可以改變按鈕的位置,爲添加的控件留出空間。這個在後面將談到。

(2)用於改變工具條中按鈕的樣式

例如:
    m_wndToolBar.SetButtonInfo(i, ID_FILE_SAVE, TBBS_CHECKBOX, 2);
該代碼將工具條按鈕ID_FILE_SAVE設置成CHECKBOX按鈕,即單擊該按鈕顯示按下,再次單擊顯示擡起。

例如:
    int i = m_wndToolBar.CommandToIndex( ID_BUTTON1);
    m_wndToolBar.SetButtonInfo(i, ID_BUTTON1, TBBS_GROUP|TBBS_CHECKBOX      , 9);
    m_wndToolBar.SetButtonInfo(i+1, ID_BUTTON2, TBBS_GROUP |TBBS_CHECKBOX  , 10);
    m_wndToolBar.SetButtonInfo(i+2, ID_BUTTON3, TBBS_GROUP |TBBS_CHECKBOX  , 11);
該代碼設置三個相鄰的按鈕爲互斥按鈕,即同一時刻只能有一個按鈕按下。

TBBS_GROUP |TBBS_CHECKBOX  等價於  TBBS_CHECKGROUP

例如:
    int i = m_wndToolBar.CommandToIndex( ID_BUTTON1);
    m_wndToolBar.SetButtonInfo(i, ID_BUTTON1, TBBS_SEPARATOR  , 0);
上述代碼將一個按鈕設置成分隔條,並設置它的寬度爲0,這可以用於動態隱藏工具條按鈕
需要的時候,還可以把它重新顯示回來:
    int i = m_wndToolBar.CommandToIndex( ID_BUTTON1);
    m_wndToolBar.SetButtonInfo(i, ID_BUTTON1, TBBS_BUTTON  , 9);
當然,nStyle參數不僅僅可以用msdn上面提到的幾種,比如CToolBarCtrl::SetButtonInfo就有更爲強大的功能,這個以後會談到。

(3)改變工具條按鈕的圖片。有的時候想在程序運行過程中,根據某些條件動態改變按鈕的圖片,
就可以用這個函數。方法如下:

(1) 在資源裏面添加一個位圖文件IDB_BITMAP1,注意它的高度和工具條位圖的高度保持一致,然後裏面可以有幾個按鈕圖片。
(2) 工具條生成以後,把這些圖片添加到工具條的圖片列表:

 CToolBarCtrl &toolctrl = m_wndToolBar.GetToolBarCtrl();
 int TotalImage =toolctrl.AddBitmap(N, IDB_BITMAP1);  //N給出位圖中圖片的個數
    這個時候TotalImage裏面就保存了工具條裏面已經保存的按鈕圖片的個數,它比實際按鈕個數要多,你可以
把這個值保存在CMainFrame類裏面,供以後使用
(3) 在需要更換工具條按鈕圖片的時候,這樣寫:
 int index = m_wndToolBar.CommandToIndex(ID_FILE_SAVE);
 m_wndToolBar.SetButtonInfo(index, ID_FILE_SAVE, TBBS_BUTTON, TotalImage-1);
則將ID_FILE_SAVE按鈕的圖片設置成圖片列表中的最後一個。


9、CToolBar 類的public函數說明

 void SetSizes(SIZE sizeButton, SIZE sizeImage); //設置按鈕尺寸,圖片尺寸
 void SetHeight(int cyHeight);   //設置工具條的高度

 BOOL LoadToolBar(LPCTSTR lpszResourceName); //加載工具條
 BOOL LoadToolBar(UINT nIDResource);

 BOOL LoadBitmap(LPCTSTR lpszResourceName); //加載位圖,這兩個函數基本不用了
 BOOL LoadBitmap(UINT nIDResource);

 //設置工具條位圖,可以用來改變工具條按鈕的位圖
 BOOL SetBitmap(HBITMAP hbmImageWell);  

 //如果沒有使用LoadToolBar,而使用LoadBitmap,則需要用這個函數設置按鈕
 BOOL SetButtons(const UINT* lpIDArray, int nIDCount); 

 //根據ID得到按鈕的位置編號
 int CommandToIndex(UINT nIDFind) const; 
 //根據按鈕的位置得到它的ID
 UINT GetItemID(int nIndex) const;

 //返回指定按鈕的矩形區域座標,單位是象素,相對於工具條左上角
 virtual void GetItemRect(int nIndex, LPRECT lpRect) const;
 //獲取指定按鈕的屬性
 UINT GetButtonStyle(int nIndex) const;
 //設置指定按鈕的屬性
 void SetButtonStyle(int nIndex, UINT nStyle);
 //獲取指定按鈕的信息,包括ID,類型,相關聯的圖片編號
 void GetButtonInfo(int nIndex, UINT& nID, UINT& nStyle, int& iImage) const;
 //設置指定按鈕的信息
 void SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage);
 //設置指定按鈕的文字
 BOOL SetButtonText(int nIndex, LPCTSTR lpszText);
 //獲取指定按鈕的文字
 CString GetButtonText(int nIndex) const;
 void GetButtonText(int nIndex, CString& rString) const;

 //獲取工具條內的CToolBarCtrl
 CToolBarCtrl& GetToolBarCtrl() const;
 //設置父窗口。由於通常在生成工具條的同時指定了父窗口,因此這個函數很少用到。
 void SetOwner(CWnd* pOwnerWnd);
 //用指定位圖替換工具條已有位圖,如果原來工具條沒有設置位圖,則添加這個位圖。
 BOOL AddReplaceBitmap(HBITMAP hbmImageWell);


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