TN006: Mapy zpráv
Tato poznámka popisuje zařízení mapy zpráv MFC.
Problém
Microsoft Windows implementuje virtuální funkce ve třídách oken, které používají své zařízení pro zasílání zpráv. Vzhledem k velkému počtu zpráv, které se týkají, by poskytnutí samostatné virtuální funkce pro každou zprávu windows vytvořilo znemožněnou velkou virtuální tabulku.
Vzhledem k tomu, že se v průběhu času mění počet zpráv windows definovaných systémem a protože aplikace mohou definovat své vlastní zprávy systému Windows, mapy zpráv poskytují úroveň nepřímých informací, která brání změnám rozhraní v přerušení existujícího kódu.
Přehled
MFC poskytuje alternativu k příkazu switch, který byl použit v tradičních aplikacích se systémem Windows ke zpracování zpráv odeslaných do okna. Mapování zpráv na metody lze definovat tak, aby při přijetí zprávy v okně byla volána příslušná metoda automaticky. Toto zařízení mapy zpráv je navržené tak, aby připomínalo virtuální funkce, ale u virtuálních funkcí jazyka C++ není možné využívat další výhody.
Definování mapy zpráv
Makro DECLARE_MESSAGE_MAP deklaruje tři členy třídy.
Privátní pole položek AFX_MSGMAP_ENTRY s názvem _messageEntries.
Chráněná AFX_MSGMAP struktura označovaná jako messageMap , která odkazuje na pole _messageEntries .
Chráněná virtuální funkce,
GetMessageMap
která vrací adresu messageMap.
Toto makro by mělo být vloženo do deklarace jakékoli třídy pomocí map zpráv. Podle konvence je na konci deklarace třídy. Příklad:
class CMyWnd : public CMyParentWndClass
{
// my stuff...
protected:
//{{AFX_MSG(CMyWnd)
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Jedná se o formát vygenerovaný aplikací AppWizard a ClassWizard při vytváření nových tříd. Pro TřídyWizard jsou potřeba závorky //{{ a //}}.
Tabulka mapy zpráv je definována pomocí sady maker, která se rozbalí na položky mapy zpráv. Tabulka začíná voláním makra BEGIN_MESSAGE_MAP , která definuje třídu, která je zpracována touto mapou zpráv, a nadřazenou třídou, do které se předávají neošetřené zprávy. Tabulka končí voláním makra END_MESSAGE_MAP .
Mezi těmito dvěma voláními maker je položka pro každou zprávu, kterou má tato mapa zpráv zpracovat. Každá standardní zpráva systému Windows obsahuje makro formuláře ON_WM_MESSAGE_NAME který pro tuto zprávu vygeneruje položku.
Byl definován standardní podpis funkce pro rozbalení parametrů každé zprávy systému Windows a zajištění bezpečnosti typů. Tyto podpisy mohou být nalezeny v souboru Afxwin.h v deklaraci CWnd. Každý z nich je označen klíčovým slovem afx_msg pro snadnou identifikaci.
Poznámka
TřídaWizard vyžaduje použití klíčového slova afx_msg v deklarací obslužné rutiny mapování zpráv.
Tyto podpisy funkcí byly odvozeny pomocí jednoduché konvence. Název funkce vždy začíná na "On
". Následuje název zprávy systému Windows s odebraným znakem "WM_" a prvním písmenem každého slova s velkými písmeny. Pořadí parametrů je wParam následované LOWORD
(lParam), pak HIWORD
(lParam). Nepoužité parametry nejsou předány. Všechny popisovače zabalené třídami MFC jsou převedeny na ukazatele na příslušné objekty MFC. Následující příklad ukazuje, jak zpracovat WM_PAINT zprávu a způsobit CMyWnd::OnPaint
zavolání funkce:
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
//{{AFX_MSG_MAP(CMyWnd)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
Tabulka mapy zpráv musí být definována mimo rozsah jakékoli definice funkce nebo třídy. Neměl by být vložen do externího bloku "C".
Poznámka
TřídaWizard upraví položky mapy zpráv, které se vyskytují mezi závorkami komentáře //{{ a //}}.
Zprávy windows definované uživatelem
Uživatelem definované zprávy mohou být zahrnuty do mapy zpráv pomocí ON_MESSAGE makra. Toto makro přijímá číslo zprávy a metodu formuláře:
// inside the class declaration
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
#define WM_MYMESSAGE (WM_USER + 100)
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()
V tomto příkladu vytvoříme obslužnou rutinu pro vlastní zprávu, která má ID zprávy systému Windows odvozené ze standardního WM_USER základu pro uživatelem definované zprávy. Následující příklad ukazuje, jak volat tuto obslužnou rutinu:
CWnd* pWnd = ...;
pWnd->SendMessage(WM_MYMESSAGE);
Rozsah zpráv definovaných uživatelem, které tento přístup používají, musí být v rozsahu WM_USER 0x7fff.
Poznámka
TřídaWizard nepodporuje zadávání rutin obslužné rutiny ON_MESSAGE z uživatelského rozhraní ClassWizard. Musíte je zadat ručně z editoru Visual C++. ClassWizard tyto položky parsuje a umožní vám je procházet stejně jako všechny ostatní položky mapy zpráv.
Registrované zprávy systému Windows
Funkce RegisterWindowMessage slouží k definování nové zprávy okna, která je zaručena jedinečná v celém systému. ON_REGISTERED_MESSAGE makra slouží ke zpracování těchto zpráv. Toto makro přijímá název proměnné UINT NEAR , která obsahuje ID registrované zprávy systému Windows. Například
class CMyWnd : public CMyParentWndClass
{
public:
CMyWnd();
//{{AFX_MSG(CMyWnd)
afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
static UINT NEAR WM_FIND = RegisterWindowMessage("COMMDLG_FIND");
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
//{{AFX_MSG_MAP(CMyWnd)
ON_REGISTERED_MESSAGE(WM_FIND, OnFind)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
Registrovaná proměnná ID zprávy systému Windows (WM_FIND v tomto příkladu) musí být proměnnou NEAR , protože je implementována ON_REGISTERED_MESSAGE.
Rozsah zpráv definovaných uživatelem, které tento přístup používají, bude v rozsahu 0xC000 k 0xFFFF.
Poznámka
TřídaWizard nepodporuje zadávání rutin obslužné rutiny ON_REGISTERED_MESSAGE z uživatelského rozhraní ClassWizard. Musíte je zadat ručně z textového editoru. ClassWizard tyto položky parsuje a umožní vám je procházet stejně jako všechny ostatní položky mapy zpráv.
Zprávy příkazů
Zprávy příkazů z nabídek a akcelerátorů se zpracovávají v mapách zpráv pomocí ON_COMMAND makra. Toto makro přijímá ID příkazu a metodu. Pouze konkrétní WM_COMMAND zpráva, která má wParam rovna zadanéMU ID příkazu, je zpracována metodou zadanou v položce message-map. Členské funkce obslužné rutiny příkazů nepřebírají žádné parametry a vrací .void
Makro má následující formulář:
ON_COMMAND(id, memberFxn)
Zprávy aktualizace příkazů se směrují stejným mechanismem, ale místo toho použijte makro ON_UPDATE_COMMAND_UI. Členské funkce obslužné rutiny aktualizace příkazu přebírají jeden parametr, ukazatel na objekt CCmdUI a vrátit void
. Makro má formulář.
ON_UPDATE_COMMAND_UI(id, memberFxn)
Pokročilí uživatelé mohou použít ON_COMMAND_EX makro, což je rozšířená forma obslužných rutin zpráv příkazů. Makro poskytuje nadmnožinu funkcí ON_COMMAND. Rozšířené členské funkce obslužné rutiny příkazů přebírají jeden parametr, UINT , který obsahuje ID příkazu, a vrátí logickou hodnotu BOOL. Vrácená hodnota by měla být PRAVDA , aby bylo možné označit, že byl příkaz zpracován. Jinak směrování bude pokračovat k dalším cílovým objektům příkazů.
Příklady těchto formulářů:
Uvnitř Resource.h (obvykle generované visual C++)
#define ID_MYCMD 100 #define ID_COMPLEX 101
Uvnitř deklarace třídy
afx_msg void OnMyCommand(); afx_msg void OnUpdateMyCommand(CCmdUI* pCmdUI); afx_msg BOOL OnComplexCommand(UINT nID);
Uvnitř definice mapy zpráv
ON_COMMAND(ID_MYCMD, OnMyCommand) ON_UPDATE_COMMAND_UI(ID_MYCMD, OnUpdateMyCommand) ON_COMMAND_EX(ID_MYCMD, OnComplexCommand)
V souboru implementace
void CMyClass::OnMyCommand() { // handle the command } void CMyClass::OnUpdateMyCommand(CCmdUI* pCmdUI) { // set the UI state with pCmdUI } BOOL CMyClass::OnComplexCommand(UINT nID) { // handle the command return TRUE; }
Pokročilí uživatelé můžou zpracovávat celou řadu příkazů pomocí jedné obslužné rutiny příkazů: ON_COMMAND_RANGE nebo ON_COMMAND_RANGE_EX. Další informace o těchto makrech najdete v dokumentaci k produktu.
Poznámka
TřídaWizard podporuje vytváření ON_COMMAND a obslužných rutin ON_UPDATE_COMMAND_UI, ale nepodporuje vytváření ON_COMMAND_EX nebo ON_COMMAND_RANGE obslužných rutin. Průvodce třídou však parsuje a umožní procházet všechny čtyři varianty obslužné rutiny příkazů.
Řízení zpráv oznámení
Zprávy odesílané z podřízených ovládacích prvků do okna mají v položce mapy zpráv další část informací: ID ovládacího prvku. Obslužná rutina zprávy zadaná v položce mapy zpráv je volána pouze v případě, že jsou splněny následující podmínky:
Kód oznámení ovládacího prvku (vysoké slovo lParam), například BN_CLICKED, odpovídá kódu oznámení zadanému v položce mapy zpráv.
ID ovládacího prvku (wParam) odpovídá ID ovládacího prvku zadanému v položce mapy zpráv.
Zprávy oznámení vlastního ovládacího prvku můžou použít makro ON_CONTROL k definování položky mapy zpráv s vlastním kódem oznámení. Toto makro má formulář.
ON_CONTROL(wNotificationCode, id, memberFxn)
Pro pokročilé použití ON_CONTROL_RANGE lze použít ke zpracování konkrétního oznámení ovládacích prvků z řady ovládacích prvků se stejnou obslužnou rutinou.
Poznámka
TřídaWizard nepodporuje vytvoření ON_CONTROL nebo ON_CONTROL_RANGE obslužné rutiny v uživatelském rozhraní. Musíte je zadat ručně pomocí textového editoru. ClassWizard tyto položky parsuje a umožní vám je procházet stejně jako všechny ostatní položky mapy zpráv.
Běžné ovládací prvky Windows používají výkonnější WM_NOTIFY pro komplexní oznámení ovládacích prvků. Tato verze mfc má přímou podporu pro tuto novou zprávu pomocí ON_NOTIFY a ON_NOTIFY_RANGE maker. Další informace o těchto makrech najdete v dokumentaci k produktu.
Viz také
Technické poznámky podle čísel
Technické poznámky podle kategorií