MFC工具條與狀態條設計

原文:http://blog.csdn.net/touzani/archive/2007/05/18/1614244.aspx

工具條/欄(tool bar)和狀態條/欄(status bar)是構建友好GUI程序的通用標準,但它們並不是Windows API 的標準部件,而是由應用程序框架(MFC)增加 的一類控件。

工具條是CToolBar類的對象,狀態條是CStatusBar類的對象,這兩個類 都是控制條(欄)CControlBar的派生類,而CControlBar類又是從CWnd類派生的:

CObject → CCmdTarget → CWnd → CControlBar → CToolBar / CStatusBar

 
工具條和狀態條都是放置在框架窗口內部的特殊控制欄窗口,前者一般位於框架窗口頂部的 菜單條之下,後者一般位於框架窗口的底部,它們隨其父框架窗口的移動和大小改變而調整自己的長短與位置。
在MFC應用程序中,可以通過其“視圖”菜單中的對應菜單項來啓用(顯示)/ 禁止(隱藏)工具條和狀態條。而且從MFC 4.0 開始,工具條由Windows提供的工具欄通用控件來建立,是完全可停靠的(所以工具條應該改稱爲工具欄)。
由應用程序框架負責管理控制欄對象的構造、析構、及其窗口的創建與顯示。MFC應用程 序嚮導爲框架窗口類產生的控制欄代碼位於MainFrm.h / MainFrm.cpp中。
1.工具條
工具條由若干可分組的圖形按鈕組成,這些按鈕的圖像屬於同一個橫條狀位圖,存儲在一個 位圖資源文件(*.bmp)中。其中,按鈕的分組,完全由編程接口(源程序)決定,而與該位圖無關。在應用程序中單擊一個按鈕後,會像菜單項和快捷鍵一樣 發送一個命令消息(一般對應於一個菜單項消息)。可以響應UI消息來改變按鈕狀態和圖形。
1) 缺省工具條
缺省工具條包含“新建”、“打開”、“保存”,“剪切”、“複製”、“粘貼”,“打 印”,“關於”等3組8個圖形按鈕,它們在同一個位圖文件(res/Toolbar.bmp)中,每一個按鈕按順序對應於位圖中一個16*15(即16像 素寬*15像素高)位圖片斷。應用程序框架爲每個按鈕提供一個邊框,並通過改變其邊框和按鈕圖片的顏色來表示按鈕的狀態。

缺省工具條及其位圖
可用VS的工具欄編輯器窗口和對應的屬性窗口等,來修改缺省的工具條(資源標識爲 IDR_MAINFRAME)。MFC應用程序嚮導生成的缺省工具條資源文本爲:(位於資源文件Student.rc中)
IDR_MAINFRAME TOOLBAR   16, 15
BEGIN

    BUTTON      ID_FILE_NEW

    BUTTON      ID_FILE_OPEN

    BUTTON      ID_FILE_SAVE

       SEPARATOR

    BUTTON      ID_EDIT_CUT

    BUTTON      ID_EDIT_COPY

    BUTTON      ID_EDIT_PASTE

       SEPARATOR

    BUTTON      ID_FILE_PRINT

    BUTTON      ID_APP_ABOUT

END
2) 編輯工具條
下面仍以Student程序爲例,說明如何向工具條中添加按鈕、設置響應、及添加新的 工具條。下面是編輯工具條的若干操作於步驟:

l         在VC項目工作區的資源視圖頁中展開 “Student/Student.rc”中的“Toolbar”資源列表,雙擊IDR_MAINFRAME打開工具欄編輯器(見下圖)

工具條編輯器
 

l         選擇當前按鈕:單擊位於VS窗口中部的 工具條編輯窗口上部工具條欄中的所需按鈕;

l         修改位圖:對當前按鈕,可以利用“圖 像”菜單、圖像編輯器工具條和(位於屬性窗口上部的)顏色窗口,在中部的圖像編輯器窗口中繪製和修改當前按鈕的位圖;

