Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Programming_Windows_95_Part_II.pdf
Скачиваний:
41
Добавлен:
05.06.2014
Размер:
3.02 Mб
Скачать

170

idFirstChild является идентификатором меню, относящимся к первому окну документа в списке документов.

Он просто равен IDM_FIRSTCHILD.

Вернемся к WinMain. Программа MDIDEMO выводит на экран только что созданное главное окно и входит в цикл обработки сообщений. Этот цикл обработки сообщений немного отличается от обычного: после получения сообщения из очереди при помощи функции GetMessage программа MDI передает сообщение функции TranslateMDISysAccel (и функции TranslateAccelerator, если, как и в программе MDIDEMO, в программе также имеются быстрые клавиши меню).

Функция TranslateMDISysAccel преобразует любые комбинации клавиш, которые могут соответствовать специальным быстрым клавишам MDI (например, <Ctrl>+<F6>), в сообщение WM_SYSCOMMAND. Если одна из функций TranslateMDISysAccel или TranslateAccelerator возвращает TRUE (что означает, что сообщение было преобразовано одной из этих функций), то вызова функции TranslateMessage и функции DispatchMessage не происходит.

Обратите внимание на два описателя окон, передаваемые функциям TranslateMDISysAccel и TranslateAccelerator: соответственно hwndClient и hwndFrame. Функция WinMain получает описатель окна hwndClient, используя вызов функции GetWindow с параметром GW_CHILD.

Создание дочерних окон

Часть FrameWndProc связана с обработкой сообщений WM_COMMAND, которые информируют о выборе какоголибо пункта меню. Как обычно, параметр wParam сообщения в FrameWndProc содержит идентификатор меню.

При значениях параметра wParam IDM_NEWHELLO и IDM_NEWRECT, FrameWndProc должна создать новое окно документа. Это требует инициализации полей структуры MDICREATESTRUCT (большая часть которых соответствует параметрам функции CreateWindow) и отправки окну-администратору сообщения WM_MDICREATE с параметром lParam, равным указателю на эту структуру. Затем окно-администратор создает дочернее окно документа. FrameWndProc, вызывая функцию CreateMDIWindow, могла бы сама создать это дочернее окно. Для программы, имеющей один поток, такой как MDIDEMO, можно выбрать любой из этих методов.

Как правило, поле szTitle структуры MDICREATESTRUCT является именем файла, соответствующего документу. В поле style могут быть заданы стили окна WS_HSCROLL, или WS_VSCROLL, или оба вместе, что позволяет включить в окно документа полосы прокрутки. (Функцию ShowScrollBar для вывода полос прокрутки на экран вызывать не обязательно.) В поле style могут быть также указаны стили WS_MINIMIZE или WS_MAXIMIZE для первого появления окна документа в свернутом или развернутом состоянии.

Поле lParam структуры MDICREATESTRUCT дает возможность главному и дочернему окну использовать некоторые общие переменные. Этому полю можно присвоить значение описателя памяти, соответствующего блоку памяти, содержащему структуру. При обработке сообщения WM_CREATE в дочернем окне документа, параметр lParam — это указатель на структуру CREATESTRUCT, а поле lpCreateParams этой структуры — это указатель на структуру MDICREATESTRUCT, используемую для создания окна.

При получении сообщения WS_MDICREATE окно-администратор создает дочернее окно документа и добавляет заголовок окна к нижней части подменю, заданного в структуре MDICREATESTRUCT, которая используется для создания окна-администратора. Когда программа MDIDEMO создает свое первое окно документа, этим подменю является подменю File меню MdiMenuInit. Позже мы увидим, как этот список документов переносится в подменю

Window меню MdiMenuHello и MdiMenuRect.

В меню может быть перечислено до девяти документов, перед каждым из которых ставится номер от 1 до 9. Номер подчеркивается. Если создается более девяти окон документов, то за этим списком появляется пункт меню "More windows". Выбор этого пункта вызывает появление окна диалога содержащего список, в котором перечислены все окна документов. Поддержка такого списка документов — это одно из самых лучших характеристик поддержки

MDI в Windows 95.

Дополнительная информация об обработке сообщений в главном окне

Перед тем, как перейти к рассмотрению дочерних окон документов, разберемся с обработкой сообщений в

FrameWndProc.

При выборе в меню File опции Close программа MDIDEMO закрывает активное дочернее окно. Описатель активного дочернего окна она получает, посылая окну-администратору сообщение WM_MDIGETACTIVE. Если дочернее окно отвечает утвердительно на сообщение WM_QUERYENDSESSION, то программа MDIDEMO для закрытия дочернего окна посылает окну-администратору сообщение WM_MDIDESTROY.

