Файл mditb/mditb.cpp
// ============================================================ // MDI-приложение с окнами Toolbar и Statusbar // ============================================================ #define STRICT #include <windows.h>
#include <mem.h>
#include "mditb.hpp"
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export FrameWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK _export ChildWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK _export TbWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK _export SbWndProc(HWND, UINT, WPARAM, LPARAM);
char const szFrameClassName[] = "MDITBAppClass"; char const szChildClassName[] = "MDITBChildAppClass"; char const szTbClassName[] = "MDITBCtrlAppClass"; char const szSbClassName[] = "MDISBCtrlAppClass"; char const szWindowTitle[] = "MDI Application";
HINSTANCE hInst; HWND hwndFrame; // окно Frame Window HWND hwndClient; // окно Client Window HWND hwndChild; // окно Child Window HWND hwndTb; // окно Toolbar HWND hwndSb; // окно Statusbar
// ===================================== // Функция WinMain // ===================================== #pragma argsused int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями hInst = hInstance; // сохраняем идентификатор приложения if(hPrevInstance) // может быть запущена return FALSE; // только одна копия приложения if(!InitApp(hInstance)) return FALSE; hwndFrame = CreateWindow( szFrameClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, 0, // задаем размеры и расположение CW_USEDEFAULT, 0, // окна, принятые по умолчанию 0, // идентификатор родительского окна 0, // идентификатор меню hInstance, // идентификатор приложения NULL);
// указатель на дополнительные параметры if(!hwndFrame) return FALSE; ShowWindow(hwndFrame, nCmdShow);
UpdateWindow(hwndFrame);
while(GetMessage(&msg, NULL, 0, 0)) { if(!TranslateMDISysAccel(hwndClient, &msg)) { TranslateMessage(&msg);
DispatchMessage(&msg);
} } return msg.wParam; }
// ===================================== // Функция InitApp // Выполняет регистрацию класса окна // ===================================== BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна memset(&wc, 0, sizeof(wc));
wc.lpszMenuName = "APP_MENU"; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)FrameWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "APP_ICON");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
wc.lpszClassName = (LPSTR)szFrameClassName; aWndClass = RegisterClass(&wc);
if(!aWndClass) return FALSE;
memset(&wc, 0, sizeof(wc));
wc.lpszMenuName = 0; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)ChildWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "APPCLIENT_ICON");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = (LPSTR)szChildClassName; aWndClass = RegisterClass(&wc);
if(!aWndClass) return FALSE;
// Регистрируем класс для окна Toolbar memset(&wc, 0, sizeof(wc));
wc.lpszMenuName = 0; wc.style = 0; wc.lpfnWndProc = (WNDPROC)TbWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = (LPSTR)szTbClassName; aWndClass = RegisterClass(&wc);
if(!aWndClass) return FALSE;
// Регистрируем класс для окна Statusbar memset(&wc, 0, sizeof(wc));
wc.lpszMenuName = 0; wc.style = 0; wc.lpfnWndProc = (WNDPROC)SbWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = (LPSTR)szSbClassName; aWndClass = RegisterClass(&wc);
if(!aWndClass) return FALSE; return TRUE; }
// ===================================== // Функция FrameWndProc // ===================================== LRESULT CALLBACK _export FrameWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { CLIENTCREATESTRUCT clcs; MDICREATESTRUCT mdics; switch (msg) { // Устанавливаем размеры окон Toolbar, Statusbar. // Уменьшаем размер окна Client Window case WM_SIZE: { // Располагаем окно Toolbar в верхней части // окна Frame Window MoveWindow(hwndTb, 0, // x-координата 0, // y-координата LOWORD(lParam), // ширина TBAR_SIZE, // высота TRUE);
// требуется перерисовка окна
// Располагаем окно Statusbar в нижней части // окна Frame Window MoveWindow(hwndSb, 0, // x-координата HIWORD(lParam) - SBAR_SIZE, // y-координата LOWORD(lParam), // ширина SBAR_SIZE, // высота TRUE);
// требуется перерисовка окна
// Если окно не свернуто в пиктограмму и его // идентификатор отличен от нуля, вызываем // функцию MoveWindow if(wParam != SIZEICONIC && hwndClient) { MoveWindow(hwndClient, 0, // x-координата TBAR_SIZE, // y-координата LOWORD(lParam), // ширина HIWORD(lParam) - (TBAR_SIZE + SBAR_SIZE), // высота TRUE);
// требуется перерисовка окна
// После уменьшения размеров окна нельзя // отдавать сообщение WM_SIZE функции DefFrameProc, // так как иначе размеры будут восстановлены return 0; } break; }
case WM_CREATE: { clcs.hWindowMenu = GetSubMenu(GetMenu(hwnd), 1);
clcs.idFirstChild = 500;
// Создаем окно Client Window hwndClient = CreateWindow( "MDICLIENT", // имя класса окна NULL, // заголовок окна WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | // стиль окна WS_HSCROLL | WS_VSCROLL, 0, 0, 0, 0, hwnd, // идентификатор родительского окна (HMENU)1, // идентификатор меню hInst, // идентификатор приложения (LPSTR)&clcs);
// указатель на дополнительные параметры
// Создаем окно Toolbar hwndTb = CreateWindow( szTbClassName, // имя класса окна NULL, // заголовок окна WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_DLGFRAME, 0, 0, 0, 0, hwnd, // идентификатор родительского окна (HMENU)2, // идентификатор меню hInst, // идентификатор приложения NULL);
// указатель на дополнительные параметры
// Создаем окно Statusbar hwndSb = CreateWindow( szSbClassName, // имя класса окна NULL, // заголовок окна WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_DLGFRAME, 0, 0, 0, 0, hwnd, // идентификатор родительского окна (HMENU)3, // идентификатор меню hInst, // идентификатор приложения NULL);
// указатель на дополнительные параметры
break; }
case WM_COMMAND: { switch (wParam) { case CM_FILENEW: { mdics.szClass = szChildClassName; // класс окна mdics.szTitle = "MDI Child Window"; // заголовок окна mdics.hOwner = hInst; // идентификатор приложения mdics.x = CW_USEDEFAULT; // размеры окна mdics.y = CW_USEDEFAULT; // Document Window mdics.cx = CW_USEDEFAULT; mdics.cy = CW_USEDEFAULT; mdics.style = 0; // дополнительные стили mdics.lParam = NULL; // 32-битное значение
// Посылаем сообщение WM_MDICREATE окну // Client Window. В результате будет создано новое // окно Document Window hwndChild = (HWND)SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)&mdics);
break; }
case CM_WINDOWTILE: { SendMessage(hwndClient, WM_MDITILE, 0, NULL);
break; } case CM_WINDOWCASCADE: { SendMessage(hwndClient, WM_MDICASCADE, 0, NULL);
break; } case CM_WINDOWICONS: { SendMessage(hwndClient, WM_MDIICONARRANGE, 0, NULL);
break; } case CM_WINDOWCLOSEALL: { HWND hwndTemp; ShowWindow(hwndClient, SW_HIDE);
for(;;) { hwndTemp = GetWindow(hwndClient, GW_CHILD);
if(!hwndTemp) break; while(hwndTemp && GetWindow(hwndTemp, GW_OWNER)) hwndTemp = GetWindow(hwndTemp, GW_HWNDNEXT);
if(hwndTemp) SendMessage(hwndClient, WM_MDIDESTROY, (WPARAM)hwndTemp, NULL);
else break; } ShowWindow(hwndClient, SW_SHOW);
break; } case CM_HELPABOUT: { MessageBox(hwnd, "Приложение MDIAPP\n(C) Фролов А.В., 1995", "Simple MDI Application", MB_OK | MB_ICONINFORMATION);
break; } case CM_FILEEXIT: { DestroyWindow(hwnd);
break; } default: break; }
HWND hwndChild = (HWND)LOWORD(SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0l));
if(IsWindow(hwndChild)) SendMessage(hwndChild, WM_COMMAND, wParam, lParam);
return DefFrameProc(hwnd, hwndClient, msg, wParam, lParam);
} case WM_DESTROY: { PostQuitMessage(0);
break; } default: break; } return DefFrameProc(hwnd, hwndClient, msg, wParam, lParam);
}
// ===================================== // Функция ChildWndProc // ===================================== LRESULT CALLBACK _export ChildWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rc; switch (msg) { case WM_PAINT: { hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
DrawText(hdc, "Child Window", -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
} default: break; } return DefMDIChildProc(hwnd, msg, wParam, lParam);
}
// ===================================== // Функция TbWndProc // ===================================== LRESULT CALLBACK _export TbWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rc; switch (msg) { case WM_PAINT: { hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
DrawText(hdc, "Toolbar Window", -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
} default: break; } return DefMDIChildProc(hwnd, msg, wParam, lParam);
}
// ===================================== // Функция SbWndProc // ===================================== LRESULT CALLBACK _export SbWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rc; switch (msg) { case WM_PAINT: { hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
DrawText(hdc, "Statusbar Window", -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
} default: break; } return DefMDIChildProc(hwnd, msg, wParam, lParam);
}
На этапе инициализации приложения функция InitApp регистрирует классы для окон Frame Window, Document Window, а также для окон Toolbar и Statusbar. Эта процедура не имеет никаких особенностей. Отметим только, что вы можете изменить форму курсора мыши для окна Toolbar, указав нужный идентификатор курсора в поле hCursor структуры WNDCLASS перед регистрацией класса, или задать цвет окна Toolbar.
Окна Toolbar и Statusbar создаются в функции окна Frame Window при обработке сообщения WM_CREATE:
hwndTb = CreateWindow( szTbClassName, // имя класса окна NULL, // заголовок окна WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_DLGFRAME, 0, 0, 0, 0, hwnd, // идентификатор родительского окна (HMENU)2, // идентификатор меню hInst, // идентификатор приложения NULL);
// указатель на дополнительные параметры hwndSb = CreateWindow( szSbClassName, // имя класса окна NULL, // заголовок окна WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_DLGFRAME, 0, 0, 0, 0, hwnd, // идентификатор родительского окна (HMENU)3, // идентификатор меню hInst, // идентификатор приложения NULL);
// указатель на дополнительные параметры
Обратите внимание, что для этих окон мы указали нулевые размеры, так как в момент их создания размеры внутренней области окна Frame Window еще неизвестны.
Вы можете указать для окон Toolbar и Statusbar любые стили, применимые к дочерним окнам. Для того чтобы эти окна появились на экране сразу после их создания, мы использовали стиль WS_VISIBLE.
Займемся теперь обработчиком сообщения WM_SIZE.
Прежде всего, он располагает окно Toolbar в верхней части внутренней области окна Frame Window, вызывая функцию MoveWindow:
MoveWindow(hwndTb, 0, // x-координата 0, // y-координата LOWORD(lParam), // ширина TBAR_SIZE, // высота TRUE);
// требуется перерисовка окна
Координаты верхнего левого угла окна Toolbar устанавливаются равными значению (0,0), поэтому верхний левый угол этого окна совмещается с верхним левым углом внутренней области окна Frame Window.
Для определения ширины окна Toolbar анализируется параметр lParam, который для сообщения WM_SIZE равен ширине внутренней области окна.
Высота окна Toolbar в нашем приложении задается константой TBAR_SIZE, которая определена в файле mditb.hpp (листинг 1.6).
Аналогичным образом устанавливаются координаты и размеры окна Statusbar:
MoveWindow(hwndSb, 0, // x-координата HIWORD(lParam) - SBAR_SIZE, // y-координата LOWORD(lParam), // ширина SBAR_SIZE, // высота TRUE);
// требуется перерисовка окна
Высота окна Statusbar задается константой SBAR_SIZE.
Затем мы проверяем, создано ли окно Client Window, и не свернуто ли оно в пиктограмму. Если с окном все в порядке, устанавливаем для него новое расположение и размеры, оставляя место для окон Toolbar и Statusbar:
if(wParam != SIZEICONIC && hwndClient) { MoveWindow(hwndClient, 0, // x-координата TBAR_SIZE, // y-координата LOWORD(lParam), // ширина HIWORD(lParam) - (TBAR_SIZE + SBAR_SIZE), // высота TRUE);
// требуется перерисовка окна return 0; } break;
Еще раз обращаем ваше внимание на то, что обработанное сообщение WM_SIZE нельзя отдавать функции DefFrameProc, поэтому после вызова функции MoveWindow мы выполняем возврат из функции окна оператором return.
При регистрации классов для окон Toolbar и Statusbar мы указали соответствующие функции окна. Эти функции определены в нашем приложении и называются TbWndProc (для окна Toolbar) и SbWndProc (для окна Statusbar). Эти функции полностью определяют поведение окон Toolbar и Statusbar, выполняя обработку предназначенных для них сообщений. В нашем случае мы просто рисуем в центре этих окон их названия, вызывая функцию DrawText.
В листинге 1.6 вы найдете файл mditb.hpp, содержащий определения констант для размеров окон Toolbar и Statusbar, а также для работы с меню.