l         修改屬性:在屬性窗口中可以

n         選擇該按鈕所對應的(菜單項)ID

n         修改該按鈕位圖的寬和高

n         鍵入/修改該按鈕所對應的提示文本 (/n後的爲按鈕的浮動提示文本)

l         刪除按鈕:將按鈕拖離工具條即可

l         添加按鈕:

n         將工具條最右邊的空白按鈕拖到你想加入 按鈕的位置

n         用“圖像”菜單、圖像編輯器工具條和顏 色窗口來繪製按鈕的位圖(在空白按鈕上繪圖後,VS會自動在其右邊添加一個新的空白按鈕)

n         在屬性窗口中選擇該按鈕所對應的(菜單 項)ID

n         還可以修改該按鈕位圖的寬和高、鍵入/ 修改該按鈕所對應的提示文本

l         分組:左/右拖動按鈕半個按鈕寬度,可 將其

n         與右邊/左邊的按鈕分開成不同的組

n         與左邊/右邊的按鈕合併成同一個組

 
例如,在Student程序的工具條中,在問號按鈕前加入分別用“+”與“-”號圖形 表示的添加菜單項(ID_ADD)與刪除菜單項(ID_DEL)按鈕。

3)添加新工具條
如果:

     在使用應用程序嚮導創建程序時,在“MFC 應用程序嚮導”對話框的“用戶界面功能”頁的“工具欄”選項中,沒有選“標準停靠”單選鈕,則需要自己加入工具條;

     或者原有的工具條不夠用,需要加入第2個工具 條;

     或者在程序運行當中需要在多個工具條中切換;

對這些情況都需要自己創建新的工具條,並且自己寫代碼將它裝入框架窗口。
(1) 創建工具條資源

l         在項目工作區的“資源視圖”頁中的 Toolbar資源表項上單擊鼠標右鍵,在彈出的浮動菜單中選“插入Toolbar”菜單項,VS會自動創建一個ID爲IDR_TOOLBAR1的空工具 條

l         可在該工具條中加入若干圖形按鈕(如 Z、L、W)

l         在屬性窗口中修改工具條的ID(如 IDR_MYTB),選擇按鈕對應的ID(如ID_NAME_ZS、ID_NAME_LS、ID_NAME_WW)

(2) 創建、裝入、顯示工具條
針對前面所講的3種情況,分別採用下列不同的方法來裝入工具條:
     在沒有工具條的框架窗口中加入工具條:

l         創建新工具條資源

l         打開頭文件MainFrm.h,在 CMainFrame類中加入工具條類CToolBar的對象m_ToolBar作爲公共數據成員:(缺省的工具條對象爲CToolBar m_wndToolBar;

CToolBar m_ToolBar;

l         在CMainFrame類中 WM_CREATE消息響應函數OnCreate(若無該函數則創建它)中的return 0;語句之前加入下列代碼:

if (!m_ToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE |

CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY |

CBRS_SIZE_DYNAMIC) || !m_ToolBar.LoadToolBar(IDR_MYTB))
       {
              TRACE0(" 未能創建工 具欄/n");
              return -1;      // 未能創建
       }
       m_ToolBar.EnableDocking(CBRS_ALIGN_ANY);
       EnableDocking(CBRS_ALIGN_ANY);
       DockControlBar(&m_ToolBar);
 
其中的CreateEx函數代替了下列三個函數的功能:

if (!m_ToolBar.Create(this)) {// 創建工具條

              TRACE0(" 未能創建工具欄/n");

              return -1;      // 創建失敗

       }

       if (!m_ToolBar.LoadToolBar(IDR_MYTB)) { // 裝入工具條

              TRACE0(" 未能創建工具欄/n");

              return -1;      // 裝入失敗

       }

       m_ToolBar.SetBarStyle(m_ToolBar.GetBarStyle() | CBRS_GRIPPER | CBRS_TOOLTIPS |

CBRS_FLYBY);
       // CBRS_GRIPPER :在工具條的左邊加一個夾條
