VC6中工具條的新特色 (轉)

worldblog發表於2007-12-04
VC6中工具條的新特色 (轉)[@more@]
VC6中工具條的新特色 加入時間:01-1-8 下午 09:10:32
在Visual C++ 版本6中工具條的新特色
作者: Dave Schmitt
在已經推出Visual C++6.0預覽版幾個月了。正式版預計到今年年底釋出。同時,預覽版顯示出版本6將包含大量的改進和提高,包括支援Inte,例如扁平工具條等。雖然改進的控制元件包與Internet無關,但它首先出現在Internet Explorer中,因此它就被取做這個名字了。事實上,官方釋出的預覽版的標題是“針對Internet Explorer 4.0的Visual C++ 5.0技術預覽”。

在以前關於MFC工具條類的討論專題中,我曾答應提供一個在版本6中工具條的外觀演示。有一個很好的訊息,那就是你現在用CToolBar所作的所有工作在新的版本中都是有效的,包括那些在以前的欄目中所描述的一些擴充套件功能。因此,你將很容易修改現存的以獲得象Internet Explorer和中那樣“酷”的介面。此外,並沒有什麼壞訊息。

工具條的新特色

早在版本4中,CToolBar就已被MFC庫完全實現了。一旦公用控制元件動態連結庫(命名為comctl32.dll)變得無所不在了,CToolBar就成了如今已包含在操作中的工具條控制元件的代名詞了。然而,CToolBar並沒有揭示公用工具條控制元件的所有能力。如今,透過CreateEx(),它成功了。

公用控制元件動態連結庫現在包含了至少三類風格:最初的、在Internet Explorer 3.0中加入的以及在Internet Explorer 4.0中加入的。雖然這些版本理論上是向下相容的,但某些專業人員曾寫出一些不能在後來版本中正常執行的應用程式,這可能是這些程式採用了一些沒有公開的功能,而這些功能並沒有被包含在所有的版本中。

Visual C++程式設計師沒有這樣的經歷,因為在Visual C++4.0或5.0中comctl32.dll並不是一個可以再分發的,它在Internet Explorer時被,因此MFC程式設計師無法依靠最新版本的某些功能來用於他們的程式。這就是CToolBar僅僅具有最初的DLL的有限功能的原因。CToolBar能夠實現最新的特色意味著微軟將在Visual C++6.0中包含最新的DLL並將其作為一個可以再分發的元件。

絕大多數新特色將由在CreateEx()和其它CToolBar成員函式時指定的新的風格標誌來確定。下面是commctrl.h的一部分,它定義了TBSTYLE類識別符號:

#define TBSTYLE_BUTTON          0x0000
#define TBSTYLE_SEP             0x0001
#define TBSTYLE_CHECK           0x0002
#define TBSTYLE_GROUP           0x0004
#define TBSTYLE_CHECKGROUP      (TBSTYLE_GROUP | TBSTYLE_CHECK)
#if (__>= 0x0300)
#define TBSTYLE_DROPDOWN        0x0008
#endif
#if (_WIN32_IE >= 0x0400)
#define TBSTYLE_AUTOSIZE        0x0010
#define TBSTYLE_NOPREFIX        0x0020
#endif

#define TBSTYLE_TOOL        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
你會注意到其中的一些採用了條件編譯,依賴於_WIN32_IE的值,它預設指的是Internet Explorer 4.0(即取值為0x0400)。對於Internet Explorer 3.0(即取值為0x0300)以前的版本,大多數的TBSTYLE識別符號指的是按鈕或是一組按鈕。Internet Explorer 3.0引入了扁平鈕、文字標籤、下拉選單和自定義繪製。Internet Explorer 4.0增強了下拉選單和自定義繪製功能,並且增加了支援OLE拖動目標到一個工具條。

扁平鈕和把手

在過去的18個月中我常常被問及該如何獲得象Internet Explorer和Visual Studio中的工具條一樣不使用浮雕按鈕而是用扁平鈕並且帶有便於移動和定位的把手那樣酷的介面。這些特色並不被MFC所支援,因此最簡單獲取的方法就是購買一個擴充套件庫。而對於Visual C++ 6.0來說卻無須多此一舉,因為它使得CToolBar類實現了對扁平鈕、把手和其它新的視覺效果的支援。

在預覽版中,AppWizard並不會自動包括這些新特色,但它們卻很容易被加入。表1顯示了AppWizard建立的主視窗的OnCreate()函式,表2顯示了需要做哪些修改以獲得具有扁平鈕和把手的工具條。圖1顯示了表1建立出的工具條,而圖2顯示出了表2實現的工具條。


表 1: CMainFrame::OnCreate as generated by AppWizard
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
   return -1;

if(!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
   {
   TRACE0("Failed to create toolbarn");
   return -1;      // fail to create
   }

if(!m_wndStatar.Create(this) ||
   !m_wndStatusBar.SetIndicators(indicators,
       sizeof(indicators


圖1



表2: Adding flat buttons and the gripper

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
   return -1;

if(!m_wndToolBar.CreateEx(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
   {
   TRACE0("Failed to create toolbarn");
   return -1;      // fail to create
   }

if(!m_wndStatusBar.Create(this) ||
   !m_wndStatusBar.SetIndicators(indicators,
       sizeof(indicators)/sizeof(UINT)))
   {
   TRACE0("Failed to create status barn");
   return -1;      // fail to create
   }

// TODO: Remove this if you don't want tool tips or a resizeable toolbar
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
   CBRS_GRIPPER | CBRS_BORDER_3D | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

// TODO: Delete these three lines if you don't want the toolbar to
//  be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);

return 0;
}


圖2



 
為了作出扁平按鈕我必須使用CreateEx()來代替Create()。這個新的函式在afxext.h中宣告:

BOOL CreateEx
 (
 CWnd* pParentWnd,                // parent window
 D dwCtrlStyle = TBSTYLE_FLAT,    // extended style
 DWORD dwStyle =                 // style
   WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP,
 CRect rcBorders = CRect(0,0,0,0),    // border rectangle
 UINT nID = AFX_IDW_TOOLBAR        // ntifier
 );


因為擴充套件風格預設指的就是TBSTYLE_FLAT,因此我要得到扁平按鈕就只需要簡單地將AppWizard形成的程式碼中的Create()改為CreateEx()即可。我將在後面實現其它的擴充套件風格。

為了獲得把手,我必須在呼叫SetBarStyle()函式時包含CBRS_GRIPPER標誌,參看表2。這是CControlBar類的一個新風格,而CToolBar類是從它繼承而來的。 請注意到我也加入了CBRS_BORDER_3D標誌,這是為了修正一個未知的繪製問題,該問題將會在工具條的邊緣繪製一些多餘的點。這也許意味著預覽版確實有這個問題,因為一旦我將3D標誌加入就立即解決了並且也似乎沒有影響到別的什麼。

上面所作的兩個簡單的改變是使得一個已存程式獲得酷介面的最省力的方法。在一個程式具有了扁平鈕和把手的同時,它也不會發生不應有的其它改變。

文字標籤

Internet Explorer使得普通的工具條具有了大按鈕和取代了文字提示的文字標籤。MFC程式設計師可以透過SetButtonText()函式為每個按鈕設定一個文字串來獲得這種效果。雖然在Visual C++ 5.0中已包含了這個函式,但如果不使用扁平鈕風格則不會取得令人滿意的效果。

表3顯示瞭如何使用現有的文字提示作為按鈕的標籤,而且圖3和圖4顯示了將工具條分別定位在頂端和右邊的效果。我仍然使得文字提示有效,但你可以透過在呼叫SetBarStyle()時去掉CBRS_TOOLTIPS風格而使之無效。

表 3: Adding text labels
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
   return -1;
   
if(!m_wndToolBar.CreateEx(this) ||
   !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
   {
   TRACE0("Failed to create toolbarn");
   return -1;      // fail to create
   }
if(!m_wndStatusBar.Create(this) ||
   !m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT)))
   {
   TRACE0("Failed to create status barn");
   return -1;      // fail to create
   }

// TODO: Remove this if you don't want tool tips or a resizeable toolbar
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
   CBRS_GRIPPER | CBRS_BORDER_3D | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

// Add text to each button
for(int i = 0; i < m_wndToolBar.GetCount(); i++)
{ UINT id = m_wndToolBar.GetItemID(i);
CString s;
if(!s.LoadString(id)) continue;
int j = s.Find(_T('n'));
if(j < 0) continue;
s = s.Right(s.GetLength() - j - 1);
m_wndToolBar.SetButtonText(i,s); }// Adjust sizes to include text
CRect rect;
m_wndToolBar.GetItemRect(0,&rect);
m_wndToolBar.SetSizes(rect.Size(),CSize(16,15));// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;}






圖4

為了產生按鈕標籤,一個簡單的for迴圈掃過所有的按鈕並且從與之相連的幫助串中提取出提示文字。在設定完每個按鈕的標籤後,就呼叫工具條的SetSizes()函式去重新計算工具條的外觀以便使得標籤可見。也許會有更好的方法去實現最後一步,但我還是從微軟的MFCIE範例程式中借用了這個過程,不為別的,只為它確實有效。

從很多方面來說,MFCIE都是值得仔細學習的。從本質上來說,它實際上是Internet Explorer的一個微型版本,並且它還闡述瞭如何使用版本6的一些新特色。你將會驚訝於在你的MFC應用程式中新增HTML瀏覽功能是如此之簡單。

在絕大多數情況下你會希望文字標籤顯示在按鈕下面(這在最初的公用控制元件庫中是唯一的選擇)。Internet Explorer 3.0版加入了TBSTYLE_LIST風格,該風格導致文字標籤顯示在按鈕右邊。對於在標籤旁邊顯示一個下拉選單或者按鈕被一個子視窗覆蓋時,該風格是很有用的。

下拉選單

在“工具條的變形”一文中,我演示了透過將一個組合框作為一個子視窗來在工具條上新增下拉選單的情形。該方法在版本6中仍然有效,並且當你想在工具條上顯示當前的可選擇項時它仍然是有用的。然而,有時你希望工具條包含一個可以在滑鼠點選時顯示選擇列表或選單的按鈕。該功能現在可以透過擴充套件風格TBSTYLE_DROPDOWN和TBSTYLE_EX_DRAWDDARROWS實現了。

例如,假設我希望對應於“”選單下“新建”的按鈕可以顯示一個我的應用程式知道如何去建立的所有檔案型別的列表。表4 顯示在前面的例子中如何加入該功能,而圖5顯示該工具條。我抓取了滑鼠停留在該按鈕上時的螢幕,它顯示出了按鈕和下拉箭頭之間的分隔線。

為了加入一個下拉箭頭,首先我必須在基本的工具條控制元件上呼叫SetExtendedStyle()函式,並且指定TBSTYLE_EX_DRAWDDARROWS風格。然後我必須在每一個我想要顯示下拉箭頭的按鈕上指定TBSTYLE_DROPDOWN風格。

表 4: Converting the File menu New command to a drop-down button
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
   return -1;
   
if(!m_wndToolBar.CreateEx(this) ||
   !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
   {
   TRACE0("Failed to create toolbarn");
   return -1;      // fail to create
   }

if(!m_wndStatusBar.Create(this) ||
   !m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT)))
   {
   TRACE0("Failed to create status barn");
   return -1;      // fail to create
   }

// TODO: Remove this if you don't want tool tips or a resizeable toolbar
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
   CBRS_GRIPPER | CBRS_BORDER_3D | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

// Add text to each button
for(int i = 0; i




圖5

當在New按鈕上點選時,就象圖5所示一樣,基本的按鈕操作就發生了。在這個例子中命令訊息導致呼叫CWinApp::OnFileNew()。然而,當使用者點選下拉箭頭時,工具條就發出TBN_DROPDOWN通知訊息給工具條的父視窗。我可以透過過載OnNotify()函式或者透過在訊息對映中加入一個ON_NOTIFY而獲取這個訊息。

表5顯示了後者的實現技術。通常我顯示一個彈出選單或者一個列表框去響應這個通知訊息。在絕大多數情況下沒有必要提供一個結果值,因為預設值(TBDDRET_DEFAULT)顯示了我已獲取了對這個事件的控制。其它可能的結果值是TBDDRET_NODEFAULT和TBDDRET_TREATPRESSED。前者表示該事件沒有受到控制,當出現後者時,工具條就表現得好像該按鈕被點選一樣。

表 5: Handling drop-down notifications
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
   //{{AFX_MSG_MAP(CMainFrame)
   ON_WM_CREATE()
   //}}AFX_MSG_MAP
   ON_NOTIFY(TBN_DROPDOWN,AFX_IDW_TOOLBAR,OnDropDown)
END_MESSAGE_MAP()


void CMainFrame::OnDropDown(NMHDR* pNotifyStruct,LRESULT* result)
{
NMTOOLBAR* pInfo = (NMTOOLBAR*)pNotifyStruct;
switch(pInfo->iItem)
   {
   case ID_FILE_NEW:
   TRACE0("ID_FILE_NEW drop downn");
   // TODO: Display popup menu or list box
   break;

   // TODO: Add cases for other drop-down buttons
   }
}


 

熱點影像

執行Internet Explorer 4.0並且將滑鼠在工具條上劃過。就能注意到在平時每個按鈕是平淡的顏色。而當滑鼠觸及到該按鈕時,他會凸出來並且顯現出鮮豔的顏色。這種視覺效果採用了工具條控制元件的被稱作“熱點影像”的功能。

一般的AppWizard程式碼使用工具條資源來指定其上按鍵的外觀和與每個按鍵相連線的一個命令ID。工具條資源實際上包含一個複合的點陣圖,該點陣圖在呼叫LoadToolBar()函式時將被轉變成一個影像列表(參見表4)。要啟用熱點影像功能,我必須透過SetHotImageList()函式提供第二個影像列表,就象表6所示一樣。

表 6: Using hot images
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
   return -1;
   
if(!m_wndToolBar.CreateEx(this) ||
   !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
   {
   TRACE0("Failed to create toolbarn");
   return -1;      // fail to create
   }

CImageList img;
if(!img.Create(I_MAINFRAME,16,0,RGB(128,128,128)))
   {
   TRACE0("Failed to load hot imagesn");
   return -1;
   }
m_wndToolBar.GetToolBarCtrl().SetHotImageList(&img);
img.Detach();

if(!m_wndStatusBar.Create(this) ||
   !m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT)))
   {
   TRACE0("Failed to create status barn");
   return -1;      // fail to create
   }

// TODO: Remove this if you don't want tool tips or a resizeable toolbar
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
   CBRS_GRIPPER | CBRS_BORDER_3D | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

// Add text to each button
for(int i = 0; i




圖6

圖6 顯示了熱點影像被啟用的情形。滑鼠正停留在New按鈕上,它就被顯示成一個空文件的圖形。其它的按鈕是扁平的和淡顏色的。為了生成這個改進的工具條,我將res子目錄下的toolbar.bmp複製為toolbar1.bmp,然後將其作為一個點陣圖資源插入資源中,並取其ID為IDR_MAINFRAME。 接下來我編輯IDR_MAINFRAME 工具條,用很淡的顏色(例如淡灰色)來取代它原來的顏色。最後,我加入瞭如表6所示的對函式SetHotImageList()的呼叫。

這個例子演示了在一個已存的工具條中加入熱點影像的捷徑,但他不會改進工具條的外觀。如果你想在這一點上取得更好的效果,MFCIE的例子包含了非常好的蝕刻點陣圖,它演示了當你使用非常有藝術性的影像時它能達到何等地步的視覺效果。

其它特色

前面的講解演示了你怎樣簡單地改變現存的MFC程式,以獲得扁平鈕、把手、下拉選單和熱點影像的功能。Visual C++ 6.0還提供了幾種其它令人感興趣的工具條特色,包括自定義繪製、OLE拖入目標和使用rebar(抱歉,不知道該單詞指的是什麼)容器等。這些特色將會是將來的欄目的主題。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-987857/,如需轉載,請註明出處,否則將追究法律責任。

相關文章