Меню главного окна приложения описывается, как обычно, в файле ресурсов.rс. Значения идентификаторов пунктов меню (имена идентификаторов могут быть любыми) определены в файле.h. Для пункта выхода из приложения использован стандартный идентификатор СМ_ЕХIТ (со значением 24310), описанный в файле window.rh. С таким же успехом можно было использовать другое обозначение (например, CM_QUIT) или присвоить идентификатору СМ_ЕХIТ произвольное значение.
Для того, чтобы меню появилось в окне приложения, достаточно вызвать функцию AssignMenu(), принадлежащую классу TFrameWindow, с указанием в качестве параметра имени меню из файла ресурсов; этот вызов удобнее всего выполнить в
конструкторе класса MyWindow. Как и в случае API Windows, обработку сообщений от "корневых" пунктов меню (в нашем случае это пункты "Файл" и "Графики") Windows берет на себя: при выборе этих пунктов Windows отображает на экране соответствующие всплывающие меню (рис. 27.3). Нам же надо обрабатывать сообщения от пунктов всплывающих меню (их часто называют командами
меню), для чего необходимо включить в таблицу откликов сообщения EV_COMMAND - по одному на каждую команду меню (обратите внимание на отсутствие в обозначении сообщения EV_COMMAND префикса WM).
В отличие от макросов типа EV_WM_TIMER или EV_WM_GETMINMAXINFO, которые при расширении задают имена функций отклика, макрос EV_COMMAND требует указания двух параметров -идентификатора соответствующего пункта меню и имени прикладной функции отклика, предназначенной для обработки сообщения от этого пункта:
EV_COMMAND(CM_ABOUT,CmAbout), EV_COMMAND(CM_SIN,CmSin),...
Обычно функциям отклика назначают имена, схожие с идентификаторами (например, CmAbout для пункта меню с идентификатором CM_ABOUT), однако это не обязательно. Разумеется, для всех включенных в программу функций отклика необходимо объявить их прототипы (в составе класса MyWindow) и определить содержание самих функций. Исключение составляет команда "Выход". Если для этого пункта меню использовать стандартный идентификатор СМ_ЕХIТ, то всю обработку команды пользователя на завершение программы берет на себя Windows. Таким образом, для пункта меню с идентификатором CM_EXIT не надо иметь ни функции отклика, ни даже макроса EV_COMMAND в составе таблицы откликов (разумеется, лишь в том случае, если выбором этого пункта меню мы хотим именно завершить программу).
Содержательная часть примера 27-2 относительно проста. В классе MyWindow объявляются два массива чисел с плавающей точкой типа double для записи в них таблиц значений тригонометрических функций sin(x) и cos(x), которые затем будут выведены на экран в виде точечных графиков. Булевы переменные sinIs и cosIs служат в качестве флагов, индицирующих наличие в этих массивах достоверных данных. В функциях отклика CmSin() и CmCos() вычисляются таблицы синуса и косинуса, устанавливаются флаги достоверности данных и вызовом функции Invalidate() инициируется посылка в приложение сообщения WM_PAINT. В функции Paint() отклика на это сообщение на экран выводится сначала ось X (на расстоянии 150 пикселов от верхнего края окна), а затем графики тригонометрических функций с предварительной проверкой для каждой функции состояния флага достоверности. Для наглядности каждому графику назначается свой цвет.
Команда меню "О программе" служит, как обычно, для вывода на экран окна (в нашем примере -стандартного окна сообщения) с информацией о данном программном продукте. Для улучшения внешнего вида окна сообщения (рис. 27.4) в замещенную нами функцию InitMainWindow() включен вызов функции EnableBWCC() класса TApplication, которая загружает библиотеку BWCC (Borland Windows Custom Controls).
В рассматриваемом примере не предусмотрено какого-либо "управления" графиками - после первого выполнения команд "Синус" или "Косинус" они остаются как в памяти, так и на экране. В этом случае не было необходимости вычислять их заново при каждом выполнении функции Paint(); заполнить массивы
250 Глава 27
sine[] и cosine[] можно было на этапе инициализации, например, в конструкторе MyWindow. В следующем примере, где предусмотрен вывод любой комбинации графиков по желанию, их вычисление в функции Paint() становится более оправданным.