// CBRS_TOOLTIPS :激活工具條提示;
// CBRS_FLYBY :允許在鼠標滑過圖形按鈕時在 顯示提示(缺省只有在按下按鈕時才提         示,且無浮動式提示)
 

     在框架窗口中加入多個工具條:

l         創建新工具條資源

l         打開頭文件MainFrm.h,在 CMainFrame類中加入工具條類CToolBar的對象m_ToolBar作爲公共數據成員:

CToolBar m_ToolBar;

l         在原有的OnCreate函數內加入似 ①的創建與裝入工具條的代碼,但要注意代碼的順序,且不需重複語句EnableDocking(CBRS_ALIGN_ANY); 參見下面代碼的紅色部分(其餘部分爲自動生成的缺省代碼):

 

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

       if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

              return -1;

      

       if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

              | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

              !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
       {
              TRACE0(" 未能創建工具欄/n");

              return -1;      // 未能創建

       }
 

       if (!m_ToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE |

              CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY |
              CBRS_SIZE_DYNAMIC) || !m_ToolBar.LoadToolBar(IDR_MYTB))
       {
              TRACE0(" 未能創建工具欄 /n");

              return -1;      // 未能創建

       }
 

       if (!m_wndStatusBar.Create(this) ||

              !m_wndStatusBar.SetIndicators(indicators,
               sizeof(indicators)/sizeof(UINT)))
       {
              TRACE0(" 未能創建狀態欄/n");

              return -1;      // 未能創建

       }
 

       // TODO: 如果不需要工具欄可停靠,則刪除這三行

       m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
       EnableDocking(CBRS_ALIGN_ANY);
       DockControlBar(&m_wndToolBar);
 
       m_ToolBar.EnableDocking(CBRS_ALIGN_ANY);
       DockControlBar(&m_ToolBar);
 

       return 0;

}
 

     顯示/隱藏/切換工具條:

l         似②創建若干工具條資源

l         在OnCreate函數內加入相應代 碼,來創建與裝入工具條

l         在這些代碼後面,加上隱藏暫不顯示的工 具條的代碼,如

ShowControlBar(&m_ToolBar, FALSE, FALSE);

這裏用了框架窗口類的 ShowControlBar成員函數,其原型爲:

void ShowControlBar( CControlBar* pBar, BOOL bShow, BOOL bDelay );

l         在菜單資源中添加顯示/隱 藏/ 切換工具條的菜單項(如“視圖/切換工具欄”ID_CHANGE_TOOL_BAR),在某一窗口派生類(如視圖類 CStudentView)中創建該菜單項的消息響應函數(如OnChangeToolBar),在該函數中隱藏/顯示/切換工具條,例如:

void CStudentView::OnChangeToolBar()
{

       CMainFrame *pFrmWnd = (CMainFrame*)GetTopLevelFrame();

       if(m_bTBar) {

              pFrmWnd->ShowControlBar(&pFrmWnd->m_wndToolBar, FALSE, FALSE);

              pFrmWnd->ShowControlBar(&pFrmWnd->m_ToolBar, TRUE, FALSE);

              m_bTBar = false;
       }
       else {

              pFrmWnd->ShowControlBar(&pFrmWnd->m_ToolBar, FALSE, FALSE);

              pFrmWnd->ShowControlBar(&pFrmWnd->m_wndToolBar, TRUE, FALSE);

              m_bTBar = true;
       }
}
其中m_bTBar爲bool型類變量,可在視圖類的頭文件中定義,在視圖類的代碼文 件中的構造函數中設置初始值爲true。
這裏可能需要修改m_wndToolBar爲公共的。
4)修改工具條的位圖與ID
除了可裝入和切換整個工具條(包括位圖與ID),也可只裝入位圖而不改其原來的ID, 這需要使用CToolBar類的成員函數LoadBitmap或SetBitmap,其原型分別爲
BOOL LoadBitmap( LPCTSTR lpszResourceName );
BOOL LoadBitmap( UINT nIDResource );
BOOL SetBitmap( HBITMAP hbmImageWell );
其中的按鈕圖片個數必須原來的按鈕數相同。
       也可不改變按鈕的圖片,而只是改變其ID、風格和位置:

