Действия с объектами меню

Базовые операции с меню, рассмотренные в предыдущем примере, не требовали использо­вания классов меню, определен­ных в библиотеке OWL - доста­точно было установить меню с помощью функции AssignMenu() и предусмотреть таблицу и функ­ции откликов на команды меню.


Если же в программу желательно включить элементы динамического управления меню, такие, как до­бавление, удаление или модификация команд меню (прикладного или системного), добавление к пунк­там меню маркеров, гашение недоступных пунктов, вывод меню в произвольное место окна и др., то следует обратиться к классам меню библиотеки OWL. В OWL описаны три класса меню - класс TMenu, в котором определено большинство функций, требуемых для работы с меню, класс TSystemMenu, назна­чение которого видно из названия, и класс TPopupMenu для работы со всплывающими меню. В примере 27-3 будет продемонстрировано использование классов TMenu и TPopupMenu.

Пример 27-3 является развитием предыдущего. В меню "Графики" добавлены команды для вывода на экран еще двух тригонометрических функций - sin(x)/x и cos(x)/x. Предусмотрена возможность ото­бражения на экране любого сочетания четырех доступных графиков, причем вывод графика сопровожда­ется появлением маркера перед соответствующей командой меню, а вторичный выбор этой команды га­сит как маркер, так и сам график. Щелчком правой клавиши мыши активизируется плавающее меню, в котором можно выбрать масштаб вывода графиков. На рис. 27.5 показан вывод приложения 27-3 в одном из вариантов.

/ /Приложение 27-3. Действия с объектами меню

//Файл 27-3.rс

//Отличается от примера 27-2 увеличением числа команд (до 4) в пункте "Графики"

//Файл 27-3.h #define CM_ABOUT 101 #define CM_SIN 102 #define CM_COS 103


Обработка сообщений Windows 251

#define CM_SINX 104

#define CM_COSX 105 #define CM_200 106 #define CM_100 107 #define CM_50 108

//Файл 27-3.cpp

#include <owl\framewin.h>

#include "27-3.h"

#include <math.h>

/*Класс приложения, производный от Tappllication*/

class MyApp:public TApplication{

public:

void InitMainWindow(); //Замещаем функцию InitMainWindow

};

/*Класс главного окна, производный от TframeWindow*/ class MyWindow:public TFrameWindow{

double sine[640],cosine[640],sinX[640],cosX[640]; //Массивы данных для 4 графиков

bool sinIs,cosIs,sinXIs,cosXIs; //Индикаторы наличия данных для 4 графиков

int k; //Масштаб по оси у

TMenu* menu;// Объявляем указатель на объект основного меню

TPopupMenu popupMenu; //Создаем объект плавающего меню

virtual void SetupWindow(); //Замещаем функцию TWindow.: SetupWindow ()

virtual void CleanupWindow(); //Замещаем фукнцию TWindow::CleanupWindow ()

void Paint(TDC&,bool,TRect&); //Переопределяем функцию Paint

void CmAbout(); //Функции

void CmSin(); //откликов

void CmCos(); // на команды

void CmSinX(); //основного меню

void CmCosX(); //Функции

void Cm200(); //откликов

void Cm100(); // на команды

void Cm50(); //плавающего меню

void EvRButtonDown(UINT,TPoint&); public:

MyWindow(TWindow*parent,const char far* title); //Конструктор

DECLARE_RESPONSE_TABLE(MyWindow); //Объявляем таблицу откликов

}; DEFINE_RESPONSE_TABLE1(MyWindow,TFrameWindow)// Описываем таблицу откликов

EV_COMMAND(CM_ABOUT,CmAbout), Макросы

EV_COMMAND(CM_SIN,CmSin), для откликов

EV_COMMAND(CM_COS,CmCos), на пункты

EV_COMMAND(CM_SINX,CmSinX), основного

EV_COMMAND(CM_COSX,CmCosX), меню

EV_COMMAND(CM_200,Cm200), Макросы для откликов

EV_COMMAND(СМ_100,Cml00), на пункты

