3) После проделанных шагов Вы должны увидеть следующее:
Появившееся окно представляет собой редактор меню. В заголовке Вы видите название созданного меню MENU_1. В правом верхнем углу окна располагается поле TEST MENU, которое позволяет проверить работу создаваемого меню. Строка созданного меню содержит название раздела меню Pop-up (что означает всплывающий). При щелчке мышью на данном имени появляются пункты меню.
4) Нам нужно получить пункт меню с именем Size. Для этого щелкните мышью по имени Pop-up в поле тестирования меню, либо на том же имени в описании меню в правом нижнем углу окна. Далее, перейдите в поле Item text и переименуйте пункт меню из Pop-up в Size. Нажмите Enter и убедитесь, что поле тестирования отобразило переименованный пункт меню.
5) Нам требуется создать команду меню Small. Для этого в поле тестирования или в окне описания меню выберите пункт Item. В поле тестирования это делается выбором пункта Size и выбором в появившемся меню поля Item.
6) Убедитесь, что поле Item text действительно содержит текст “Item”. Перейдите в это поле и измените текст на “Small”. Проверьте, что в создаваемом меню отображается пункт Small.
7) В поле Item Id редактора меню введите имя константного идентификатора, который будет передаваться программе при выборе пункта меню Small. Пусть это будет CM_SIZE_SMALL (CM означает Command, команда).
8) Создадим теперь пункт меню Large. Для начала проверьте, что в окне описания меню выделен пункт меню Small, т. к. создаваемый нами новый пункт меню должен появиться под ним. Затем выполните команду меню редактора Menu|New menu item. Результатом работы команды будет новый пункт меню, который будет расположен под командой Small. С помощью описанных выше действий дайте пункту меню имя Large и впишите идентификатор команды CM_SIZE_LARGE.
Обратите внимание! Необходимо выбирать New menu item, а не New menu pop-up, который создает не команду, а пункт меню, который сам содержит свои команды и при активизации открывает вложенное в него меню.
9) Проверьте, что показывает поле тестирования созданного Вами меню.
На этом создание меню программы завершено. Закройте Workshop и ответьте Yes на предложение программы сохранить результат Вашей работы.
Необходимо также отметить, что в header-файл, имя которого Вы указали в начале построения проекта, будут помещены имена константных идентификаторов пунктов меню CM_SIZE_SMALL и CM_SIZE_LARGE, а также идентификатор меню MENU_1, на которые Вы будете ссылаться при написании программы.
7.2. Программирование с использованием меню
Нижеследующее приложение использует команды Small и Large для управления выводом на экран фигур разного размера.
Прежде, чем приводить текст программы покажем, что же мы получили в результате манипуляций над Resource Workshop.
7.2.1. Листинг rh-файла
/**************************************************************************
lab3с.rh
produced by Borland Resource Workshop
**************************************************************************/
#define MENU_1 1
#define CM_SIZE_SMALL 102
#define CM_SIZE_LARGE 101
7.2.2. Листинг rc-файла
/**************************************************************************
LAB3С.RC
produced by Borland Resource Workshop
**************************************************************************/
#include "lab3с.rh"
MENU_1 MENU
{
POPUP "Size"
{
MENUITEM "Small", CM_SIZE_SMALL
MENUITEM "Large", CM_SIZE_LARGE
}
}
Вообще rc-файл содержит в себе текстовое описание ресурсов и, как может показаться, легче написать его с помощью текстового редактора. Это верно только для простых файлов ресурсов. Для написания же больших программ лучше воспользоваться возможностями Resource Workshop.
7.2.3. Исходный текст приложения
#include <owl\applicat.h>
#include <owl\framewin.h>
#include <owl\dc.h>
#pragma hdrstop
#include "lab3а.rh"
class TMyWin : public TFrameWindow
{
public:
TPoint pn,pk;
TMyWin() : TFrameWindow(0,"The Paint function")
{
pn.x=100;
pn.y=50;
pk.x=300;
pk.y=200;
}
protected:
void Paint(TDC&,BOOL,TRect&);
void CmLarge();
void CmSmall();
DECLARE_RESPONSE_TABLE(TMyWin);
};
DEFINE_RESPONSE_TABLE1(TMyWin,TFrameWindow)
EV_COMMAND(CM_SIZE_LARGE,CmLarge),
EV_COMMAND(CM_SIZE_SMALL,CmSmall),
END_RESPONSE_TABLE;
void TMyWin::Paint(TDC &dc,BOOL,TRect&)
{
TColor color(TColor::LtBlue);
TPen pen1(color);
dc.SelectObject(pen1);
dc.Rectangle(pn,pk);
TPen pen2(TColor::LtGreen);
dc.SelectObject(pen2);
dc.Ellipse(pn,pk);
}
void TMyWin::CmLarge()
{
pk.x=500;
pk.y=400;
Invalidate();
}
void TMyWin::CmSmall()
{
pk.x=150;
pk.y=100;
Invalidate();
}
class TMyApp : public TApplication
{
public:
TMyApp():TApplication()
{}
void InitMainWindow()
{
MainWindow=new TMyWin();
MainWindow->AssignMenu(MENU_1);
}
};
int OwlMain(int, char *[])
{
TMyApp app;
return app.Run();
}
7.2.4. Пояснения к программе
Класс TMyWin содержит объявление членов-функций Paint, CmLarge, CmSmall.
Описание таблицы реакции показывает, что в ответ на выбор команды меню Small с идентификатором CM_SIZE_SMALL будет вызываться функция CmSmall. Аналогично для команды Large. При ее выборе будет вызвана CmLarge. Еще раз подчеркнем, что для команд меню нет стандартных функций отклика, как это было с системными сообщениями Windows, т. е. в макросе Вы можете указать имя любой функции отклика, главное, чтобы она не принимала и не возвращала значений.
Описание функции Paint целиком совпадает с ее текстом в предыдущем разделе.
Функции отклика на сообщения меню изменяют координаты правого нижнего угла прямоугольника и вызывают инкапсулированную в TFrameWindow функцию Invalidate, которая заставляет Windows обновить окно приложения. Вызов данной функции говорит системе, что окно требует обновления и та посылает приложению сообщение WM_PAINT.
7.3. Задание
1) Создать и выполнить приложение.
2) Удалите вызов функции Invalidate в одной из функций отклика. Объясните изменения в логике работы приложения.
3) Создайте дополнительное меню Color с командами Black и Red, которые должны изменять цвет выводимых на экране фигур.
8. Управляющие компоненты Windows
Рассмотрим несколько управляющих компонент Windows, облегчающих диалог с приложением.
Первый компонент - это линейка прокрутки. Она может быть расположена в окне приложения и представляет собой вертикальную или горизонтальную полосу с ползунком. Ползунок можно передвинуть, зацепив его указателем мыши и перетащив вдоль полосы прокрутки.
Линейка создается как объект класса TScrollBar в конструкторе окна приложения. Конструктору TScrollBar передаются координаты и размеры создаваемой линейки, а так же тип линейки - горизонтальная или вертикальная.
Покажем, как использовать в приложении вертикальную линейку прокрутки.
Во время перемещения ползунка вертикальная линейка генерирует уведомляющие сообщения WM_VSCROLL. Вы можете перехватить и обработать эти сообщения, объявив в классе-владельце такой линейки функцию отклика EvVScroll и дополнив таблицу отклика класса макросом EV_WM_VSCROLL. Функция будет вызываться при изменении положения ползунка на линейке.
При создании линейки присвойте адрес сконструированного объекта указателю. В результате Вы получите доступ к разнообразному набору функций объекта. К примеру, появится возможность позиционировать ползунок из программы, получать позицию ползунка и изменять масштаб линейки ( по умолчанию позиция ползунка на линейке изменяется от 0 до 100).
Все сказанное выше справедливо и для горизонтальной линейки прокрутки, но для реакции на ее сообщения требуется функция EvHScroll и макрос EV_WM_HSCROLL.
Теперь уделим внимание другому компоненту визуального интерфейса Windows - кнопке.
Кнопка может быть расположена в окне приложения и представляет собой прямоугольник с надписью. Кнопка реагирует на щелчки мышью выдачей уведомляющего сообщения. Она создается в конструкторе окна приложения, как объект класса TButton.
Конструктору TButton передается адрес объекта-окна, в котором Вы хотите разместить кнопку, текст надписи на кнопке, ее координаты и размер. Конструктору также передается константный идентификатор кнопки. Данный идентификатор совпадает с идентификатором уведомляющего сообщения, генерируемого кнопкой при нажатии.
Реакция на нажатия кнопки реализуется аналогично реакции на выбор команды меню: Вы описываете функцию реакции (имя функции произвольное) на нажатия кнопки и помещаете в таблицу реакции макрос
EV_COMMAND(BUTTON_ID,UserName)
с идентификатором кнопки и именем функции отклика.
Приложение может иметь несколько кнопок с различными идентификаторами и для каждой кнопки нужно создать свою функцию отклика и добавить элемент в таблицу реакций.
Если Вы хотите реагировать только на нажатия кнопки, никак не изменяя ее характеристик, то присваивать указателю адрес созданного объекта-кнопки не требуется.
8.1. Изменение размера выводимой графики с помощью линейки прокрутки
В нижеследующем приложении в прикладном окне выдается голубой прямоугольник с вписанным в него эллипсом. В окне создается вертикальная линейка прокрутки. Перемещая ползунок линейки, можно плавно изменять размеры выводимых геометрических фигур в некотором фиксированном диапазоне.
8.1.1. Исходный текст программы
#include <owl\applicat.h>
#include <owl\framewin.h>
#include <owl\dc.h>
#include <owl\scrollba.h>
class TMyWin : public TFrameWindow
{
public:
TPoint pn,pk;
TScrollBar *sb;
TMyWin() : TFrameWindow(0,"The Paint function")
{
sb=new TScrollBar(this,1,350,100,20,125,FALSE);
pn.x=100;
pn.y=40;
pk.x=300;
pk.y=pn.y;
}
protected:
void Paint(TDC&,BOOL,TRect&);
void EvVScroll(UINT, UINT, HWND);
DECLARE_RESPONSE_TABLE(TMyWin);
};
DEFINE_RESPONSE_TABLE1(TMyWin,TFrameWindow)
EV_WM_VSCROLL,
END_RESPONSE_TABLE;
void TMyWin::Paint(TDC &dc,BOOL,TRect&)
{
TColor color(TColor::LtBlue);
TPen pen1(color);
dc.SelectObject(pen1);
dc.Rectangle(pn,pk);
TPen pen2(TColor::LtGreen);
dc.SelectObject(pen2);
dc.Ellipse(pn,pk);
}
void TMyWin::EvVScroll(UINT scrollcode, UINT thumbPos, HWND hwnd)
{
TFrameWindow::EvVScroll(scrollcode,thumbPos,hwnd);
InvalidateRect(TRect(pn,pk));
pk.y=pn.y+sb->GetPosition()*2;
UpdateWindow();
}
class TMyApp : public TApplication
{
public:
TMyApp():TApplication()
{}