void SetButtonInfo( int nIndex, UINT nID, UINT nStyle, int iImage );

5)設置按鈕狀態
(1) 禁止與激活
工具條上圖形按鈕的禁止與激活是與其對應菜單項同步的,並不需要另外處理。例如在 Student程序中,在還沒有按“添加”菜單項時,應該禁止“刪除”菜單項功能的使用;同樣,如果最多隻允許加入兩個菜單項,則在已經加入了兩個菜單項 後,也應該禁止“添加”菜單項功能的使用。具體步驟如下:

l         可在CStudenView類中設置一 個整數型數據成員m_iAddNum (int m_iAddNum;)

l         在類的構造函數中將該變量初始化爲0 (m_iAddNum = 0;)

l         在消息響應函數OnAdd中,將該變量 加一 (m_iAddNum++;)

l         在消息響應函數OnDel中,將該變量 減一 (m_iAddNum--;)

l         在“刪除”菜單項的UI更新響應函數 OnUpdateDel中,根據m_iAddNum的值設置“刪除”按鈕(和菜單項)的禁止與激活狀態:

void CStudentView::OnUpdateDel(CCmdUI* pCmdUI) {
       pCmdUI->Enable(m_iAddNum);
}

l         在“添加”菜單項的UI更新響應函數 OnUpdateAdd中,根據m_iAddNum的值設置“添加”按鈕(和菜單項)的禁止與激活狀態:

void CStudentView::OnUpdateAdd(CCmdUI *pCmdUI) {
       pCmdUI->Enable(m_iAddNum<2);
}
       注意:禁止與激活狀態對直接位於菜單條中的菜單項是無效的,但對於位於下拉式或浮動式彈出菜單中菜單 項則是有效的。爲了觀察對比,可以在原來的缺省菜單條中再增加一個“加刪”菜單,並且通過拷貝和粘貼將“添加”和“刪除”菜單項也加進“加刪”菜單中。運 行結果參見下圖:

(2) 是否按下
工具條上圖形按鈕是否被按下是與其對應菜單項是否已被選中(帶有√)同步的,也不需要 另外處理。如在Student程序中,切換到MYTB工具條後,可單擊按鈕Z讓其在按下與還原之間切換。具體步驟如下:

l         可在CStudenView類中設置一 個布爾型數據成員zs (bool zs;)

l         在類的構造函數中將該變量初始化爲假 (zs = false;)

l         在消息響應函數OnNameZs中,切 換該變量的真假 (zs = !zs;)

l         在Z按鈕(ID_NAME_ZS)UI 更新響應函數OnUpdateNameZs中,根據zs的值來設置按鈕是否按下:

void CStudentView::OnUpdateNameZs(CCmdUI* pCmdUI) {
    pCmdUI->SetCheck(zs);
}
2.狀態條
狀態條既不接受用戶輸入,也不產生命令消息,只能顯示提示/狀態信息和其他文本串。狀 態條窗口由若干文本窗格(pane)組成,窗格分成兩類:消息行窗格和狀態指示窗格。若想在狀態條中顯示應用程序數據,則必須禁用標準的狀態條。
1) 缺省狀態條
缺省狀態條用於顯示菜單提示和鍵盤狀態。

缺省狀態條在CMainFrame類中對應於保護型數據成員 CStatusBar m_wndStatusBar; 在MainFrm.cpp 文件的前面部分中有數組:

static UINT indicators[] =
{
       ID_SEPARATOR,           // 狀態行指示器
       ID_INDICATOR_CAPS,        // Caps Lock 指示符
       ID_INDICATOR_NUM,  // Num Lock 指示符
       ID_INDICATOR_SCRL,        // Scroll Lock 指示符
};
在CMainFrame類的消息響應函數OnCreate內有相應的創建代碼:
       if (!m_wndStatusBar.Create(this) ||
              !m_wndStatusBar.SetIndicators(indicators,
               sizeof(indicators)/sizeof(UINT)))
       {
              TRACE0(" 未能創建狀 態欄/n");
              return -1;      // 未 能創建
       }