EV_COMMAND(СМ_50,Сm50), плавающего меню

EV_WM_RBUTTONDOWN,

END_RESPONSE_TABLE; //Завершаем таблицу откликов /*Конструктор класса MyWindow*/ MyWindow::MyWindow(TWindow*parent,const char far* title):TframeWindow

(parent,title){

AssignMenu("MainMenu");//Загрузка меню из файла приложения

sinIs=false; cosIs=false; sinXIs=false; cosXIs=false; //Начальные значения

//индикаторов

k=100; // Начальное значение масштаба

popupMenu.AppendMenu(MF_STRING,CM_200,"1.0=200 пикселов");/ /Формируем

popupMenu.AppendMenu(MF_STRING,CM_100,"1.0=100 пикселов"); //плавающее

popupMenu.AppendMenu(MF_STRING,CM_50,"1.0=50 пикселов"); //меню из 3 пунктов

}

/*3амещенная функция SetupWindow*/ void MyWindow::SetupWindow(){

TWindow::SetupWindow(); //Вызываем замещенную функцию SetupWindow

menu=new TMenu(HWindow); //Образуем объект класса TMenu

}

/*3амещенная функция CleanupWindow()*/ void MyWindow::CleanupWindowО{

delete menu;//Удаляем созданный ранее объект меню

TWindow::CleanupWindow();//Вызываем исходную функцию

}


252. Глава27

/*Функции откликов на сообщения*/

void MyWindow::CmAbout(){

MessageBox("Демонстрация математических функций","О программе",

MB_ICONINFORMATION); } void MyWindow::CmSin(){

int state=menu->GetMenuState(CM_SIN,MF_BYCOMMAND);

if(state==MF_UNCHECKED) (//Если этот пункт меню не выбран

for(int i=0;i<640;i++)/ /Образовать

sine[i]=sin((double)i/20);/ /массив данных

sinIs=true; //Установить индикатор наличия данных

menu->CheckMenuItem(CM_SIN,MF_CHECKED); //Пометить команду меню

Invalidate();/ /Инициировать перерисовку окна

} else{//Если этот пункт меню уже выбран

for(int i=0;i<640;i++) //Очистить

sine[i]=0; //массив данных

sinIs=false; //Сбросить индикатор наличия данных

menu->CheckMenuItem(CM_SIN,MF_UNCHECKED); //Снять маркер

Invalidate(); //Перерисовать окно (без этого графика)

} } /*Функции CmCos(), CmSinX(), CmCosX() имеют аналогичное содержимое*/

