TN021: 命令和路由傳送郵件
注意事項 |
---|
由於它第一次線上文件中包含尚未更新下列技術提示。如此一來,某些程序和主題可能已經過期或不正確。如需最新資訊,建議您先搜尋線上文件索引中有興趣的主題。 |
這張便箋說明命令路由和發送架構,以及一般視窗訊息路由的進階的主題。
請參閱 Visual C++ 如一般的詳細資訊,在此處所描述的架構上特別區分 Windows 訊息、 控制項告知和命令。 這張便箋會假設您已相當熟悉列印的文件中所述的問題,並僅解決非常先進的主題。
命令傳送和分派 MFC 1.0 功能發展至 MFC 2.0 架構
Windows 有 WM_COMMAND 為多載提供告知的功能表命令、 快速鍵和對話方塊控制項告知的訊息。
MFC 1.0 的有點藉由使用命令處理常式 (例如,"OnFileNew") 內建 CWnd 衍生類別,以取得呼叫以回應特定的 WM_COMMAND。 這稱為訊息對應的資料結構與已經黏附,而且很佔空間命令機制會產生。
MFC 1.0 另外還提供其他功能來分隔命令訊息從控制項告知。 表示命令的 16 位元的識別碼,有時也稱為命令 id。 正常啟動命令 CFrameWnd (也就是功能表選取或已轉換的對應鍵),取得傳送到各種不同的上層。
MFC 1.0 用有限的角度來說,實作多重文件介面 (MDI) 的命令路由。 (MDI 框架視窗的委派,其作用中的 MDI 子視窗的指令)。
這項功能已經歸納起來,並擴充在 MFC 2.0,以允許較大範圍的物件 (不只是視窗物件) 已經處理過的命令。 它提供了更多正式的和可延伸的架構,等待路由傳送郵件,並重新使用命令目標傳送,不只處理指令,但更新以反映目前可用的命令的 UI 物件 (例如功能表項目和工具列按鈕)。
命令 Id
如需命令路由,並繫結處理程序的說明,請參閱 Visual C++。 技術注意事項 20 包含識別碼命名的相關資訊。
我們可以使用一般的前置詞"ID_"的命令 Id。 命令 Id 是 > = 0x8000。 訊息列或狀態列會顯示指令的說明字串是否有 STRINGTABLE 資源以相同的識別碼作為命令 id。
在您的應用程式的資源,的命令 ID 可以出現在幾個位置:
在一個 STRINGTABLE 資源具有相同的識別碼作為訊息行提示。
可能是許多功能表資源中附加至叫用同一個命令的功能表項目。
(進階) 在 GOSUB 指令的 [對話方塊] 按鈕。
在您的應用程式的原始程式碼,的命令 ID 可以出現在幾個地方:
在您的資源。H (或其他主要符號標頭檔) 來定義特定應用程式的命令 Id。
也許在 ID 的陣列,用來建立工具列。
在 ON_COMMAND 巨集。
也許在 ON_UPDATE_COMMAND_UI 巨集。
目前,只有在需要的命令 Id 的 MFC 實作的是 > = 0x8000 是 GOSUB 的對話方塊或命令的實作。
GOSUB 命令,使用 [命令] 對話方塊中的架構
命令架構的路由,以及啟用命令的運作方式與框架視窗、 功能表項目、 工具列按鈕、 對話方塊列按鈕、 其他控制列和其他的使用者介面項目,設計用來更新的要求和路由命令或控制項 Id 至主要命令目標 (通常是主框架視窗)。 該命令的主要目標可能路由命令或控制項告知其他適當的命令目標物件。
(獨佔式或非強制回應) 的對話方塊有益於部分命令架構的功能,如果您將對話方塊控制項的控制項 ID 指派給適當的命令 id。 支援對話方塊不是自動的因此您可能需要撰寫一些額外的程式碼。
請注意這些功能才能正確運作中,為您的命令 Id 應該 > = 0x8000。 由於許多對話方塊無法路由至相同的框架,應該會共用的指令 > = 0x8000,而非共用的 IDCs 中特定的對話方塊應該是 < = 0x7FFF。
您可以將一般的按鈕放在正常的強制回應對話方塊與外觀的按鈕設定為適當的命令 id。 當使用者選取按鈕時,對話方塊 (通常是主框架視窗) 的擁有者就會取得就像任何其他命令的命令。 這就稱為 GOSUB 命令,因為它通常用來顯示其他對話方塊 (第一個對話方塊中的 GOSUB)。
您也可以呼叫此函式 CWnd::UpdateDialogControls 上您的對話方塊,並將它傳遞您的主框架視窗的地址。 這項功能會啟用或停用您根據它們是否具有命令處理常式的框架中的對話方塊控制項。 呼叫這個函式會自動為您的控制列,在您的應用程式閒置迴圈中,但您必須呼叫它直接為您想要讓這項功能的一般對話方塊。
呼叫 ON_UPDATE_COMMAND_UI 時
對於維持啟用/核取狀態的所有程式的功能表項目一直可能成為相當費時的問題。 啟用/核取功能表項目只有在使用者選取快顯視窗時,只是一個常用的技巧。 MFC 2.0 實作 CFrameWnd 控點 WM_INITMENUPOPUP 訊息和命令路由架構會使用來決定的狀態的功能表,透過 ON_UPDATE_COMMAND_UI 處理常式。
CFrameWnd 也會處理 WM_ENTERIDLE 訊息來描述在狀態列上 (也就是將訊息線) 上選取的項目目前的功能表。
應用程式的功能表結構,由 Visual C++ 中,編輯用來表示可在潛在指令 WM_INITMENUPOPUP 的時間。 ON_UPDATE_COMMAND_UI 處理常式可以修改的狀態或文字的功能表或功能表 (例如檔案 MRU 清單或 OLE 動詞命令的快顯功能表) 的進階的用法實際修改之前對功能表結構進行繪製。
將相同排列在 ON_UPDATE_COMMAND_UI 工具列 (和其他控制列) 會進行處理時的應用程式進入其閒置迴圈。 請參閱類別庫參考 和 技術提示 31 如需詳細資訊,請在 [控制列上。
巢狀的快顯功能表
如果您正在使用巢狀的功能表結構,您會注意到 ON_UPDATE_COMMAND_UI 在兩個不同的情況下,會呼叫第一個功能表項目的快顯功能表中的處理常式。
首先,它會針對跳現式功能表本身呼叫。 這是必要的因為快顯功能表沒有 Id,我們使用的快顯功能表的第一個功能表項目識別碼來參照整個快顯功能表。 如此一來, m_pSubMenu 成員變數的 CCmdUI 物件將會為非 NULL,且將會指到快顯功能表。
第二,它之前即呼叫之快顯功能表的功能表項目會繪製。 如此一來,ID 是指除了第一個功能表項目和 m_pSubMenu 成員變數的 CCmdUI 物件為 NULL。
這可讓您啟用快顯功能表及其功能表項目中,區隔,但是您必須撰寫某些功能表注意程式碼。 例如,在具有下列結構的巢狀功能表:
File>
New>
Sheet (ID_NEW_SHEET)
Chart (ID_NEW_CHART)
ID_NEW_SHEET 和 ID_NEW_CHART 命令可以獨立地啟用或停用。 新增兩者其中一種已啟用時,才應該啟用快顯功能表。
ID_NEW_SHEET (在快顯視窗中的第一個指令) 的命令處理常式看起來像:
void CMyApp::OnUpdateNewSheet(CCmdUI* pCmdUI)
{
if (pCmdUI->m_pSubMenu != NULL)
{
// enable entire pop-up for "New" sheet and chart
BOOL bEnable = m_bCanCreateSheet || m_bCanCreateChart;
// CCmdUI::Enable is a no-op for this case, so we
// must do what it would have done.
pCmdUI->m_pMenu->EnableMenuItem(pCmdUI->m_nIndex,
MF_BYPOSITION |
(bEnable ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
return;
}
// otherwise just the New Sheet command
pCmdUI->Enable(m_bCanCreateSheet);
}
一般更新命令處理常式和類似的查詢,將會是 ID_NEW_CHART 的命令處理常式:
void CMyApp::OnUpdateNewChart(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_bCanCreateChart);
}
ON_COMMAND 和 ON_BN_CLICKED
訊息對應巨集,如 ON_COMMAND 和 ON_BN_CLICKED 相同。 MFC 命令和控制項告知傳送機制只會使用的命令 ID 來決定要路由傳送到哪個位置。 控制與控制項告知程式碼為零的通知 (BN_CLICKED) 會被解譯為命令。
注意事項 |
---|
事實上,所有的控制項告知訊息要執行的命令處理常式鏈結。比方說,是可行,您可以撰寫控制項告知處理常式的 EN_CHANGE 在您的文件類別。這並不建議在一般,因為幾個實用的應用程式,這項功能、 功能不支援的類別精靈,以及使用功能可能會導致易損壞的程式碼。 |
停用按鈕控制項的自動停用
如果您加入的按鈕控制項在對話方塊列,或在使用 [位置] 對話方塊中所要呼叫 CWnd::UpdateDialogControls 自己,您會注意到該按鈕沒有 ON_COMMAND 或 ON_UPDATE_COMMAND_UI 處理常式會自動停用了架構。 在某些情況下,您不需要有處理常式,但您會想要一直保持啟用該按鈕。 為了達成這個目的最簡單的方法是加入空的命令處理常式 (與類別精靈簡單) 並不在它執行任何動作。
視窗訊息路由
下列 MFC 類別以及它們如何影響 Windows 訊息路由,以及其他主題說明一些更進階的主題。 這裡的資訊只會簡短說明。 請參閱類別庫參考如需詳細資訊公用 Api。 請參閱 MFC 程式庫原始程式碼,如需有關實作細節。
請參閱技術的註解 17 視窗清理的詳細資訊,非常重要的主題為所有的 CWnd-衍生類別。
CWnd 問題
實作的成員函式 CWnd::OnChildNotify 提供功能強大且可延伸的架構,若要將連結或否則通知訊息、 指令和控制項告知,若是跳至其父代 (或"董事長"]) 的子視窗 (也就是控制項)。 如果子視窗 (/ 控制) 為 C++ CWnd 虛擬函式的物件本身, OnChildNotify 會先呼叫使用參數從原始的訊息 (也就是 MSG 結構)。 子視窗可以保留郵件,吃下它,或修改訊息的父代 (極少用)。
預設值 CWnd 實作處理下列的訊息,並使用 OnChildNotify 攔截程序,讓 windows (控制項) 的訊息的第一次存取的子系:
WM_MEASUREITEM 和 WM_DRAWITEM (如 self-draw)
WM_COMPAREITEM 和 WM_DELETEITEM (如 self-draw)
WM_HSCROLL 和 WM_VSCROLL
WM_CTLCOLOR
WM_PARENTNOTIFY
您會注意到 OnChildNotify 攔截程序用來變更成 self-draw 訊息的擁有者繪製訊息。
除了 OnChildNotify 上鉤時,捲軸訊息有進一步的路由行為。 如需捲軸及來源的詳細資訊請參閱下面 WM_HSCROLL 和 WM_VSCROLL 訊息。
CFrameWnd 問題
CFrameWnd 類別會提供的大部份命令路由,以及使用者介面更新實作。 這主要用於應用程式的主框架視窗 (CWinApp::m_pMainWnd),但適用於所有的框架視窗。
主框架視窗具有功能表列的視窗,並是 [狀態列] 上一層或訊息行。 請參閱上述討論命令傳送項目和 WM_INITMENUPOPUP。
CFrameWnd 類別會提供管理使用中檢視。 下列的郵件路由傳送到使用中檢視:
(使用中檢視取得第一次存取給他們) 的所有命令訊息。
WM_HSCROLL 和 WM_VSCROLL 來自同層級郵件捲軸 (如下所示)。
WM_ACTIVATE (與 WM_MDIACTIVATE 的 MDI) 取得轉換成虛擬函式的呼叫 CView::OnActivateView。
CMDIFrameWnd/CMDIChildWnd 問題
這兩個 MDI 框架視窗類別衍生自 CFrameWnd 因此兩者都已啟用的同類型的命令路由,並且更新使用者介面中所提供 CFrameWnd。 在典型的 MDI 應用程式,主框架視窗 (也就是 CMDIFrameWnd 物件) 會保留在功能表列和狀態列,因此在路由命令的實作的主要來源。
一般路由的配置是作用中的 MDI 子視窗取得第一次存取命令。 預設值 PreTranslateMessage 函式控制對這兩個 MDI 子視窗的對應鍵對應表 (第一次) 和 MDI 框架 (第二個),以及標準 MDI 系統命令快速鍵通常由 TranslateMDISysAccel (上一次)。
捲軸上的問題
當處理捲軸訊息 (WM_HSCROLL/OnHScroll 及 (或) WM_VSCROLL/OnVScroll),您應該試著寫入處理常式程式碼,因此它不需要使用捲軸列訊息的來源。 這不只是一般的 Windows 問題,因為捲軸訊息可能來自,則為 true 的捲軸列控制或從 WS_HSCROLL/WS_VSCROLL 捲軸不是捲軸控制項。
MFC 會擴充,以便為子系或同層項目被捲動視窗的捲軸控制項 (事實上,捲軸上與被捲動視窗的父/子關係可以是任何項目)。 這是共用的捲軸列分隔視窗使用的特別重要。 請參閱技術的附註 29 如需詳細資訊的實作 CSplitterWnd 包含更多的資訊上共用捲軸列的問題。
在 [附帶一提,有兩個 CWnd 衍生的類別,捲動 [長條圖樣式,會指定在建立時間會被截取,並不會傳送到 Windows。 當傳遞給建立常式, WS_HSCROLL 和 WS_VSCROLL 可以獨立地設定,但不能變更建立之後。 不用說,您應該不會直接測試,或是設定 WS_ 嗎?捲動視窗他們自己建立的樣式位元。
對於 CMDIFrameWnd 捲軸的長條圖樣式您所傳遞至建立 或 LoadFrame 用來建立 MDICLIENT。 如果您想要讓可捲動 MDICLIENT 區域 (就像 Windows 程式管理員) 確保為同時捲動長條圖樣式 (WS_HSCROLL |WS_VSCROLL) 用來建立樣式 CMDIFrameWnd。
對於 CSplitterWnd 捲軸的長條圖樣式套用至分割區域的特殊共用的捲軸列。 對於靜態分隔視窗中,您將非透過正常設定不論是哪一捲軸列樣式。 對於動態分隔視窗中,您通常會有捲軸的方向,您將會分割,也就是樣式集 WS_HSCROLL 如果您可以將分割列, WS_VSCROLL 如果您可以將分割資料行。