可用狀態條類的成員函數SetPaneText在狀態條中顯示提示信息。例如

m_wndStatusBar.SetPaneText(0, L"Message line for first pane");

其函數原型爲

BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );

其中的nIndex可取不同的值,對應於不同的窗格。
2)定製狀態條/顯示應用程序數據

l         將CMainFrame類中的保護數據 成員m_wndStatusBar改爲公共的

l         在頭文件MainFrm.h中加入窗格 ID的枚舉變量。如

enum SBID {prompt, xName, xVal, yName, yVal};

l         去掉原indicators數組中的三 個狀態指示窗格的ID,加入若干(n個)消息行窗格ID (ID_SEPARATOR),其中第1個(nIndex = 0)用於顯示提示信息,其餘的(n個)用作應用程序的數據顯示。如

static UINT indicators[] =
{

       ID_SEPARATOR,        // 提示  nIndex = 0

       ID_SEPARATOR,          // "x:"     nIndex = 1

       ID_SEPARATOR,          // x      nIndex = 2

       ID_SEPARATOR,         // "y:"     nIndex = 3

       ID_SEPARATOR,         // y      nIndex = 4
};

l         在創建狀態條的代碼後(如在 CMainFrame::OnCreate函數的尾部),用狀態條的成員函數SetPaneInfo來設置每個窗格的ID、風格和寬度(單位似對話框,爲 1/4英文字母),其函數原型爲

void SetPaneInfo( int nIndex, UINT nID, UINT nStyle, int cxWidth );

其中nStyle可取值:

n         SBPS_NOBORDERS  窗格周圍無三維邊框

n         SBPS_POPOUT       窗格突出顯示

n         SBPS_DISABLED      不畫文本

n         SBPS_STRETCH      伸縮窗格以填滿空間(每個狀態條中只能有一個窗格可以被設置成伸縮的)

n         SBPS_NORMAL       不伸縮、無邊框、不凸顯

還可以用狀態條類的另一成員函數SetPaneText在窗格中顯示文本信息。如
m_wndStatusBar.SetPaneInfo(0, prompt, SBPS_STRETCH,0); // 提示
m_wndStatusBar.SetPaneInfo(1, xName, SBPS_NOBORDERS, 8); // "x:"
m_wndStatusBar.SetPaneText(xName, L"x:");
m_wndStatusBar.SetPaneInfo(2, xVal, SBPS_NORMAL, 24); // x
m_wndStatusBar.SetPaneInfo(3, yName, SBPS_NOBORDERS, 8); // "y:"
m_wndStatusBar.SetPaneText(yName, L"y:");
m_wndStatusBar.SetPaneInfo(4, yVal, SBPS_NORMAL, 24); // y

l         在應用程序中用函數 SetPaneText動態修改窗格中的文本串。如

void CStudentView::OnMouseMove(UINT nFlags, CPoint point) {
       wchar_t buf[20];

       CMainFrame *pFrmWnd = (CMainFrame*)GetTopLevelFrame();

       _itow_s(point.x, buf, 20, 10);

       pFrmWnd->m_wndStatusBar.SetPaneText(pFrmWnd->xVal, buf);

       _itow_s(point.y, buf, 20, 10);

       pFrmWnd->m_wndStatusBar.SetPaneText(pFrmWnd->yVal, buf);

       CView::OnMouseMove(nFlags, point);

}
這裏可能需要在視圖代碼文件的開始處包含主框架類的頭文件(#include "MainFrm.h");而且需要在視圖類中,爲WM_MOUSEMOVE消息添加響應函數OnMouseMove。
發佈了12 篇原創文章 · 獲贊 13 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章