W ramach ćwiczenia pierwszy raz napisałem aplikację windowsową posiadającą nie jedno, ale dwa okna, z czego jedno jest oknem głównym, a drugie jest podrzędne i nie zawsze jest otwarte.
Zrzut ekranu:

Zaimplementowałem następujące cechy zachowania aplikacji z wieloma oknami:
- Drugie okno pojawia się na oknie pierwszym, a nie w jakimś przypadkowym miejscu. Potem użytkownik może oczywiście je przemieszczać.
- Zamknięcie przez użytkownika drugiego okna nie wiąże się z zakończeniem programu. Okno pierwsze staje się wtedy oknem aktywnym.
- Gdy okno drugie jest otwarte, to pierwsze jest wyszarzałe i nie reaguje na kliknięcia, a jeśli spróbujemy coś w nim kliknąć to Windows przypomni nam o drugim oknie za pomocą dobrze znanego efektu graficznego. Nie można, a przynajmniej mi się nie udało, wepchnąć żadnego "obcego" okna pomiędzy okno pierwsze a drugie.
Pod względem technicznim okno drugie nie jest tworzone w momencie żądania jego otwarcia, niszczone, a potem tworzone od nowa, ale istnieje od początku do końca działania programu i jest tylko ukrywane albo pokazywane. Gdyby zawierało jakieś pola tekstowe albo pola wyboru, to należałoby rozważyć przywrócenie ich wszystkich do jakiegoś domyślnego stanu przy pokazywaniu drugiego okna. Dzięki temu pokazanie okna jest szybsze, ale za to, gdyby zawierało ono jekieś hipotetyczne "ciężkie pamięciwo" komponenty to zajmowałyby one pamięć nawet, gdy nie byłyby potrzebne.
Czy jest to poprawny i przewidziany przez twórców systemu Windows sposób implementacji takiej aplikacji dwuoknowej, gdyby na przykład drugie okno służyło wyświetleniu wyników przetwarzania danych wprowadzonych w pierwszym albo umożliwieniu wprowadzenia szczegółowych parametrów polecenia wydanego przyciskiem w pierwszym oknie?
Kod w języku C:
#include <windows.h>
#define TYT1 "Okno pierwsze"
#define TYT2 "Okno drugie"
HWND uok1, uok2;
HWND o1pcisk;
BOOL jest2;
LRESULT CALLBACK wndp1 (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
HWND hh;
RECT rect;
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_COMMAND:
hh = (HWND) lParam;
if (hh == o1pcisk) {
if (!jest2) {
jest2 = TRUE;
EnableWindow (uok1, FALSE);
GetWindowRect (uok1, &rect);
SetWindowPos (uok2, HWND_TOP,
rect.left + 25, rect.top + 25,
0, 0, SWP_NOSIZE);
ShowWindow (uok2, SW_RESTORE);
}
}
break;
default:
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
}
LRESULT CALLBACK wndp2 (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CLOSE:
ShowWindow (uok2, SW_HIDE);
jest2 = FALSE;
EnableWindow (uok1, TRUE);
BringWindowToTop (uok1);
break;
default:
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
WNDCLASS wndcla;
MSG msg;
jest2 = FALSE;
wndcla.style = 0;
wndcla.lpfnWndProc = wndp1;
wndcla.cbClsExtra = wndcla.cbWndExtra = 0;
wndcla.hInstance = hInstance;
wndcla.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndcla.hCursor = LoadCursor (NULL, IDC_CROSS);
wndcla.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wndcla.lpszMenuName = NULL;
wndcla.lpszClassName = "pierwsze";
RegisterClass (&wndcla);
wndcla.style = 0;
wndcla.lpfnWndProc = wndp2;
wndcla.cbClsExtra = wndcla.cbWndExtra = 0;
wndcla.hInstance = hInstance;
wndcla.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndcla.hCursor = LoadCursor (NULL, IDC_ARROW);
wndcla.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wndcla.lpszMenuName = NULL;
wndcla.lpszClassName = "drugie";
RegisterClass (&wndcla);
uok1 = CreateWindow ("pierwsze", TYT1,
WS_OVERLAPPED | WS_SYSMENU,
CW_USEDEFAULT, 0, 320, 110, NULL,
NULL, hInstance, NULL);
o1pcisk = CreateWindow ("BUTTON", "Otworz okno 2",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
10, 10, 300, 55, uok1,
NULL, hInstance, NULL);
uok2 = CreateWindow ("drugie", TYT2,
WS_OVERLAPPED | WS_SYSMENU,
0, 0, 250, 250, uok1,
NULL, hInstance, NULL);
CreateWindow ("STATIC", "Jestem drugim oknem.",
WS_CHILD | WS_VISIBLE | SS_CENTER,
0, 100, 250, 50, uok2,
NULL, hInstance, NULL);
ShowWindow (uok1, SW_SHOW);
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
DestroyWindow (uok2);
ExitProcess (0);
}