Для обработки опции Exit меню File необходимо только, чтобы оконная процедура главного окна послала себе сообщение WM_CLOSE.

171

Обработать опции Tile, Cascade и Arrange Icons из подменю Window проще простого, нужно только послать окну-

администратору сообщения WM_MDITILE, WM_MDICASCADE и WM_MDIICONARRANGE.

Обработка опции Close All несколько сложнее. FrameWndProc вызывает функцию EnumChildWindows, передавая указатель на функцию CloseEnumProc. Эта функция посылает сообщение WM_MDIRESTORE каждому дочернему окну, затем сообщение WM_QUERYENDSESSION и (возможно) сообщение WM_MDIDESTROY. Этого не делается для окна заголовка значка, определяемого, если возвращаемое значение функции GetWindow c параметром GW_OWNER не равно NULL.

Обратите внимание, что FrameWndProc не обрабатывает ни одного сообщения WM_COMMAND, которые сигнализируют о том, что в меню Color выбран один из цветов. Эти сообщения относятся сфере ответственности окна документа. По этой причине FrameWndProc посылает все необрабатываемые сообщения WM_COMMAND активному дочернему окну, следовательно, дочернее окно может обработать те сообщения, которые относятся к нему.

Все сообщения, которые оконная процедура главного окна не обрабатывает, должны передаваться в DefFrameProc. Эта функция заменяет в оконной процедуре главного окна функцию DefWindowProc. Даже если оконная процедура главного окна и перехватывает сообщения WM_MENUCHAR, WM_SETFOCUS или WM_SIZE, все равно они должны передаваться в DefFrameProc.

Необрабатываемые сообщения WM_COMMAND также должны передаваться в DefFrameProc. В частности, FrameWndProc не обрабатывает сообщений WM_COMMAND, появившихся в результате того, что пользователь выбирает один из документов из списка в подменю Window. (Значение параметра wParam для этих опций начинается с IDM_FIRSTCHILD.) Эти сообщения передаются в DefFrameProc и обрабатываются там.

Обратите внимание, что главному окну не нужно поддерживать список описателей окон всех созданных документов. При необходимости (например, при обработке опции Close All из меню), эти описатели можно получить, вызывая функцию EnumChildWindows.

Дочерние окна документов

Теперь рассмотрим HelloWndProc — оконную процедуру тех дочерних окон документов, которые выводят на экран фразу "Hello, World!".

Как и для любого класса окна, который используется более, чем для одного окна, статические переменные, определенные в оконной процедуре (как и в любой функции, вызываемой из оконной процедуры), совместно используются всеми окнами, созданными на основе этого класса окна.

Данные, уникальные для каждого окна, должны храниться в форме, отличной от статических переменных. Один из таких приемов подразумевает применение свойств окна. При другом подходе (реализованном в программе) используется область памяти, зарезервированная путем определения отличного от нуля значения в поле cbWndExtra структуры WNDCLASSEX, используемой при регистрации класса окна.

В программе MDIDEMO эта область предназначена для хранения указателя на блок памяти размером со структуру HELLODATA. HelloWndProc выделяет эту память при обработке сообщения WM_CREATE, инициализирует оба поля (обозначающие помеченный в данный момент контрольной меткой пункт меню и цвет символов) и с помощью функции SetWindowLong запоминает указатель на блок памяти.

При обработке сообщения WM_COMMAND, связанного с изменением цвета символов (вспомните, что это сообщение сначала появляется в оконной процедуре главного окна), HelloWndProc задействует функцию GetWindowLong для получения указателя на блок памяти, содержащий структуру HELLODATA. Используя эту структуру, HelloWndProc снимает пометку с помеченного ранее пункта меню, ставит ее к выбранному пункту, и запоминает новый цвет.

Оконная процедура окна документа получает сообщение WM_MDIACTIVATE всегда, когда окно становится активным или перестает быть активным (в зависимости от того, содержится ли описатель окна в параметре lParam этого сообщения). Вспомните, что в программе MDIDEMO имеется три различных меню: MdiMenuInit выводится, если нет ни одного окна документа, MdiMenuHello выводится, если активно окно документа Hello, и MdiMenuRect выводится, если активно окно документа с прямоугольниками.

Сообщение WM_MDIACTIVATE дает возможность окну документа изменить меню. Если в параметре lParam этого сообщения содержится описатель окна (означающий, что окно становится активным), HelloWndProc изменяет меню на MdiMenuHello. Если в параметре lParam этого сообщения содержится описатель другого окна, HelloWndProc преобразует меню в MdiMenuInit.

