- •Объекты и события в turbo vision.
- •Глава 1. Объекты TurboVision.
- •Глава 2. События.
- •Глава 3. Взаимодействие видимых элементов.
- •Введение
- •Глава 1. Объекты turbo vision.
- •Иерархия объектов TurboVision. Принципы построения иерархии.
- •Примитивные типы объектов. Система координат TurboVision.
- •Видимые элементы.
- •Взаимосвязи между видимыми элементами.
- •Поля State и Options.
- •Выбор и активизация видимых элементов.
- •Глава 2. События.
- •Чтение ввода пользователя.
- •Виды событий.
- •События-сообщения. Команды. Разрешение и запрещение команд.
- •Запись события. Тип tEvent.
- •Цикл событий. Функция Execute.
- •Методы GetEvent и PutEvent. Централизация сбора событий.
- •Обработка событий. Метод HandleEvent.
- •Маршрутизация событий. Переменные FocusedEvents и PositionalEvents. Поле EventMask.
- •Глава 3. Взаимодействие видимых элементов.
- •Посредники.
- •Сообщения между видимыми элементами.
- •3. Кто обрабатывает общие сообщения.
- •4. Вызов процедуры HandleEvent.
3. Кто обрабатывает общие сообщения.
Предположим, вам требуется определить, находится ли на панели экрана открытое окно, прежде чем выполнить некоторые действия. Как это сделать? Ваш код должен послать общее событие, на которое окна знают как ответить. «Подпись», оставленная объектом, который обработал это событие, будет говорить, кто (если есть) обработал его.
Конкретный пример: в IDE TurboPascal (Интегрированная Среда Разработки TurboPascal), если пользователь запрашивает открыть окно просмотра, код, который открывает окно просмотра, должен проверить, не открыто ли оно. Если нет, то открывает его; если есть, то переносит наверх.
Передача общего сообщения проста:
AreYouThere := Message(DeskTop, evBroadcast, cmFindWindow, nil);
В методе HandleEvent окна просмотра есть проверка на отклик (очистка события) на команду cmFindWindow:
case Event.What of
…
cmFindWindow : ClearEvent(Event);
…
end; .
Вспомним, что ClearEvent не только устанавливает поле What записи события в evNothing, no также устанавливает поле InfoPtr в @Self. Message читает эти поля и, если событие было обработано, возвращает указатель на объект, обработавший событие-сообщение. В данном случае это окно просмотра. Так, за строкой, которая посылала сообщение, следует:
if AreYouThere = nil then CreateWatchWindow
else AreYouThere^.Select; .
Поскольку окно просмотра — это единственный объект, который знает, как отвечать на общее сообщение cmFindWindow, можно быть уверенным, что когда код выполнится, будет одно и только одно окно просмотра на вершине всех видимых элементов на панели экрана.
Используя технику, описанную ранее, вы также можете, например, определить, какое окно является верхним из видимых элементов его типа на панели экрана. Поскольку общее сообщение посылается каждому подэлементу модального видимого элемента в Z-порядке, первым получит сообщение верхний видимый элемент на панели экрана.
Рассмотрим ситуацию, возникающую в IDE, когда пользователь имеет окно просмотра, открытое на вершине панели экрана во время пошагового выполнения кода в окне редактора. Окно просмотра может быть активным окном (двойная рамка), но курсор выполнения кода в окне требует сохранения трассы выполняемого кода. Если на панели экрана открыто несколько окон редактора, они могут не перекрываться вообще, но IDE должен знать, какое из окон редактора предназначено для трассировки.
Ответ: конечно, самое верхнее окно редактора. Для того, чтобы определить, какое из окон «верхнее», IDE посылает общее сообщение, отклик на которое знают только окна редактора. Первое окно редактора, которое получает общее сообщение, и будет верхним; оно обработает событие, очищая его, и IDE узнает, какое окно использовать для трассировки кода, читая результат, возвращенный Message.
4. Вызов процедуры HandleEvent.
Bы также можете создать или модифицировать событие, а затем вызвать HandleEvent напрямую. Можно сделать три типа вызовов:
1. Bы можете иметь видимый элемент, вызывающий HandleEvent равного подэлемента прямо («равные» видимые элементы – это подэлементы с одним владельцем). Сообщение не передается другим видимым элементам. Оно идет прямо к этому HandleEvent, затем управление возвращается к вам.
2. Вы можете вызвать HandleEvent владельца. Событие будет затем распространяться вниз по цепочке видимых элементов. (Если вы вызываете HandleEvent из вашего собственного HandleEvent, ваш HandleEvent будет вызываться рекурсивно.) Управление передается вам после обработки события.
3. Bы можете вызвать HandleEvent видимого элемента из другой цепочки видимых элементов. Событие будет передаваться вниз по этой цепочке видимых элементов. Управление передается вам после обработки события.
Приложение.
Пример программы с использованием библиотеки TurboVision.
program Hello;
uses App, Objects, Menus, Drivers, Views, Dialogs;
const
cmGreetingBox = 200;
{Определение новой команды.}
type
THelloApp = object(TApplication)
{Определение нового типа объекта для обеспечения требуемой
функциональности.}
procedure GreetingBox;
{Определение нового метода, отсутствующего в типе TApplication.}
procedure HandleEvent(var Event: TEvent); virtual;
{Перекрытие HandleEvent для обработки новых событий.}
procedure InitStatusLine; virtual;
{Перекрытие InitStatusLine для инициализации строки статуса.}
procedure InitMenuBar; virtual;
{Перекрытие InitMenuBar для инициализации строки меню.}
end;
var
HelloWorld: THelloApp;
{Образование экземпляра объекта для выполнения.}
procedure THelloApp.GreetingBox;
{Процедура создания диалогового окна ‘Hello, World!’.}
var
R: TRect;
Dialog: PDialog;
Control: Word;
begin
R.Assign(0, 0, 37, 13); R.Move(20, 3);
{Назначение границ для диалогового окна.}
Dialog := New(PDialog, Init(R, 'Hello, World!'));
{Создание экземпляра объекта диалогового окна типа TDialog.}
with Dialog^ do {Вставка подэлементов в диалоговое окно.}
begin
R.Assign(4, 5, 16, 6); {Назначение границ подэлемента.}
Insert(New(PStaticText, Init(R, 'How are you?')));
{Создание и вставка объекта статического текста.}
R.Assign(20, 3, 32, 5);
Insert(New(PButton, Init(R, '~T~errific', cmOK, bfNormal)));
{Создание и вставка объекта кнопки.}
R.Assign(20, 6, 32, 8);
Insert(New(PButton, Init(R, '~O~K', cmOK, bfDefault)));
R.Assign(20, 9, 32, 11);
Insert(New(PButton, Init(R, '~C~ancel', cmCancel, bfNormal)));
end;
Control := DeskTop^.ExecView(Dialog);
{Вставка диалогового окна в панель экрана для модального
выполнения.}
Dispose(Dialog, Done);
{Освобождение памяти, занимаемой объектом диалогового окна, после
его выполнения.}
end;
procedure THelloApp.HandleEvent(var Event: TEvent);
begin
TApplication.HandleEvent(Event); {Наследуемый HandleEvent.}
if Event.What=evCommand then
begin
case Event.Command of
cmGreetingBox : GreetingBox;
{Определение реакции на команду cmGreetingBox.}
else
Exit;
end;
ClearEvent(Event);
{Очистка события после выполнения процедуры GreetingBox.}
end;
end;
procedure THelloApp.InitStatusLine;
{Инициализация строки статуса.}
var
R: TRect;
begin
GetExtent(R); {Возвращает в R область, занимаемую TApplication.}
R.A.Y := R.B.Y - 1; {Преобразует R в нижнюю строку этой области.}
StatusLine := New(PStatusLine, Init(R,
{Создание экземпляра объекта типа TStatusLine.}
NewStatusDef(0, $FFFF,
{Определение поддиапазона контекстной подсказки.}
NewStatusKey('~Alt-X~ Exit', kbAltX, cmQuit,
{Включение в строку статуса элемента «Alt-X Exit» с горячей
клавишей «Alt-X», и связывание с ним команды cmQuit (выход из
программы).}
NewStatusKey('~F10~ Menu', kbF10, cmMenu,
{Включение в строку статуса элемента «F10 Menu» с горячей
клавишей «F10», и связывание с ним команды cmMenu (вызов
меню).}
nil)), {Больше не определено элементов.}
nil) {Больше не определено поддиапазонов контекстной подсказки.}
));
end;
procedure THelloApp.InitMenuBar;
{Инициализация строки меню.}
var
R: TRect;
begin
GetExtent(R); {Возвращает в R область, занимаемую TApplication.}
R.B.Y := R.A.Y + 1; {Преобразует R в верхнюю строку этой области.}
MenuBar := New(PMenuBar, Init(R, NewMenu(
{Создание экземпляра объекта типа TMenuBar.}
NewSubMenu('~H~ello', hcNoContext, NewMenu(
{Определение выпадающего подменю ‘Hello’ с коротким набором
‘H’.}
NewItem('~G~reeting...', '', kbNoKey, cmGreetingBox, hcNoContext,
{Определение элемента подменю «Greeting...» с горячей клавишей
«G», и связывание с ним команды cmGreetingBox.}
NewLine(
{Вставка линии-разделителя между элементами подменю.}
NewItem('E~x~it', 'Alt-X', kbAltX, cmQuit, hcNoContext,
{Определение элемента подменю «Exit» с горячей клавишей
«Alt-X», и связывание с ним команды cmQuit.}
nil)))), {Больше не определено элементов подменю.}
nil) {Больше не определено подменю.}
)));
end;
begin
HelloWorld.Init; {Инициализация HelloWorld.}
HelloWorld.Run; {Выполнение HelloWorld.}
HelloWorld.Done; {Освобождение памяти HelloWorld.}
end.