void MyWindow::Cm200() {//Устанавливаем 200 точек на 1 k=200; Invalidate();// Перерисовываем

void MyWindow::Cm100() {//Устанавливаем 100 точек на 1

k=100;

Invalidate();// Перерисовываем

] void MyWindow::Cm50(){//Устанавливаем 50 точек на 1

к=50;

Invalidate();// Перерисовываем

} void MyWindow::EvRButtonDown(UINT,TPoint& point){

TRect rect;

GetWindowRect(rect); //Получим текущие координаты главного окна

point+=rect.TopLeft(); //Смещаем точку вывода меню

popupMenu.TrackPopupMenu(TPM_LEFTALIGN,point,0,HWindow);/ /Отобразим

//плавающее меню

}

/*3амещающая функция I ni tMainWindow() */ void MyApp::InitMainWindow(){

MyWindow* myWin=new MyWindow(0,"Программа 27-3");

SetMainWindow(myWin);

EnableBWCC(); //Разрешаем загрузку и использование BWCC.DLL

] '

void MyWindow::Paint (TDC&dc,bool,TRect&) { ...//Аналогично примеру 27-2, но выводятся 4 графика

} /*Главная функция приложения OwlMain*/

int OwlMain(int,char*[]){

return MyApp().Run();

}

Поскольку содержательные части двух последних примеров совпадают, ниже будут описаны только принципиальные отличия приложения 27-3 от предыдущего.

В классе MyWindow объявляется указатель menu на объект класса TMenu для добавления в меню маркеров, а также объект popupMenu класса TPopupMenu для образования плавающего меню, активизи­руемого щелчком правой клавиши мыши. Объект класса TMenu еще предстоит создать; это удобно вы­полнить в замещенной функции SetupWindow() класса TFrameWindow. Функции с именем SetupWindow входят во многие классы, описывающие различные окна (TWindow, TFrameWindow, TButton, TDialog и -др.); все они замещают исходную виртуальную функцию SetupWindow() класса TWindow и служат для выполнения необходимых для данного класса инициализирующих действий. Замещение функции Set-upWindow() в прикладном классе позволяет добавить к системным инициализирующим действиям соб­ственные. При этом, как правило, в замещающей функции необходимо сначала вызвать замещенную, и лишь затем выполнять прикладную инициализацию. Так и сделано в нашем примере (см. определение функции MyWindow::SetupWindow()).


Обработка сообщений Windows 253

Выделив "своими руками" память под объект, мы должны ее сами же и освободить; для этого мы за­мещаем еще и функцию CleanupWindow() класса TWindow. В замещающей функции мы сначала удаляем созданные ранее объект с указателем menu, а затем вызываем исходную, замещенную функцию (см. оп­ределение функции MyWindow::CleanupWindow()).

В таблицу откликов, входящую в класс MyWindow, включены макросы EV_COMMAND как для всех ' пунктов основного меню (CM_ABOUT, CM_SIN и др.), так и для плавающего меню задания масштаба (СМ_200, СМ_100 и СМ_50). Соответствующие функции обработки сообщений (Сm200 и др.) объявле­ны выше. В программе также предусмотрена обработка сообщений от правой клавиши мыши (макрос EV_WM_RBUTTONDOWN и функция с предопределенным именем EvRButtonDown()).

Образование плавающего меню распадается на два этапа. В конструкторе класса MyWindow мы за­полняем объявленный ранее и пока пустой объект popupMenu класса TPopupMenu конкретными строка­ми команд. Это делается с помощью функции AppendMenu() класса TMenu (от которого класс TPopup­Menu является производным), в параметрах которой указывается тип каждого пункта меню (MF_STRING, текстовая строка), идентификатор и конкретный текст. Второй этап - активизация пла­вающего меню, т.е. вывод его на экран, осуществляется в функции EvRButtonDown() обработки сообще­ний от правой клавиши мыши. Здесь вызывается функция TrackPopupMenu() класса TPopupMenu, кото­рой передается флаг позиционирования меню TPF_LEFTALIGN (задается положение левого края меню), конкретные координаты (переменная point) и дескриптор окна-владельца, в качестве которого использу­ется открытый член класса TWindow HWindow, который получает свое значение (равное, между прочим, NULL) в процессе создания главного окна. Вместе с сообщением WM_RBUTTONDOWN в программу поступают текущие координаты курсора мыши относительно рабочей области окна приложения, однако функция TrackPopupMenu() выводит плавающее меню в координатах всего экрана. Для смещения меню к нашему окну в функции EvRButtonDown() объявляется прямоугольник rect класса TRect, вызовом функ­ции GetWindowRect() в него засылаются текущие координаты окна приложения, и переменная point должным образом корректируется.

Для сокращения текста приложения в нем не предусмотрена маркировка выбранного в плавающем меню пункта, что, разумеется, снижает наглядность использования этого меню (рис. 27.6).

Для маркировки команд меню "Графики" используется созданные ранее указатель menu на основное меню главного окна. Сама маркировка (а также ее снятие) осуществляется в функциях обработки сооб­щений от команд этого меню CmSin(), CmCos() и др. С помощью функции GetMenuState() программа по­лучает состояние пункта меню, по которому произведен щелчок левой клавишей мыши, и если этот пункт не помечен маркером, то вычисляется таблица значений соответствующей тригонометрической функции, устанавливается флаг индикации готовности данных, с помощью функции CheckMenuItem() данный пункт меню помечается маркером-галочкой и, наконец, вызовом функции Invalidate() иницииру­ется перерисовывание всего окна.

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


Глава 28 Диалоговые окна


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow