第一眼,Microsoft Internet Explorer 5 和更新版本中的功能表欄看起來類似標準功能表。 不過,當您開始使用它時,看起來會相當不同。
下列螢幕快照顯示已選取 [工具] 功能表的 Windows Internet Explorer 功能表欄。
功能表欄實際上是看起來像標準功能表的工具列控制件。 功能表列沒有最上層功能表單項,而是有一系列純文本按鈕,會在單擊時顯示下拉功能表。 不過,作為特殊類型的工具列,功能表欄具有標準功能表缺少的一些功能:
- 您可以使用標準工具列技術來自定義它,讓使用者移動、刪除或新增專案。
- 它可以有熱追蹤,讓使用者知道他們何時超過最上層專案,而不需要先按兩下它。
功能表列可以併入 Rebar 控制項,並提供下列功能:
- 它可以有一個夾子,讓用戶移動或調整帶的大小。
- 它可以與其他區域共用 Rebar 控制項中的等量,例如上圖中的標準工具列。
- 當它被相鄰的樂隊所覆蓋時,它可以顯示箭號,讓使用者存取隱藏的專案。
- 它可以有應用程式定義的背景點陣圖。
本主題討論如何實作功能表欄。 由於功能表列是工具列控件的特製化實作,因此焦點會放在功能表欄特定的主題上。 如需如何將工具列併入 Rebar 控件的討論,請參閱 如何建立 Internet Explorer 樣式工具列 和 關於 Rebar 控件。
將工具列製作成功能表欄
若要將工具列設為選單列:
- 使用其他視窗樣式旗標包含 TBSTYLE_FLAT ,以建立一般工具列。 TBSTYLE_FLAT樣式也會啟用熱追蹤。 使用此樣式時,功能表欄看起來很像標準功能表,直到使用者啟動按鈕為止。 然後,當按鍵時,按鈕會顯示在工具列中脫穎而出並壓低,就像標準按鈕一樣。 因為已啟用熱追蹤,所以啟動按鈕所需的所有專案都是讓游標停留在它上方。 如果游標移至另一個按鈕,則會啟動並停用舊的按鈕。
- 使用其他視窗樣式旗標包含 TBSTYLE_LIST ,以建立清單樣式按鈕。 此樣式會建立更精簡的按鈕,看起來更像是標準最上層功能表項。
- 將按鈕的 TBBUTTON 結構的 iBitmap 成員設定為I_IMAGENONE,並將 iString 成員設定為按鈕文字,讓按鈕成為純文本。
- 為每個按鈕提供 BTNS_DROPDOWN 樣式。 按下按鈕時,工具列控件會傳送應用程式 TBN_DROPDOWN 通知,以提示它顯示按鈕的功能表。
- 將功能表欄併入 Rebar 帶中。 啟用移駐夾和形箭號,如如何建立 Internet Explorer 樣式工具列中所述。
- 實作TBN_DROPDOWN處理程式,以在單擊按鈕時顯示按鈕的下拉功能表。 下拉功能表是一種快捷功能表。 其建立方式是使用 TrackPopupMenu 函式,其左上角與按鈕的左下角對齊。
- 實作鍵盤流覽,讓功能表欄完全可存取,而不需要滑鼠。
- 實作功能表熱追蹤。 使用標準功能表時,一旦顯示最上層功能表項的功能表,將游標移到另一個最上層專案上,就會自動顯示其功能表,並折疊上一個專案的功能表。 工具列控件會熱追蹤游標並變更按鈕影像,但它會自動顯示新的功能表。 您的應用程式必須明確執行此動作。
這些專案大部分都直接實作,並會在其他地方討論。 如需如何使用工具列和 Rebar 控件的一般討論,請參閱 如何建立 Internet Explorer 樣式工具列、 關於工具列控件或 關於 Rebar 控件 。 如需如何處理快捷功能表的討論,請參閱 功能表 。 本主題的其餘部分將討論最後兩個專案:鍵盤導覽和功能表熱追蹤。
使用功能表熱追蹤停用處理導覽
用戶可以選擇使用滑鼠、鍵盤或兩者混合瀏覽功能表欄。 若要實作功能表欄導覽,您的應用程式必須處理工具列通知,並監視滑鼠和鍵盤。 此工作可以分成兩個不同的部分:使用和不使用功能表熱追蹤。 本節討論如何在未顯示任何功能表且未啟用功能表熱追蹤時處理導覽。
滑鼠流覽
如果功能表熱追蹤已停用,您可以將功能表欄視為一般工具列。 如果使用者使用滑鼠流覽,則您所有應用程式都必須處理 TBN_DROPDOWN 通知。 收到此通知時,顯示適當的下拉功能表,並啟用功能表熱追蹤。 從此為止,您會在處理導覽中討論的功能表熱追蹤制度, 並已啟用功能表熱追蹤。
如混合導覽中所述,您也需要處理TBN_HOTITEMCHANGE通知,以追蹤使用中的按鈕。 如果使用者只使用滑鼠流覽,則此通知無關緊要,但當滑鼠和鍵盤流覽混合時,這是必要的。
鍵盤流覽
如上一節所述,停用功能表熱追蹤時,使用者可以使用鍵盤執行一些瀏覽作業。 工具列控制件只有在焦點有時,才支援鍵盤流覽。 它們也不會處理功能表欄所需的所有按鍵。 處理鍵盤流覽的最簡單解決方案是明確處理相關的按鍵事件。
如果停用功能表熱追蹤,您的應用程式必須以下列方式處理這些按鍵按下事件:
- F10 鍵。 使用 TB_SETHOTITEM 啟動第一個按鈕。
- 向左鍵和向右鍵。 使用 TB_SETHOTITEM 啟動相鄰按鈕。 如果用戶嘗試從功能表欄的任一端巡覽,請啟動相反端的第一個按鈕。
- ESCAPE 鍵。 使用 TB_SETHOTITEM停用使用中按鈕。 功能表欄應該會回到啟動第一個按鈕之前的狀態。
- ALT 鍵快捷鍵。 使用TB_MAPACCELERATOR訊息來判斷 Key 字元對應的按鈕。 顯示按鈕的下拉功能表,並啟用功能表熱追蹤。
- 向下鍵。 如果按鈕為使用中,但沒有顯示任何功能表,請顯示按鈕的功能表並啟用功能表熱追蹤。
- ENTER 鍵。 使用 TB_SETHOTITEM停用使用中按鈕。 功能表欄應該會回到啟動第一個按鈕之前的狀態。
混合導覽
上一節概述的鍵盤瀏覽處理程式基本上會執行兩項工作:追蹤使用中的按鈕,並在選取按鈕時顯示適當的功能表。 只要使用者只使用鍵盤瀏覽,這些處理程式就已足夠。 不過,使用者通常會混合鍵盤和滑鼠流覽。 例如,他們可能會使用 F10 鍵啟動第一個按鈕、使用滑鼠來啟動不同的按鈕,然後使用向下鍵開啟其功能表。 如果您只監視按下按鍵來追蹤使用中的按鍵,您將會顯示錯誤的功能表。 您也必須處理 TBN_HOTITEMCHANGE 通知,才能正確追蹤使用中的按鈕。
使用已啟用功能表熱追蹤處理導覽
啟用功能表熱追蹤時,您的應用程式必須變更回應用戶流覽的方式。 若要復寫標準功能表的行為,您必須明確實作下列功能。
使用滑鼠瀏覽:
- 如果使用者將游標移至另一個按鈕上,該功能表會立即出現,而上一個功能表就會消失。
- 功能表熱追蹤會保持作用中狀態,直到用戶選取命令或單擊不屬於功能表區域的點為止。 任一個動作會停用功能表熱追蹤,直到單擊另一個按鈕為止。
- 如果游標離開功能表,則目前的下拉功能表會維持在游標返回之前,或使用者按單選單所涵蓋區域以外的點。 如果游標回到與目前顯示的按鈕不同,則會折迭舊功能表並顯示新的功能表。
使用鍵盤瀏覽:
向右鍵會將焦點向右移動。 如果專案有子功能表,則顯示子功能表。 如果項目沒有子功能表,請折疊功能表和任何子功能表、使用 TB_SETHOTITEM 啟動下一個按鈕,並顯示相鄰按鈕的功能表。 如果收到此訊息時最後一個按鈕為使用中,則顯示第一個按鈕的功能表。
向左鍵會將焦點向左移動。 如果專案是子功能表,請折疊它,並將焦點移至其父功能表。 如果專案不是子功能表,請折疊功能表、使用 TB_SETHOTITEM啟動下一個按鈕,並顯示該按鈕的功能表。
ESCAPE 鍵會備份顯示一個步驟。
- 如果顯示子功能表,則會折疊,焦點會移至父功能表。
- 如果顯示按鈕的功能表,則會折疊並停用功能表熱追蹤。 項目的按鈕會保持作用中。
- 如果未顯示功能表,但按鈕為使用中,則會停用按鈕,並停用功能表熱追蹤。
向上鍵和向下鍵只會用來在特定功能表中巡覽。
ENTER 鍵會啟動與功能表項相關聯的命令。 如果功能表項有子功能表,ENTER 鍵會顯示它。
如同功能表熱追蹤停用案例,您的應用程式必須能夠處理滑鼠、鍵盤和混合流覽。 不過,顯示功能表的事實表示傳訊必須以稍微不同的方式處理。
功能表熱追蹤的訊息處理
除了切換至新功能表所需的簡短間隔之外,功能表熱追蹤需要隨時顯示功能表。 不過,TrackPopupMenu 所顯示的下拉功能表是強制回應。 您的應用程式會繼續直接接收一些訊息,包括WM_COMMAND、TBN_HOTITEMCHANGE和一般功能表相關訊息,例如WM_MENUSELECT。 不過,它不會直接接收低階鍵盤或滑鼠訊息。 若要處理WM_MOUSEMOVE等訊息,您必須設定訊息攔截,以攔截導向至功能表的訊息。
顯示下拉功能表時,呼叫 SetWindowsHookEx 函 式並將 idHook 參數設定為 WH_MSGFILTER,以設定訊息攔截。 所有針對功能表的訊息都會傳遞至您的 MessageProc。 例如,下列代碼段會設定訊息攔截,以攔截即將進入下拉功能表的訊息。 MsgHook
是攔截程序的名稱,而 hhookMsg
是程式的句柄。
hhookMsg = SetWindowsHookEx(WH_MSGFILTER, MsgHook, HINST_THISDLL, 0);
將勾點程式的 nCode 參數設定為 MSGF_MENU,以識別功能表訊息。 lParam 參數會指向具有訊息的 MSG 結構。 本主題其餘部分會討論哪些訊息需要處理的詳細數據,以及如何討論。
您的應用程式必須藉由呼叫 CallNextHookEx 函式,將所有訊息傳遞至下一個訊息攔截。 您也必須將滑鼠訊息直接傳送至工具列控件,請務必將任何點座標轉換為工具列用戶端座標空間。 直接傳送訊息可確保工具列控件會收到適當的滑鼠訊息。 例如,工具列必須接收 WM_MOUSEMOVE 訊息,才能熱追蹤其按鈕。
啟動新的按鈕時,您的應用程式必須使用WM_CANCELMODE訊息折迭舊的下拉功能表,並顯示新的功能表。 當焦點取自具有鍵盤流覽的功能表欄,或單擊功能表區域外部時,它也必須折疊下拉功能表。 每當折疊功能表時,您應該使用 UnhookWindowsHookEx 函式釋放其訊息攔截。 如果您需要顯示另一個下拉功能表,請建立新的訊息勾點。 當命令啟動時,功能表會自動折疊,但您必須明確釋放訊息攔截。
下列程式代碼範例會釋放先前範例中所設定的訊息攔截。
UnhookWindowsHookEx(hhookMsg);
滑鼠流覽
當一般工具列控件熱追蹤按鈕時,它會醒目提示使用中的按鈕,並在每次啟動新按鈕時傳送 TBN_HOTITEMCHANGE 通知。 您的應用程式負責顯示適當的下拉功能表。 它必須:
- 處理TBN_HOTITEMCHANGE通知,以追蹤使用中的按鈕。 當使用中按鈕變更時,請折迭舊功能表並建立新的功能表。
- 處理按鍵時所傳送的TBN_DROPDOWN通知。 然後,它應該會折疊功能表並停用功能表熱追蹤。 按鈕會維持使用中狀態。
- 處理訊息攔截程式中的WM_LBUTTONDOWN、WM_RBUTTONDOWN和WM_MOUSEMOVE訊息,以追蹤滑鼠位置。 如果在功能表區域外按下滑鼠,請折疊目前的下拉功能表、停用功能表熱追蹤,並將功能表欄傳回其停用狀態。
- 啟動功能表命令時,請停用功能表熱追蹤。 功能表會自動折疊,但您必須明確釋放訊息勾點。
您也必須處理功能表相關的傳訊,例如 功能表項需要顯示子功能表時所傳送的WM_INITMENUPOPUP 訊息。 如需如何處理這類訊息的討論,請參閱 功能表。
鍵盤流覽
您的應用程式必須在訊息攔截程式中處理鍵盤訊息,並處理影響功能表熱追蹤的鍵盤訊息。 必須處理下列按鍵按下:
- ESCAPE 鍵。 ESCAPE 鍵會備份一個層級的顯示。 如果顯示子功能表,則必須折疊它。 如果顯示按鈕的主要功能表,請折疊它並停用功能表熱追蹤。 按鈕會維持使用中狀態。
- 向右鍵。 如果專案有子功能表,請加以顯示。 如果項目沒有子功能表,請折疊功能表和任何子功能表、使用 TB_SETHOTITEM啟動下一個按鈕,並顯示其功能表。 如果收到此通知時最後一個按鈕為使用中,則顯示第一個按鈕的功能表。
- 向左鍵。 如果項目位於子功能表中,請折疊專案,並將焦點移至其父功能表。 如果專案不是子功能表,請折疊功能表、使用 TB_SETHOTITEM啟動相鄰按鈕,並顯示其功能表。 如果收到此通知時第一個按鈕為使用中,請顯示最後一個按鈕的功能表。
- 向上鍵和向下鍵。 這些索引鍵可用來在功能表內巡覽,但不會影響功能表熱追蹤。
- ALT 鍵快捷鍵。 使用TB_MAPACCELERATOR訊息來判斷 Key 字元對應的按鈕。 如果它對應到與目前使用中按鈕不同的按鈕,請折疊目前的下拉功能表、使用 TB_SETHOTITEM啟動新按鈕,以及顯示相鄰按鈕的功能表。 如果 Key 字元 對應至目前顯示的按鈕,請折疊下拉功能表並停用功能表熱追蹤。 按鈕應該保持作用中。