HelloWndProc изменяет меню путем отправки сообщения WM_MDISETMENU окну-администратору. Окноадминистратор обрабатывает это сообщение, удаляя список документов из текущего меню и присоединяя его к новому меню. Таким образом список документов попадает из меню MdiMenuInit (которое является результатом

172

создания первого документа) в меню MdiMenuHello. Не используйте для изменения меню в приложении MDI функцию SetMenu.

Другая небольшая проблема связана с пометкой в подменю Color. Такие опции программы как эта, должны быть уникальны для каждого документа. Например, необходимо иметь возможность задать для одного окна документа черный цвет символов, а для другого — красный. Пометка в меню должна отражать выбранную в активном окне опцию. По этой причине HelloWndProc удаляет пометку выбранного пункта меню, когда окно перестает быть активным и ставит ее у соответствующего пункта, когда окно становится активным.

Значения параметров wParam и lParam сообщения WM_MDIACTIVATE являются, соответственно, описателями окна, которое перестает быть активным, и окна, становящегося активным. Оконная процедура получает первое сообщение WM_MDIACTIVATE с параметром lParam равным описателю текущего окна, когда это окно впервые создается, а когда окно закрывается, она получает последнее сообщение WM_MDIACTIVATE с параметром lParam равным другому значению. Когда пользователь переключается с одного документа на другой, первое окно документа получает сообщение WM_MDIACTIVATE с параметром lParam равным описателю первого окна (в это время оконная процедура устанавливает меню в MdiMenuInit). Второе окно документа получает сообщение WM_MDIACTIVATE с параметром wParam равным описателю второго окна (в это время оконная процедура устанавливает меню либо в MdiMenuHello, либо в MdiMenuRect, в зависимости от описателя). При закрытии всех окон документов остается только меню MdiMenuInit.

Вспомните, что FrameWndProc посылает дочернему окну асинхронное сообщение WM_QUERYENDSESSION, когда пользователь выбирает в меню опцию Close или Close All. HelloWndProc обрабатывает сообщения WM_QUERYENDSESSION и WM_CLOSE, выводя на экран окно сообщений с запросом пользователю о том, можно ли закрывать окно. (В реальной программе в этом окне сообщений может появляться запрос о том, нужно ли сохранять файл.) Если пользователь выбирает опцию, соответствующую тому, что окно закрывать не следует, оконная процедура возвращает 0.

При обработке сообщения WM_DESTROY, HelloWndProc освобождает блок памяти, выделенный при обработке сообщения WM_CREATE.

Все необрабатываемые сообщения должны передаваться в DefMDIChildProc (а не в DefWindowProc) для их обработки по умолчанию. Некоторые сообщения должны быть переданы в DefMDIChildProc независимо от того, обрабатываются ли они как-нибудь в оконной процедуре или нет. Такими сообщениями являются: WM_CHILDACTIVATE, WM_GETMINMAXINFO, WM_MOVE, WM_SETFOCUS, WM_SIZE, WM_MENUCHAR и WM_SYSCOMMAND.

RectWndProc почти полностью аналогична HelloWndProc, но она несколько проще (нет опции меню для выбора цвета, и окно может быть закрыто без запроса разрешения на закрытие у пользователя), поэтому нет смысла ее специально рассматривать. Но, тем не менее, обратите внимание, что RectWndProc прерывает обработку сообщения WM_SIZE, и оно передается в DefMDIChildProc.

Освобождение захваченных ресурсов

Программа MDIDEMO в функции WinMain использует функцию LoadMenu для загрузки трех меню, определенных в файле описания ресурсов. Обычно Windows удаляет меню, когда закрывается окно, к которому меню относится. Это касается и меню MdiMenuInit. Однако, меню, не относящиеся к какому бы то ни было окну (в программе MDIDEMO это меню Hello и Rect), будут продолжать занимать некоторую область памяти, даже после завершения программы. Поэтому, для освобождения памяти, занимаемой меню Hello и Rect, в программе MDIDEMO функция

DestroyMenu в WinMain вызывается дважды.

Сила оконной процедуры

Большая часть того, что в Windows 95 создано для поддержки многооконного интерфейса, заключено в классе окна MDICLIENT. В этом совершенно отчетливо проявляется сила объектно-ориентированной архитектуры Windows. Оконная процедура окна-администратора служит, как бы, связующим звеном между главным окном и различными окнами документов.

Теперь рассмотрим другое мощное средство Windows — динамически подключаемые библиотеки.

Соседние файлы в предмете Операционные системы