日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

演练VC中的COMMON一族(转贴)之二

發布時間:2024/1/18 c/c++ 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 演练VC中的COMMON一族(转贴)之二 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
第6章 演練CToolBar
6.1 工具條控制的主要功能
??? 所謂工具條就是具有位圖和分隔符組成的一組命令按鈕,位圖按鈕部分可以是下推按鈕、檢查盒按鈕、無線按鈕等。工具條對象類派生于主窗口架框類CframeWnd或CMDIFrameWnd,其類控制CToolBar::GetToolBarCtrl是MFC類庫中封裝的一個成員函數,允許使用類庫中提供的一般控制和附加功能,CtoolBar類控制成員控制提供了Windows一般控制的所有功能,然而,通過調用 GetToolBarCtrl成員函數取得引用后,可以使工具條具有更強的特性。
??? 工具條的創建具有四個步聚:首先是建立工具條資源;然后建立工具條對象結構;其次通過調用建立函數建立工具條對象并綁定;最后調用LoadToolBar調入工具條資源。
??? 另外,還可以通過直接加載位圖的方法來建立,步驟如下:首先建立工具條對象;然后通過調用建立函數建立工具條并綁定對象;其次調入包含按鈕的位圖;最后利用SetButtons 函數設置按鈕的風格并與位圖建立聯系。
??? 其中,所有按鈕位圖均存放在一個位圖文件中,按鈕位圖的大小相同,默認為16點寬、15點高,位圖必須從左至右存放。設置按鈕函數具有指向一組控制標識符ID的指針和索引值,用來確定每個按鈕的位置,如果存在分隔符ID_SEPARATOR, 那么該圖像就不存在索引值。正常情況下工具條中的按鈕都是單排從左至右排列的,可以通過SetButtonInfo函數改變排序規則。 工具條中最終形成的按鈕大小相同,均為24 x 22 象素,每個按鈕只對象一幅圖像。工具條中的按鈕默認為下推按鈕,通過設置TBBS_CHECKBOX風格可以實現檢查盒按鈕,通過調用SetRadio成員函數可以實現無線按鈕。
6.2 工具條控制的對象結構
6.2.1 工具條的對象結構
6.2.1.1 工具條的建立方法
??? CToolBar &ToolBar? 建立工具條對象結構
??? Create????????????? 建立工具條對象并綁定
??? 工具條類CToolBar::Create 的調用格式如下:
??? BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP,
??? UINT nID = AFX_IDW_TOOLBAR );
??? 其中參數pParentWnd用來確定指向工具條父窗口的指針;參數dwStyle用來確定工具條的風格,其取值如下;參數nID用來確定工具條子窗口的標識符。
??? CBRS_TOP????????? 表示工具條在框架窗口的頂部
??? CBRS_BOTTOM?????? 表示工具條在框架窗口的底部
??? CBRS_NOALIGN????? 表示工具條在父窗口改變大小時不響應
??? CBRS_TOOLTIPS???? 表示工具條具有動態提示功能
??? CBRS_SIZE_DYNAMIC 表示工具條是靜態的不能改變
??? CBRS_SIZE_FIXED?? 表示工具條是動態的可以改變
??? CBRS_FLOATING???? 表示工具條是浮動的
??? CBRS_FLYBY??????? 表示狀態條上顯示工具條中按鈕的信息
??? CBRS_HIDE_INPLACE 表示工具條隱藏
??? 除以上函數外,還包括設置按鈕和位圖的大小SetSizes、設置工具條的高度SetHeight、調入工具條資源LoadToolBar、調入工具條按鈕位圖LoadBitmap、設置工具條按鈕位圖SetBitmap、設置工具條中位圖按鈕的風格和索引值SetButtons等控制函數。
6.2.1.2 工具條的類屬性
? 工具條控制類的屬性包括取得標識符ID對象按鈕索引CommandToIndex、取得索引對應的命令標識符ID或分隔符GetItemID、取得索引對應的矩形區域GetItemRect、取得按鈕風格??? GetButtonStyle、設置按鈕風格SetButtonStyle、取得按鈕的ID標識-風格-圖象數GetButtonInfo、設置按鈕ID標識-風格-圖象數SetButtonInfo、取得按鈕提示文本GetButtonText、設置按鈕提示文本SetButtonText和取得工具條直接存取控制GetToolBarCtrl等。
6.2.2 工具條控制的對象結構
6.2.2.1 工具條控制的建立方法
??? CToolBarCtrl &ToolBarCtrl? 建立工具條控制對象結構
??? Create???????????????????? 建立工具條控制對象并綁定
??? 工具條控制類CToolBarCtrl::Create的調用格式如下:
??? BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
??? 其中參數dwStyle用來確定工具條控制的風格,必須存在WS_CHILD風格;參數rect用來確定工具條控制的大小和位置;參數pParentWnd用來確定工具條控制的父窗口指針,不能為NULL;參數nID用來確定工具條控制的標識符。
??? 可以利用WS_CHILD、WS_VISIBLE和WS_DISABLED來設置工具條窗口的風格,但必須合理設置如下控制風格:
CCS_ADJUSTABLE? 允許用戶處理工具條窗口大小,如果存在工具條窗口必須處理相應信
CCS_BOTTOM????? 使控制處于父窗口客戶區域底部并與窗口同樣寬
CCS_NODIVIDER?? 禁止在控制的頂部繪制2個象素的高亮條
CCS_NOHILITE??? 禁止在控制的頂部繪制1個象素的高亮條
CCS_NOMOVEY???? 使控制改變大小和移動時自動水平對齊,垂直對齊必須處理WM_SIZE消息
????如果CCS_NORESIZE風格有效,則該風格無效
CCS_NOPARENTALIGN禁止控制自動移到父窗口頂部或底部,如果CCS_TOP或 CCS_BOTTOM風格
????有效,則高度調整為默認而寬度可以改變
CCS_NORESIZE??? 禁止設置新的大小或無效值時使用默認寬度和高度值,而使用建立值
CCS_TOP???????? 使控制自動停靠在父窗口客戶區域頂部并與父窗口同樣寬度
??? 最后,還必須利用下面的風格來控制工具條
TBSTYLE_TOOLTIPS?? 使工具條建立并管理動態提示控制
TBSTYLE_WRAPABLE?? 使工具條控制按鈕具有多行排列格式
6.2.2.2 工具條控制中的數據結構
??? 工具條控制中最常用的數據結構為TBBUTTON,其具體結構如下:
??? typedef struct _TBBUTTON {
??? int iBitmap;??? // 基于0的位圖索引值
??? int idCommand;? // 按鈕按下時發送的命令值
??? BYTE fsState;?? // 按鈕的狀態
??? BYTE fsStyle;?? // 按鈕的風格
??? DWORD dwData;?? // 應用程序定義的數據
??? int iString;??? // 基于0的按鈕標簽字符串索引值
??? } TBBUTTON;
??? 其中按鈕狀態fsState的值如下:
TBSTATE_CHECKED? 表示按鈕具有TBSTYLE_CHECKED風格并且被按下
??? TBSTATE_ENABLED? 表示按鈕允許接受輸入,否則變灰不接受任何輸入
??? TBSTATE_HIDDEN?? 表示按鈕不可見并且不接受任何輸入
??? TBSTATE_INDETERMINATE? 表示按鈕是變灰的
??? TBSTATE_PRESSED? 表示按鈕正被按下
??? TBSTATE_WRAP???? 表示按鈕具有換行特性,該按鈕必須具有TBSTATE_ENABLED狀態
??? 按鈕風格style可以是下列值的組合:
??? TBSTYLE_BUTTON?? 表示建立標準下推按鈕
??? TBSTYLE_CHECK??? 表示建立檢查狀態按鈕
??? TBSTYLE_CHECKGROUP表示建立檢查按鈕群
??? TBSTYLE_GROUP??? 表示建立按下狀態按鈕群
??? TBSTYLE_SEP????? 表示建立按鈕分隔符
6.2.2.3 工具條控制的類屬性
??? 工具條控制的類屬性必然的聯系判斷按鈕使能狀態IsButtonEnabled、判斷按鈕檢查狀態??? IsButtonChecked、判斷按鈕按下狀態IsButtonPressed、判斷按鈕是否隱藏IsButtonHidden、判斷按鈕變灰狀態IsButtonIndeterminate、設置按鈕狀態SetState、取得按鈕狀態GetState、取得按鈕有關信息GetButton、取得按鈕總數GetButtonCount、取得按鈕矩形區域GetItemRect、設置按鈕結構大小SetButtonStructSize、設置按鈕大小SetButtonSize、設置按鈕位圖大小SetBitmapSize、取得按鈕提示控制GetToolTips、設置按鈕提示控制SetToolTips等。
6.2.2.4 工具條控制類的操作方法
??? 工具條控制類的操作方法包括使能按鈕EnableButton、檢查按鈕CheckButton、按下按鈕PressButton、隱藏按鈕HideButton、變灰按鈕Indeterminate、增加按鈕AddButtons、插入按鈕InsertButton、刪除按鈕DeleteButton、取得控制符ID對應的索引CommandToIndex、恢復工具條狀態RestoreState、保存工具條狀態SaveState和重新確定工具條大小AutoSize等。
6.3 工具條控制的應用技巧
??? 可以這樣說,工具條和上述常用控制是應用程序中不可缺少的功能元素,它的優劣會直接影響程序的基本功能和操作特性。所以這里將對工具條的建立技巧、狀態保存與恢復、平面特性、停靠位置、排序方法、消息映射、狀態更新、控制使用和屬性控制等方面,全面闡述工具條的使用技巧。
6.3.1 工具條的建立技巧
6.3.1.1 普通工具條的建立方法
??? 如果應用程序在建立時就具有工具條,則只需對工具條中的按鈕圖標進行簡單的增加、修改和刪除等操作就可滿足要求。如果未建立或者想增加其它工具條,則應按步驟追加建立。
??? 首先打開已建立好的基于單文檔的框架工程文件CTool并選擇"Insert->Resource->ToolBar"選項,插入工具條資源并設置資源標識符;然后編輯工具欄中的按鈕圖標和相應的按鈕標識符,并利用類向導ClassWizard 為按鈕消息增加COMMAND和UPDATE_COMMAND_UI兩種處理函數;在資源文件中增加和修改工具條圖標的動態提示等內容;打開MainFrm.h包含文件在"CToolBar m_wndMainToolBar"后增加"CToolBar m_wndTestToolBar" 等來創建增加的工具條對象;在MainFrm.h 中設置建立函數所需的成員變量,如顏色變量為m_bColor、動態提示功能變量為m_bToolTips 等,注意成員變量名與其獲取的參數應完全對應以便使用;最后在MainFrm.cpp中的OnCreate()建立函數中按下述示例規則增加控制代碼,其實現具體步驟如下:
??? ①在MainFrm.h中增加工具條對象控制和成員變量
??? #define TOOLLEFT?? 18
??? class CMainFrame:public CFrameWnd
??? ......//其它代碼
??? public:
??? BOOL m_bToolTips;//工具條提示功能
??? ......//其它代碼
??? protected://工具條控制成員變量
??????? CStatusBar?? m_wndStatusBar;? file://框架程序的狀態條
??????? CTestToolBar m_wndMainToolBar;//框架程序的工具條
??????? CTestToolBar m_wndTestToolBar;//新增工具條
??????? CTestToolBar m_wndDockToolBar;//浮動工具條
??????? CTestToolBar m_wndDockNextBar;//浮動工具條
??? ......//其它代碼
??? }
??? 框架程序中工具條的控制類正常應為CToolBar,可以是自己設計的派生類CtestToolBar(為筆者擴充平面特性等功能后的新工具條控制類名)等,具體根據實際需要而定。利用CDialogBar類和CStyleBar 類還可以建立擴展類型的工具條,詳見后面工具條中控制應用技巧,但在該文件頭處必須
包含如下命令:
??? #ifndef __AFXEXT_H__
??? #include <afxext.h>//直接存取CToolBar和CStatusBar
??? #endif
??? ②在MainFrm.cpp中完善窗口建立函數
??? int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
??? {? if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
??????? return -1;
??????? WINDOWPLACEMENT wp;//保存主窗口及工具欄窗口位置狀態
??????? if (ReadWindowPlacement(&wp))//讀取位置狀態信息
?????????? SetWindowPlacement(&wp);? file://設置位置狀態信息
??????? m_bToolTips=(AfxGetApp()->GetProfileInt(//讀提示功能
?????????? _T("General"),_T("ToolTips"),1)!=0); file://默認值為1
??????? m_wndMainToolBar.SetState(TOOLLEFT,TRUE);//設置初始狀態
??????? EnableDocking(CBRS_ALIGN_ANY);//停靠位置,必須提前位置
??????? if (!m_wndMainToolBar.Create(this,WS_CHILD|WS_VISIBLE
?????????? |CBRS_SIZE_DYNAMIC|CBRS_TOP|((m_bToolTips)?
?????????? (CBRS_TOOLTIPS|CBRS_FLYBY):0),IDR_MAINFRAME)||
?????????? !m_wndMainToolBar.LoadToolBar(IDR_MAINFRAME))
??????? {? file://CBRS_SIZE_DYNAMIC為鎖定位置風格
?????????? TRACE0("主工具條MAINFRAME建立失敗/n");
?????????? return -1;} // 建立失敗處理
??????? ......//建立其它工具條代碼,基本相同
??????? if (!m_wndStatusBar.Create(this)||
?????????? !m_wndStatusBar.SetIndicators(indicators,
?????????? sizeof(indicators)/sizeof(UINT)))
??????? {? file://建立狀態條
?????????? TRACE0("Failed to create status bar/n");
?????????? return -1;} // fail to create
??????? m_wndMainToolBar.SetWindowText(_T("主工具欄"));//設置標題
??????? m_wndMainToolBar.EnableDocking(CBRS_ALIGN_ANY);//停靠位置
??????? file://m_wndMainToolBar.ModifyStyle(0,TBSTYLE_FLAT);//平面特性
??????? ......//設置其它工具條位置代碼,基本相同
??????? DockControlBar(&m_wndMainToolBar,
????????? AFX_IDW_DOCKBAR_TOP);//鎖定位置
??????? DockControlBarLeftOf(&m_wndTestToolBar,
????????? &m_wndMainToolBar);//連接工具條
??????? DockControlBar(&m_wndDockToolBar,AFX_IDW_DOCKBAR_RIGHT);
??????? m_wndDockToolBar.SetColumns(AfxGetApp()->GetProfileInt(
????????? _T("General"),_T("Columns"),3));//恢復列格式,默認為3
??????? DockControlBarLeftOf(&m_wndDockNextBar,&m_wndDockToolBar);
??????? m_wndDockNextBar.SetColumns(AfxGetApp()->GetProfileInt(
????????? _T("General"),_T("Columns"),3));
??????? LoadBarState(_T("General"));//恢復保存的狀態和位置
??????? return 0;
??? }
??? 以上建立過程除工具條建立和資源調用函數外,還涉及到了窗口和工具條的狀態保存和恢復函數、注冊表參數讀取函數、工具條停靠位置函數、工具條標題修改函數、工具條連接函數、工具條列格式控制函數和工具條風格修改函數,其中工具條建立函數中的風格設置很重要,如果建立的工具條需要重新設置多行多列的排序功能,除正確設置工具條停靠位置參數外,還必須設置CBRS_SIZE_FIXED 風格,即允許程序改變工具條窗口的尺寸,如果工具條不需要重新排序,則必須設置為CBRS_SIZE_DYNAMIC 風格,否則工具欄不但不能進行重新排序和正確停靠到理想的位置,而且也無法正確保存和恢復工具條的位置和狀態,這一點應引起編程者高度重視。其余函數以后分別介紹。
6.3.1.2 浮動工具條的建立方法
??? 如果要建立浮動工具條,必須使用如下工具條的控制方法:
??? Cpoint pt(GetSystemMetrics(SM_CXSCREEN)-100,GetSystemMetrics(SM_CYSCREEN)/3);
??? FloatControlBar(&m_wndPaletteBar,pt);//浮動工具條
6.3.1.3 多位圖工具條的建立方法
??? 如果工具條存在多幅按鈕位圖,如單色和彩色等,則必須將工具條按鈕存在在位圖資源文件中而不是工具條資源中,并如下建立:
??? if(!m_wndDockToolBar.Create(this,WS_CHILD|WS_VISIBLE|
????? CBRS_SIZE_FIXED|CBRS_TOP|CBRS_TOOLTIPS,ID_PALETTEBAR)||
????? !m_wndDockToolBar.LoadBitmap(IDR_DOCKTOOLBAR)||
????? !m_wndDockToolBar.SetButtons(DockTool,
????? sizeof(DockTool)/sizeof(UINT)))
??? 其中DockTool為按鈕IDs數據結構,其定義方法如下:
??? static UINT BASED_CODE DockTool[]=
??? {?? ID_SEPARATOR,
??????? ID_STYLE_LEFT,
??????? ID_STYLE_CENTERED,
??????? ID_STYLE_RIGHT,
??????? ID_STYLE_JUSTIFIED,
??? };
??? 上述建立過程中的EnableDocking 函數必須放在所有工具條建立函數之前,否則可能出現很難發現的錯誤,如特殊工具條初始位置控制等。工具條的所有特性均在上述建立函數中確定,所以其建立過程是實現理想工具條的關鍵環節。
6.3.2 工具條狀態保存和恢復6.3.3
??? 很多應用程序中都具有保存和恢復應用程序及其工具條等狀態的功能,即下次啟動應用程序后進入上次的運行狀態,這種功能只需進行一次界面布局便可永久保存,極大方便用戶。
??? 要正確保存和恢復應用程序界面狀態,必須對應用程序窗口和工具條窗口等均進行保存和恢復,這需要完善應用程序的建立和關閉過程。具體步驟如下:
??? (1)首先利用類向導ClassWizard為應用程序增加窗口關閉WM_CLOSE消息處理功能OnClose();
??? (2)在MainFrm.cpp中為應用程序狀態設置成員變量
??? static TCHAR BASED_CODE szSection[]=_T("Settings");
??? static TCHAR BASED_CODE szWindowPos[]=_T("WindowPos");
??? static TCHAR szFormat[]=_T("%u,%u,%d,%d,%d,%d,%d,%d,%d,%d");
??? (3)編制窗口位置狀態讀取和寫入函數
??? static BOOL PASCAL NEAR ReadWindowPlacement(LPWINDOWPLACEMENT pwp)
??? {?? file://窗口位置狀態讀取函數,從INI文件中
??????? CString strBuffer=AfxGetApp()->GetProfileString(szSection,szWindowPos);
??????? if (strBuffer.IsEmpty()) return FALSE;
??????? WINDOWPLACEMENT wp;//窗口位置數據結構
??????? int nRead=_stscanf(strBuffer,szFormat,
??????????? &wp.flags,&wp.showCmd,//為數據結構讀取數值
??????????? &wp.ptMinPosition.x,&wp.ptMinPosition.y,
??????????? &wp.ptMaxPosition.x,&wp.ptMaxPosition.y,
??????????? &wp.rcNormalPosition.left,&wp.rcNormalPosition.top,
??????????? &wp.rcNormalPosition.right,&wp.rcNormalPosition.bottom);
??????? if (nRead!=10) return FALSE;
??????? wp.length=sizeof wp;//結構大小
??????? *pwp=wp;??????????? file://結構指針
??????? return TRUE;
??? }
??? static void PASCAL NEAR WriteWindowPlacement(
??????? LPWINDOWPLACEMENT pwp)
??? {?? file://窗口位置狀態寫入函數,寫到INI文件
??????? TCHAR szBuffer[sizeof("-32767")*8+sizeof("65535")*2];
??????? wsprintf(szBuffer,szFormat,//將參數值轉換為字符串
????????? pwp->flags,pwp->showCmd,
????????? pwp->ptMinPosition.x,pwp->ptMinPosition.y,
????????? pwp->ptMaxPosition.x,pwp->ptMaxPosition.y,
????????? pwp->rcNormalPosition.left,pwp->rcNormalPosition.top,
????????? pwp->rcNormalPosition.right,pwp->rcNormalPosition.bottom);
??????? AfxGetApp()->WriteProfileString(szSection,szWindowPos,szBuffer);
??? }
??? (4)在應用程序建立函數OnCreate()中增加狀態讀取和設置功能
??????? WINDOWPLACEMENT wp;//保存主窗口及工具條窗口位置狀態
??????? if (ReadWindowPlacement(&wp))//讀取位置狀態信息
?????????? SetWindowPlacement(&wp);? file://設置位置狀態信息
??? (5)在應用程序建立函數OnCreate()中增加工具條狀態恢復功能
??????? m_wndDockToolBar.SetColumns(AfxGetApp()->GetProfileInt(
????????? _T("General"),_T("Columns"),3));//恢復列格式,默認為3
??????? m_wndDockNextBar.SetColumns(AfxGetApp()->GetProfileInt(
????????? _T("General"),_T("Columns"),3));
??????? LoadBarState(_T("General"));//恢復保存的狀態和位置
??? (6)在應用程序關閉函數OnClose()中完善狀態保存功能
??? void CMainFrame::OnClose()
??? {?? file://保存工具條等的狀態
??????? SaveBarState(_T("General"));//保存工具條狀態
??????? AfxGetApp()->WriteProfileInt(_T("General"),//寫入列數
????????? _T("Columns"),m_wndDockToolBar.GetColumns());
??????? AfxGetApp()->WriteProfileInt(_T("General"),
????????? _T("ToolTips"),(m_bToolTips!=0));//寫入提示功能
??????? WINDOWPLACEMENT wp;
??????? wp.length=sizeof wp;
??????? if (GetWindowPlacement(&wp)){
?????????? wp.flags=0;
?????????? if (IsZoomed()) wp.flags|=WPF_RESTORETOMAXIMIZED;
????????????? file://如果窗口被放大,則保存為最大化狀態
????????????? WriteWindowPlacement(&wp);
??????? }
??????? CFrameWnd::OnClose();
??? }
??? 雖然SaveBarState()和LoadBarState()函數保存和恢復了工具條的所有默認位置狀態,但在實際自己實現的功能參數部分并不能被保存,所以應單獨編寫這些參數的保存代碼,如工具欄的排列格式列參數值、顏色狀態標志和是否存在動態提示功能標志等,在實際編程時一定要注意。
6.3.4 工具條的平面特性
??? 工具條的平面特性給人耳目一新之感,很多大型應用程序中的工具條都采用這一特性,并取得了巨大成功。利用VC++5中的COMCTL32.DLL動態鏈接庫可以實現平面式工具條,其主要解決問題包括:由于MFC使用風格控制位來控制工具條的外觀,所以在建立工具條時不能直接設置這種風格,必須在建立后利用SetFlatLookStyle()函數來修改;工具條控制本身也不在各級按鈕之間繪制分隔線,其另一個任務就是截取WM_PAINT消息,并在相應的位置處增加分隔線;工具條控制也不繪制左邊的把手(gripper) ,最后的任務就是調整客戶區域并繪制并繪制相應的gripper。
??? 顯然,實際工作中需要動態鏈接庫COMCTL32.DLL支持的上述方法很不方便。盡管最簡便的方法是利用VC++ 5中的未公開工具欄風格TBSTYLE_FLAT,可以得到工具條的平面特性,只需在工具條建立后簡單地增加一條代碼"m_WndMainToolBar.ModifyStyle(0,TBSTYLE_FLAT)",但筆者經試驗發現這種方法存在兩個嚴重錯誤:其一是所建立的平面工具條在移動時,不能自動清除移動前的按鈕圖標,使工具條畫面雜亂無章;其二是當建立的平面工具條具有浮動特性時,只要鼠標指針移動到浮動工具條上,整個應用程序窗口就會自動消失。所以第二種方法根本不可行。實現平面工具條的最好方法是在派生類中自己來完成,雖然這一過程比較復雜普通用戶很難做到,但如果存在一個完美的平面工具條控制類,在自己的應用程序中增加相應控制類就是一件很容易的事了。下面是筆者實現完美平面工具條派生類的步驟:
??? (1)首先利用類向導ClassWizard為工具條控制類派生一個新類CTESTTOOLBAR ,并設置相應的派生類實現文件名。由于新類的基類無法直接選擇CTOOLBAR,所以在選擇新類的基類時先選擇CTOOLBARCTRL為基類,當派生類生成后再將實現文件中的所有CTOOLBARCTRL類名修改為CTOOLBAR控制類,并利用ClassWizard 為新類增加消息WM_PAINT、WM_NCPAINT、WM_MOUSEMOVE、WM_LBUTTONDOWN和WM_LBUTTONUP消息處理功能函數,以便實現新類中平面工具條的各種特性。同時,要在MainFrm.cpp中增加包含文件TestToolBar.h。
??? (2)完善派生類實現文件TestToolBar.h內容
??? class CTestToolBar : public CToolBar
??? {......//其它代碼
??? public:
??????? CTestToolBar(); file://新類構造函數
??????? UINT GetColumns() { return m_nColumns;};//取得列數
??????? void SetState(UINT nLeft,BOOL nStated);//設置列數和狀態
??????? void OnDrawBorder(int index,CDC &dc,int flag);//畫邊框
??????? void OnEraseBorder(int index,CDC &dc);//刪除邊框
??????? void OnDrawBorders();//畫平面特性
??????? void OnDrawSep(int index,CDC &dc);//畫分隔線
??????? void OnDrawGrapper();//畫把手
??? ......//其它代碼
??? #ifdef _DEBUG file://增加插入控制
??????? virtual void AssertValid() const;
??????? virtual void Dump(CDumpContext& dc) const;
??? #endif
??? protected:??? file://增加成員變量
??????? UINT m_nColumns; file://工具欄按鈕列數
??????? UINT m_nFlags;?? file://鼠標按鍵標志
??????? int? m_nIndex;?? file://按下的按鈕號
??????? int? m_nFlagl;?? file://左鍵按下標志
??????? UINT m_nStated;? file://工具欄狀態
??????? CRect rt;??????? file://關閉按鈕矩形區域
??? ......//其它代碼
??? }
??? (3)完善派生類實現文件TestToolBar.cpp內容
??? ......//其它代碼
??? #define TOOLLEFT??? 18
??? #define LBUTTONDOWN 1
??? #define LBUTTONUP?? 2
??? ......//其它代碼
??? CTestToolBar::CTestToolBar()
??? {?? file://在構造函數中初始化變量
??????? m_nColumns=0;????? file://工具欄按鈕列數
??????? m_cxLeftBorder=16; file://左邊界
??????? m_cxRightBorder=3; file://右邊界
??????? m_cyTopBorder=3;?? file://頂邊界
??????? m_cyBottomBorder=3;//底邊界
??????? m_nFlags=0;??????? file://按鍵標志成員變量
??????? m_nIndex=0xffff;?? file://按下的按鈕號
??????? m_nFlagl=0;??????? file://左鍵按下標志
??????? m_nStated=TRUE;??? file://工具欄狀態
??? }
??? ......//其它代碼
??? #ifdef _DEBUG//插入代碼完善
??? void CTestToolBar::AssertValid() const
??? {?? CToolBar::AssertValid(); }
??? void CTestToolBar::Dump(CDumpContext& dc) const
??? {?? CToolBar::Dump(dc); }
??? #endif file://_DEBUG
......//其它代碼
??? 雖然需要實現的函數比較多,但總起來說不過是取得客戶區域或窗口所有區域的文本設備、建立畫筆和繪圖函數的集合,所以這里只給出了畫按鈕凸凹邊線的函數,其它函數可仿造實現。
??? void CTestToolBar::OnDrawBorder(int index,CDC &dc,int flag)
??? {?? file://畫按鈕邊線flag=0凸=1凹
??????? CRect rect;
??????? GetItemRect(index,&rect);//取得客戶區域
??????? rect.right--;rect.bottom--;
??????? CPen *oldpen;
??????? UINT color1,color2;
??????? if (flag==0){//兩種狀態的顏色處理
?????????? color1=COLOR_BTNHILIGHT;//按鈕高度顏色
?????????? color2=COLOR_BTNSHADOW; file://按鈕陰影顏色
??????? } else {
?????????? color1=COLOR_BTNSHADOW;
?????????? color2=COLOR_BTNHILIGHT;
??????? }
??????? CPen pen1(PS_SOLID,1,::GetSysColor(color1));
??????? CPen pen2(PS_SOLID,1,::GetSysColor(color2));
??????? dc.SelectStockObject(NULL_BRUSH);
??????? oldpen=dc.SelectObject(&pen1);
??????? dc.MoveTo(rect.right,rect.top);//畫按鈕邊亮線
??????? dc.LineTo(rect.left,rect.top);
??????? dc.LineTo(rect.left,rect.bottom);
??????? dc.SelectObject(&pen2);???? file://畫按鈕邊暗線
??????? dc.MoveTo(rect.right,rect.top);
??????? dc.LineTo(rect.right,rect.bottom);
??????? dc.LineTo(rect.left,rect.bottom);
??????? file://dc.SelectStockObject(BLACK_PEN);//畫按鈕邊黑線
??????? file://dc.MoveTo(rect.right+1,rect.top);
??????? file://dc.LineTo(rect.right+1,rect.bottom+1);
??????? file://dc.LineTo(rect.left,rect.bottom+1);
??????? dc.SelectObject(oldpen);
??????? DeleteObject(pen1);
??????? DeleteObject(pen2);
??? }
??? void CTestToolBar::OnDrawBorders()
??? {? file://實現平面工具條
??????? CRect rect;
??????? CPoint pt;
??????? GetCursorPos(&pt);? file://取得鼠標指針
??????? ScreenToClient(&pt);//變成窗口坐標
??????? int index;
??????? int count=GetCount();//工具條按鈕總數
??????? CClientDC dc(this); file://窗口客戶區域
??????? TBBUTTON button;??? file://按鈕數據結構
??????? CToolBarCtrl &ToolBarCtrl=GetToolBarCtrl();
??????? OnDrawGrapper();??? file://畫把手
??????? for(index=0;index<count;index++){
??????????? GetItemRect(index,&rect);//取得按鈕矩形區域
??????????? rect.left++;rect.top++;
??????????? ToolBarCtrl.GetButton(index,&button);//取得按鈕信息
??????????? if(button.fsState&(TBSTATE_CHECKED|TBSTATE_HIDDEN))
????????????? continue;
??????????? if(button.fsStyle&TBSTYLE_SEP){//畫分隔線
????????????? if(m_nNew!=0) OnDrawSep(index,dc);
????????????? } else if ((m_nIndex==index)||
??????????????? button.fsState&TBSTATE_PRESSED){//凹按鈕
??????????????? OnEraseBorder(index,dc);//刪除按鈕邊界
??????????????? if (rect.PtInRect(pt)) OnDrawBorder(index,dc,1);//繪下凹按鈕
?????????????????? else OnDrawBorder(index,dc,0);//繪凸出按鈕
????????????? } else if (!rect.PtInRect(pt)||m_nFlags==LBUTTONUP||
????????????????? !(button.fsState&TBSTATE_ENABLED)){
????????????????? OnEraseBorder(index,dc);//刪除按鈕邊界
????????????? } else if (m_nFlags!=LBUTTONDOWN){//凸按鈕
????????????????? OnEraseBorder(index,dc);//刪除按鈕邊界
????????????????? if(m_nFlagl==0)//鼠標按下防止再次重新出現凸起
???????????????????? OnDrawBorder(index,dc,0);//繪按鈕邊界
????????????? }
??????????? m_nFlags=0;//按下后移動后不正常凸起
??????? }
??????? ReleaseDC(&dc);
??? }
??? void CTestToolBar::OnPaint()
??? {?? file://完善重繪按鈕功能
??????? CToolBar::OnPaint();
??????? OnDrawBorders();//處理所有按鈕邊界
??? }
??? void CTestToolBar::OnLButtonDown(UINT nFlags, CPoint point)
??? {?? file://完善鼠標左鍵按下功能
??????? m_nFlags=LBUTTONDOWN;//設置鼠標按鍵標志
??????? m_nFlagl=1;
??????? CToolBar::OnLButtonDown(nFlags,point);//調原函數
??????? int index;
??????? int count=GetCount();//工具欄按鈕總數
??????? TBBUTTON button;
??????? CToolBarCtrl &ToolBarCtrl=GetToolBarCtrl();
??????? for(index=0;index<count;index++){
????????? ToolBarCtrl.GetButton(index,&button);//取得按鈕信息
????????? if (button.fsState&TBSTATE_PRESSED){ file://記錄按下按鈕號
??????????? m_nIndex=index;
????????? }
??????? }
??? }
??? void CTestToolBar::OnLButtonUp(UINT nFlags, CPoint point)
??? {?? file://完善鼠標釋放功能
??????? m_nFlags=LBUTTONUP;//設置鼠標按鍵標志
??????? m_nFlagl=0;
??????? CToolBar::OnLButtonUp(nFlags, point);//調原函數
??????? CRect rect;
??????? CPoint pt;
??????? GetCursorPos(&pt);//取得光標位置
??????? ScreenToClient(&pt);//變成窗口坐標
??????? CClientDC dc(this);//窗口客戶區域
??????? if (m_nIndex!=0xffff){//判斷按下按鈕執行功能時仍下凹
?????????? GetItemRect(m_nIndex,&rect);//取得矩形區域
?????????? rect.left++;rect.top++;
?????????? OnEraseBorder(m_nIndex,dc);//刪除按鈕邊界
?????????? if (rect.PtInRect(pt)) OnDrawBorder(m_nIndex,dc,1);//繪下凹按鈕
??????? }
??????? m_nIndex=0xffff;
??? }
??? void CTestToolBar::OnMouseMove(UINT nFlags, CPoint point)
??? {?? file://完善鼠標移動功能
??????? CToolBar::OnMouseMove(nFlags, point);
??????? int index;
??????? int count=GetCount();//工具欄按鈕總數
??????? CRect rect;
??????? if (nFlags&MK_LBUTTON) m_nFlagl=1;//防止再次重新出現凸起
??????? else m_nFlagl=0;
??????? OnDrawBorders();//繪制所有按鈕
??????? for(index=0;index<count;index++){//判斷鼠標在哪個按鈕上
?????????? GetItemRect(index,&rect);
?????????? rect.left++;rect.top++;
?????????? if (rect.PtInRect(point)&&//取得移動過程中輸入焦點
????????????? !(GetButtonStyle(index)&TBBS_SEPARATOR)){
????????????? SetCapture();//設置鼠標輸入焦點
????????????? return;
?????????? }
??????? }
??????? if (nFlags&MK_LBUTTON){//防止移出而失去輸入焦點
?????????? SetCapture();//設置鼠標輸入焦點
?????????? m_nFlagl=1;
?????????? return;
??????? } else m_nFlagl=0;
??????? ReleaseCapture();
??????? return;
??? }
??? void CTestToolBar::OnNcPaint()
??? {?? file://背景重畫函數
??????? CToolBar::OnNcPaint();
??????? OnDrawGrapper();
??? }
??? void CTestToolBar::SetState(UINT nLeft,BOOL nStated)
??? {?? file://狀態設置函數
??????? m_cxLeftBorder=nLeft;//左邊界
??????? m_nStated=nStated;?? file://工具欄狀態
??? }
??? (4)有關派生類函數幾點說明
??? ①畫按鈕凹凸邊線函數OnDrawBorder()
??? 正常工具條中的按鈕具有黑色的邊線,使按鈕凹凸感更強烈,但在平面工具條中的這種按鈕并不美觀,所以應省略黑色邊線部分,并且必須使用系統的API函數GetSysColor函數來取得邊線顏色,以便系統改變顏色時按鈕邊線也隨之改變,同時由于凹凸按鈕邊線畫法完全相同,只是顏色相反,所以兩者完全可由這個函數來實現;
??? ②畫分隔線函數OnDrawSep()
??? 畫分隔線時應遍歷每個按鈕,來取得分隔線的位置,并且利用客戶區域文本描述表就可實現,只需畫亮暗兩條線就可實現;
??? ③畫把手函數OnDrawGripper()
??? 畫把手時應使用整個窗口的文本描述表,因為客戶區域描述表不能在窗口的非客戶區域畫線,而且還必須判斷按鈕是否以多行多列方式排列,根據不同的排列方式畫水平或垂直把手,同時還要實現畫關閉按鈕功能,以和VC++5 等界面工具欄功能完全相同,另外還要判斷工具欄是否為子窗口狀態,以確定是否畫把手和關閉按鈕;
??? ④刪除按鈕邊線函數OnEraseBorder()
??? 函數用于消除系統所繪按鈕凹凸邊線,使按鈕具有平面效果,也必須利用系統的API函數GetSysColor函數來取得系統顏色,以保證系統改變顏色時能夠正常消除按鈕邊線;
??? ⑤實現平面工具欄所有功能函數OnDrawBorders()
??? 在該函數中應特別注意對按鈕分隔符判斷、按鈕凹凸狀態判斷、鼠標左鍵按下后按鈕凹凸狀態判斷、刪除系統所畫按鈕邊線判斷判斷和按下鼠標左鍵并移動鼠標按鈕的凹凸狀態判斷等,并需要利用工具條控制取得對工具欄的引用;
??? ⑥工具條更新功能函數OnPaint()
??? 在這個函數中應注意對原系統更新功能函數的調用,以實現動態提示和按鈕圖標的顯示等功能;
??? ⑦鼠標左鍵按下功能函數OnLButtonDown()
??? 該函數中除需要調用原系統鼠標左鍵按下功能函數,以實現消息的發送等功能外,還需要設置鼠標左鍵按下標志并記錄按下按鈕的位置,以便程序正確判斷按鈕的凹凸狀態;
??? ⑧鼠標左鍵釋放功能函數OnLButtonDown()
??? 該函數中除需要調用原系統鼠標左鍵釋放功能函數,以實現按鈕執行消息的發送等功能外,還需要設置鼠標左鍵釋放標志,以便程序正確判斷按鈕的凹凸狀態,此外還應重繪按鈕凹下狀態以使按鈕功能執行時按鈕應處于凹下狀態,來保證工具欄按鈕與其它高級應用程序實現的功能完全相同;
??? ⑨鼠標移動功能函數OnMouseMove()
??? 該函數中應記錄鼠標左鍵按下狀態標志,并在鼠標移動到按鈕上和鼠標左鍵按下時設置鼠標輸入焦點,來保證平面工具條在鼠標移動過程中的正常凸起狀態和鼠標點擊按鈕后對按鈕狀態的控制,如利用這一點可實現鼠標點擊按鈕后按鈕下凹,不釋放鼠標并移動到任何位置時按鈕凸起,重新移動到按鈕上按鈕仍下凹,這些全是控制鼠標焦點的功能,并及時釋放鼠標輸入焦點;
??? ⑩背景重繪等函數OnNcPaint()
??? 背景重繪函數是用來防止一個工具條被切換顯示狀態后,另一個工具欄中的把手和關閉按鈕等消失,這在鼠標反復雙擊排序后工具條非客戶區域時,另一個排序后工具欄就會出現的現象;另外函數SetState()用來設置工具條左邊界和狀態,以便為畫把手和關閉按鈕調整客戶區域并提供繪圖狀態。
??? 此外,還有鼠標移動到把手上光標改變形狀和關閉按鈕功能,由于篇幅所限這里從略,有興趣的讀者完全可以自己實現。
6.3.5 工具條的停靠位置
6.3.5.1 標6.3.5.2 準工具條的停靠位置
??? 工具條類CToolBar是控制條類CControlBar 的派生類,其顯示的初始停靠位置是通過調用繼承的函數CControlBar::EnableDocking(DWORD dwStyle)來確定的,其參數dwStyle用來指定停靠具體位置,與本文有關的風格如下,其余請參閱VC5的聯機幫助:
??? CBRS_ALIGN_TOP??? 工具條停靠在客戶區域頂部
??? CBRS_ALIGN_BOTTOM 工具條停靠在客戶區域底部
??? CBRS_ALIGN_LEFT?? 工具條停靠在客戶區域左邊
??? CBRS_ALIGN_RIGHT? 工具條停靠在客戶區域右邊
??? CBRS_ALIGN_ANY??? 工具條停靠在客戶區域任何位置
??? 利用應用程序向導AppWizard 生成的應用程序,其默認的停靠位置為CBRS_ALIGN_ANY,即允許停靠在客戶區域的任何邊,正常顯示時為靠近客戶區域的頂部:EnableDocking(CBRS_ALIGN_ANY) ,詳見上述的工具欄建立函數ONCREATE()。
??? 應用程序的單文檔和多文檔的窗口框架類均為CFrameWnd 的派生類,其指定工具條的停靠位置均是通過調用繼承的函數 CFrameWnd::EnableDocking(DWORD dwDockStyle)來實現的,其可選的參數除上述五種之外,還增加了CBRS_FLOAT_MULTI參數,這個參數主要是為設計浮動工具條而增加的,其用來確定一個框架窗口中允許存在多個浮動工具欄。同樣利用應用程序向導AppWizard 生成的應用程序,其默認的停靠位置也是CBRS_ALIGN_ANY,即允許停靠在框架窗口的任何邊,正常顯示時為靠近框架窗口的頂部,即為EnableDocking(CBRS_ALIGN_ANY),詳見上述的工具條建立函數ONCREATE()。
6.3.5.3 浮動工具條的停靠位置
??? 當一個框架窗口中存在多個浮動工具條時,需要利用函數void DockControlBar(CControlBar *pBar,UINT nDockBarID=0,LPCRECT lpRect= NULL)來確定要控制停靠位置的工具條,它也是CFrameWnd類的成員函數,其中參數pBar用來指向被控制停靠位置的工具條對象,參數nDockBarID用來確定工具條停靠在框架窗口的哪條邊上,取值為:
??? AFX_IDW_DOCKBAR_TOP??? 工具條停靠在框架窗口的頂部
??? AFX_IDW_DOCKBAR_BOTTOM 工具條停靠在框架窗口的底部
??? AFX_IDW_DOCKBAR_LEFT?? 工具條停靠在框架窗口的左邊
??? AFX_IDW_DOCKBAR_RIGHT? 工具條停靠在框架窗口的右邊
??? 如果參數nDockBarID取值為0,則工具條可以停靠在框架窗口中的任何一個可停靠的邊上,其默認位置為頂部。
6.3.5.4 工具條的連接停靠方法
??? 在很多應用程序中都存在將多個工具條同時停靠在某窗口的某一條邊上的同一工具條窗口中的情況,利用上述工具條控制函數DockControlBar的lpRect參數,通過控制工具條的停靠矩形區域來實現這個功能,如筆者實現的函數如下:
??? ①在主程序實現文件MainFrm.h中增加函數定義
??? public:
????? void DockControlBarLeftOf(CToolBar* Bar,CToolBar* LeftOf);
??? ②在主程序實現文件MainFrm.cpp中增加如下函數
??? void CMainFrame::DockControlBarLeftOf(
???????? CToolBar* Bar,CToolBar* LeftOf)
??? {?? file://設置工具條停靠在同一邊窗口中
??????? CRect rect;
??????? DWORD dw;
??????? UINT n;
??????? RecalcLayout();//重新顯示
??????? LeftOf->GetWindowRect(&rect);
??????? rect.OffsetRect(1,0);//設置偏移值以停靠在同一窗口中
??????? dw=LeftOf->GetBarStyle();
??????? n=0;
??????? n=(dw&CBRS_ALIGN_TOP)?AFX_IDW_DOCKBAR_TOP:n;
??????? n=(dw&CBRS_ALIGN_BOTTOM&&n==0)?AFX_IDW_DOCKBAR_BOTTOM:n;
??????? n=(dw&CBRS_ALIGN_LEFT&&n==0)?AFX_IDW_DOCKBAR_LEFT:n;
??????? n=(dw&CBRS_ALIGN_RIGHT&&n==0)?AFX_IDW_DOCKBAR_RIGHT:n;
??????? DockControlBar(Bar,n,&rect);
??? }
??? 在這個函數中應注意對RecalcLayout()函數和OffsetRect()函數的調用,前一個函數用來重新顯示被調整的客戶區和工具條,后一個函數用來重新確定矩形區域,這相當于用鼠標將第二個工具條拖動到前一個工具條上。
??? ③修改應用程序建立函數OnCreate()函數中的相應DockControlBar()函數為DoctControlBarOf()函數,并正確設置工具條指針,見工具條的建立技巧中的有關函數。
6.3.5.5 定制工具條的頂部停靠控制
??? 另一種工具條的停靠位置是定制工具條的停靠位置,如具有通用控制功能工具條的停靠位置,這主要實現左側定制工具條與頂部工具條之間的位置關系。其實現方法如下:
??? ①打開菜單資源增加頂部位置控制菜單項IDD_DLGBARTOP;
??? ②在實現文件MainFrm.h中增加成員控制變量m_bDialogTop;
??? BOOL m_bDialogTop;
??? 并在構造函數中為其設置初始值;
??? ③利用類向導函數為菜單項設置響應函數;
??? ④在實現文件MainFrm.cpp中完善消息映射函數。
??? void CMainFrame::OnButtonDlgbartop()
??? {?? file://定制工具條頂部位置控制函數
??????? if (m_bDialogTop) m_wndDlgBar.SetWindowPos(
?????????? &m_wndStatusBar,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
?????????? file://其它工具條停靠在最頂部,該工具條停靠其下
??????? else m_wndDlgBar.SetWindowPos(&wndTop,0,0,0,0,
?????????? SWP_NOSIZE|SWP_NOMOVE);//停靠在最頂部
??????? RecalcLayout(); file://重新顯示窗口
??????? m_bDialogTop=!m_bDialogTop;//改變變量標志
??? }
??? void CMainFrame::OnUpdateButtonDlgbartop(CCmdUI* pCmdUI)
??? {?? file://設置菜單項檢查狀態
??????? pCmdUI->SetCheck(m_bDialogTop);
??? }
6.3.6 工具條按鈕的排序方法
??? 利用應用程序向導AppWizard 生成的應用程序工具條,其按鈕均為單行水平排列的,這在實際程序開發時既不美觀又不實用,很多大型應用程序等界面中的工具條都采用多行多列的排序方式,要在自己的應用程序中實現這種排列方式,應按下述方法在派生類中控制:
??? (1)在TestToolBar.h中增加函數定義和成員變量控制
??? class CTestToolBar : public CToolBar
??? {......//其它代碼
??? public:
??????? CTestToolBar(); file://在構造函數后增加下一行
??????? void SetColumns(UINT nColumns);//增加列控制
??? ......//其它代碼
??? protected:??? file://增加成員變量
??????? UINT m_nColumns; file://工具條列按鈕數
??? ......//其它代碼
??? }
??? (2)在TestToolBar.cpp中增加變量初始化和函數
??? CTestToolBar::CTestToolBar()
??? {?? file://在構造函數中初始化變量
??????? m_nColumns=0;????? file://工具條按鈕列數
??????? ......//其它代碼
??? }
??? void CTestToolBar::SetColumns(UINT nColumns)
??? {?? file://設置按鈕排列格式
??????? m_nColumns=nColumns;//列數
??????? int nCount=GetToolBarCtrl().GetButtonCount();//按鈕數
??????? for(int i=0;i<nCount;i++){
?????????? UINT nStyle=GetButtonStyle(i);//按鈕風格
?????????? BOOL bWrap=(((i+1)%nColumns)==0);
?????????? if(bWrap) nStyle|=TBBS_WRAPPED;//設置換行
?????????? else nStyle&=~TBBS_WRAPPED;//不換行
?????????? SetButtonStyle(i,nStyle);//設置風格
??????? }
??????? Invalidate();//窗口更新
??????? GetParentFrame()->RecalcLayout();//工具欄狀態更新
??? }
??? (3)在應用程序建立函數OnCreate()中為相應的工具條增加列控制功能,并注意對保存和恢復工具條狀態函數的列控制參數處理,請參閱工具條建立技巧和狀態保存與恢復中的有關函數,重新編譯并執行應用程序就可以看到多行多列的工具條。

總結

以上是生活随笔為你收集整理的演练VC中的COMMON一族(转贴)之二的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。