Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Tato část vysvětluje, jak provádět následující úlohy:
- Registrování tříd podřízených oken a tříd oken s rámečkem
- Vytváření rámečků a Podřízených Oken
- psaní hlavní zprávové smyčky
- Psaní procedury rámového okna
- Psát proceduru podřízeného okna
- Vytváření podřízeného okna
Pro ilustraci těchto úloh obsahuje tato část příklady z multipadu, což je typická aplikace s více dokumenty (MDI).
Registrace tříd dceřiných a rámových oken
Typická aplikace MDI musí registrovat dvě třídy oken: jednu pro okno rámečku a jednu pro podřízená okna. Pokud aplikace podporuje více než jeden typ dokumentu (například tabulku a graf), musí pro každý typ zaregistrovat třídu okna.
Struktura třídy pro rámečkové okno je podobná struktuře třídy pro hlavní okno v aplikacích, které nejsou MDI. Struktura třídy podřízených oken MDI se mírně liší od struktury podřízených oken v aplikacích jiných než MDI následujícím způsobem:
- Struktura třídy by měla mít ikonu, protože uživatel může minimalizovat podřízené okno MDI, jako by to bylo normální okno aplikace.
- Název nabídky by měl být null, protože podřízené okno MDI nemůže mít vlastní nabídku.
- Struktura třídy by měla rezervovat nadbytečné místo ve struktuře okna. S tímto prostorem může aplikace přidružit data, jako je název souboru, ke konkrétnímu podřízenému okně.
Následující příklad ukazuje, jak Multipad registruje své okno a třídy podřízených oken.
BOOL WINAPI InitializeApplication()
{
WNDCLASS wc;
// Register the frame window class.
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) MPFrameWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = LoadIcon(hInst, IDMULTIPAD);
wc.hCursor = LoadCursor((HANDLE) NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
wc.lpszMenuName = IDMULTIPAD;
wc.lpszClassName = szFrame;
if (!RegisterClass (&wc) )
return FALSE;
// Register the MDI child window class.
wc.lpfnWndProc = (WNDPROC) MPMDIChildWndProc;
wc.hIcon = LoadIcon(hInst, IDNOTE);
wc.lpszMenuName = (LPCTSTR) NULL;
wc.cbWndExtra = CBWNDEXTRA;
wc.lpszClassName = szChild;
if (!RegisterClass(&wc))
return FALSE;
return TRUE;
}
Vytváření rámcových a podřízených oken
Po registraci tříd oken může aplikace MDI vytvořit svá okna. Nejprve vytvoří okno rámce pomocí funkce CreateWindow nebo CreateWindowEx. Po vytvoření okna rámce aplikace znovu vytvoří okno klienta pomocí CreateWindow nebo CreateWindowEx. Aplikace by měla jako název třídy klientského okna zadat MDICLIENT; MDICLIENT je předregistrovaná třída okna definovaná systémem. Parametr lpvParamCreateWindow nebo CreateWindowEx by měl odkazovat na strukturu CLIENTCREATESTRUCT. Tato struktura obsahuje členy popsané v následující tabulce:
| Člen | Popis |
|---|---|
| hWindowMenu | Identifikátor pro nabídku okna sloužící k ovládání podřízených oken MDI. Při vytváření podřízených oken aplikace přidá jejich názvy do nabídky okna jako položky nabídky. Uživatel pak může aktivovat podřízené okno kliknutím na jeho název v nabídce okna. |
| idFirstChild | Určuje identifikátor prvního podřízeného okna MDI. Prvnímu vytvořenému podřízenému oknu MDI je přiřazen tento identifikátor. Další okna se vytvářejí s přírůstkovými identifikátory oken. Když dojde ke zrušení podřízeného okna, systém okamžitě znovu přiřadí identifikátory okna, aby zachoval jejich rozsah souvislý. |
Při přidání názvu podřízeného okna do nabídky okna systém přiřadí identifikátor podřízeného okna. Když uživatel klikne na titulek podřízeného okna, rámcové okno obdrží zprávu WM_COMMAND s identifikátorem v parametru wParam. Měli byste zadat hodnotu pro idFirstChild člena, která není v konfliktu s identifikátory položek v menu rámcového okna.
Při zpracování zprávy WM_CREATE vytvoří procedura okna s rámečkem Multipad okno klienta MDI. Následující příklad ukazuje, jak se vytvoří okno klienta.
case WM_CREATE:
{
CLIENTCREATESTRUCT ccs;
// Retrieve the handle to the window menu and assign the
// first child window identifier.
ccs.hWindowMenu = GetSubMenu(GetMenu(hwnd), WINDOWMENU);
ccs.idFirstChild = IDM_WINDOWCHILD;
// Create the MDI client window.
hwndMDIClient = CreateWindow( "MDICLIENT", (LPCTSTR) NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
0, 0, 0, 0, hwnd, (HMENU) 0xCAC, hInst, (LPSTR) &ccs);
ShowWindow(hwndMDIClient, SW_SHOW);
}
break;
Názvy podřízených oken jsou přidávány do spodní části nabídky okna. Pokud aplikace přidá řetězce do nabídky okna pomocí funkce AppendMenu, mohou být tyto řetězce přepsány názvy podřízených oken při překreslení nabídky okna (pokaždé když je podřízené okno vytvořeno nebo zničeno). Aplikace MDI, která přidává řetězce do nabídky okna, by měla použít funkci InsertMenu a ověřit, zda názvy podřízených oken nepřepsaly tyto nové řetězce.
Pomocí stylu WS_CLIPCHILDREN vytvořte okno klienta MDI, abyste zabránili překreslování okna přes jeho podřízená okna.
Vytvoření hlavní smyčky zpráv
Hlavní smyčka zpráv aplikace MDI je podobná hlavní smyčce aplikace, která není MDI, při zpracování akcelerátorových kláves. Rozdíl je v tom, že smyčka zpráv MDI volá funkci TranslateMDISysAccel před kontrolou klíčů akcelerátorů definovaných aplikací nebo před odesláním zprávy.
Následující příklad ukazuje smyčku zpráv typické aplikace MDI. Všimněte si, že GetMessage může vrátit -1, pokud dojde k chybě.
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
if (!TranslateMDISysAccel(hwndMDIClient, &msg) &&
!TranslateAccelerator(hwndFrame, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
Funkce TranslateMDISysAccel překládá WM_KEYDOWN zprávy do WM_SYSCOMMAND zpráv a odesílá je do aktivního podřízeného okna MDI. Pokud zpráva není zprávou akcelerátoru MDI, vrátí funkce FALSE, v takovém případě aplikace používá funkci TranslateAccelerator k určení, zda byla stisknuta některá z kláves akcelerátoru definovaná aplikací. Pokud ne, smyčka odešle zprávu do příslušné okenní procedury.
Psaní procedury rámcového okna
Postup okna pro MDI rámcové okno je podobný jako u hlavního okna aplikace bez MDI. Rozdíl je v tom, že procedura okna rámečku předává všechny zprávy, které nezpracuje do funkce DefFrameProc namísto funkce DefWindowProc. Kromě toho musí procedura okna rámečku předat také některé zprávy, které zpracovává, včetně těch uvedených v následující tabulce.
| Zpráva | Odpověď |
|---|---|
| WM_COMMAND | Aktivuje podřízené okno MDI, které uživatel zvolí. Tato zpráva se odešle, když uživatel zvolí podřízené okno MDI z nabídky okna okna rámce MDI. Identifikátor okna, který tuto zprávu doprovází, identifikuje podřízené okno MDI, které se má aktivovat. |
| WM_MENUCHAR | Otevře nabídku okna aktivního podřízeného okna MDI, když uživatel stiskne kombinaci kláves ALT+ – (minus). |
| WM_SETFOCUS | Předá fokus klávesnice do okna klienta MDI, které ho zase předá do aktivního podřízeného okna MDI. |
| WM_SIZE | Změní velikost okna klienta MDI tak, aby se vešla do klientské oblasti nového rámcového okna. Pokud procedura okna rámce změní velikost okna klienta MDI na jinou velikost, neměla by funkce zprávu předat DefWindowProc. |
Procedura okna rámečku v Multipadu se nazývá MPFrameWndProc. Zpracování jiných zpráv pomocí funkce MPFrameWndProc je podobné zpracování jiných než MDI aplikací. WM_COMMAND zprávy v Multipad jsou zpracovávány místně definovanou funkcí CommandHandler. Příkazy, které Multipad nezpracuje, jsou předány funkci DefFrameProc voláním CommandHandler. Pokud multipad nepoužívá DefFrameProc ve výchozím nastavení, uživatel nemůže aktivovat podřízené okno z nabídky okna, protože WM_COMMAND zpráva odeslaná kliknutím na položku nabídky okna by byla ztracena.
Zápis procedury podřízeného okna
Podobně jako procedura okna s rámečkem používá procedura podřízeného okna MDI ve výchozím nastavení speciální funkci pro zpracování zpráv. Všechny zprávy, které procedura podřízeného okna nezpracuje, musí být předány funkci DefMDIChildProc namísto funkci DefWindowProc. Kromě toho musí být některé zprávy správy oken předány funkci DefMDIChildProc, a to i když aplikace zprávu již zpracovává, pro správnou funkci MDI. Níže jsou uvedené zprávy, které aplikace musí předat DefMDIChildProc.
| Zpráva | Odpověď |
|---|---|
| WM_CHILDACTIVATE | Provádí zpracování aktivace, když se mění velikost, přesouvají nebo zobrazují podřízená okna MDI. Tato zpráva musí být předána. |
| WM_GETMINMAXINFO | Vypočítá velikost maximalizovaného podřízeného okna MDI na základě aktuální velikosti okna klienta MDI. |
| WM_MENUCHAR | Předá zprávu do okna rámce MDI. |
| WM_MOVE | Přepočítá posuvníkové lišty klienta MDI, pokud jsou přítomny. |
| WM_SETFOCUS | Aktivuje podřízené okno, pokud není aktivním podřízeným oknem MDI. |
| WM_SIZE | Provádí operace nezbytné ke změně velikosti okna, zejména pro maximalizaci nebo obnovení podřízeného okna MDI. Nepředání této zprávy funkci DefMDIChildProc vede k vysoce nežádoucím výsledkům. |
| WM_SYSCOMMAND | Zpracovává příkazy nabídky okna (dříve známé jako systémové): SC_NEXTWINDOW, SC_PREVWINDOW, SC_MOVE, SC_SIZEa SC_MAXIMIZE. |
Vytvoření podřízeného okna
Pokud chcete vytvořit podřízené okno MDI, může aplikace buď volat funkci CreateMDIWindow, nebo odeslat WM_MDICREATE zprávu do okna klienta MDI. (Aplikace může k vytvoření podřízených oken MDI použít funkci CreateWindowEx se stylem WS_EX_MDICHILD.) Jednovláknová aplikace MDI může k vytvoření podřízeného okna použít některou z metod. Vlákno ve vícevláknové aplikaci MDI musí používat funkci CreateMDIWindow nebo CreateWindowEx k vytvoření podřízeného okna v jiném vlákně.
Parametr lParam zprávy WM_MDICREATE je vzdálený ukazatel na strukturu MDICREATESTRUCT. Struktura zahrnuje čtyři rozměrové členy: x a y, které označují vodorovné a svislé pozice okna, a cx a cy, které označují vodorovné a svislé rozsahy okna. Každý z těchto členů může být explicitně přiřazen aplikací nebo mohou být nastaveny na CW_USEDEFAULT, v takovém případě systém vybere pozici, velikost nebo obojí podle kaskádového algoritmu. V každém případě musí být inicializovány všechny čtyři členy. Multipad používá CW_USEDEFAULT pro všechny rozměry.
Posledním členem struktury MDICREATESTRUCT je styl člen, který může obsahovat bity stylů pro okno. Pokud chcete vytvořit podřízené okno MDI, které může mít libovolnou kombinaci stylů oken, zadejte MDIS_ALLCHILDSTYLES styl okna. Pokud tento styl není zadaný, má podřízené okno MDI výchozí nastavení WS_MINIMIZE, WS_MAXIMIZE, WS_HSCROLLa WS_VSCROLL styly.
Multipad vytvoří podřízená okna MDI pomocí místně definované funkce AddFile (nachází se ve zdrojovém souboru MPFILE. C). Funkce AddFile nastaví název podřízeného okna tím, že přiřadí členu szTitle struktury MDICREATESTRUCT buď název souboru, který se upravuje, nebo "Bez názvu". Člen szClass je nastaven na název třídy podřízeného okna MDI, která je zaregistrována ve funkci InitializeApplication v programu Multipad. Člen hOwner je nastaven na popisovač instance aplikace.
Následující příklad ukazuje funkci „AddFile“ v Multipadu.
HWND APIENTRY AddFile(pName)
TCHAR * pName;
{
HWND hwnd;
TCHAR sz[160];
MDICREATESTRUCT mcs;
if (!pName)
{
// If the pName parameter is NULL, load the "Untitled"
// string from the STRINGTABLE resource and set the szTitle
// member of MDICREATESTRUCT.
LoadString(hInst, IDS_UNTITLED, sz, sizeof(sz)/sizeof(TCHAR));
mcs.szTitle = (LPCTSTR) sz;
}
else
// Title the window with the full path and filename,
// obtained by calling the OpenFile function with the
// OF_PARSE flag, which is called before AddFile().
mcs.szTitle = of.szPathName;
mcs.szClass = szChild;
mcs.hOwner = hInst;
// Use the default size for the child window.
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
// Give the child window the default style. The styleDefault
// variable is defined in MULTIPAD.C.
mcs.style = styleDefault;
// Tell the MDI client window to create the child window.
hwnd = (HWND) SendMessage (hwndMDIClient, WM_MDICREATE, 0,
(LONG) (LPMDICREATESTRUCT) &mcs);
// If the file is found, read its contents into the child
// window's client area.
if (pName)
{
if (!LoadFile(hwnd, pName))
{
// Cannot load the file; close the window.
SendMessage(hwndMDIClient, WM_MDIDESTROY,
(DWORD) hwnd, 0L);
}
}
return hwnd;
}
Ukazatel předaný v parametru lParam zprávy WM_MDICREATE je předán funkci CreateWindow a zobrazí se jako první člen ve struktuře CREATESTRUCT předané ve zprávě WM_CREATE. V Multipadu se podřízené okno inicializuje během zpracování zprávy WM_CREATE inicializací proměnných dokumentu v dodatečných datech a vytvořením podřízeného okna editcontrolu.