
- •Часть 1. Введение в turbo vision...............................14
- •Глава 1. Наследование велосипеда...............................14
- •Глава 2. Разработка прикладных программ с использованием
- •Часть 2. Глава 3. Иерархия классов..........................88
- •Глава 4. Отображаемые элементы................................108
- •Глава 5. Программирование, управляемое событиями..............143
- •Глава 6. Разработка надежных программ.........................170
- •Глава 7. Коллекции............................................177
- •Глава 8. Объекты, хранимые с потоками.........................199
- •Глава 9. Ресурсы..............................................211
- •Часть 1. Введение в turbo vision
- •Глава 1. Наследование велосипеда
- •Глава 2. Разработка прикладных программ
- •Часть 2. Глава 3. Иерархия классов
- •Глава 4. Отображаемые элементы
- •Глава 5. Программирование, управляемое событиями
- •Глава 6. Разработка надежных программ
- •Глава 7. Коллекции
- •Глава 8. Объекты, хранимые с потоками
- •Глава 9. Ресурсы
- •Глава 10. Дополнительная информация....................................5
- •Часть 3. Справочник по turbo vision...................................13
- •Глава 11. Как использовать справочник.................................13
- •Глава 12. Заголовочные файлы turbo vision.............................16
- •Глава 13. Справочник по классам.......................................35
- •Глава 10. Дополнительная информация
- •Часть 3. Справочник по turbo vision
- •Глава 11. Как использовать справочник
- •Глава 12 описывает различные заголовочные файлы Turbo
- •Глава 16 описывает в алфавитном порядке все глобальные конс-
- •Глава 12. Заголовочные файлы turbo vision
- •Глава 13. Справочник по классам
- •Глава 14. Классы редактора......................................6
- •Глава 15. Стандартные диалоговые окна..........................41
- •Глава 16. Глобальный справочник................................70
- •Глава 14. Классы редактора
- •Глава 15. Стандартные диалоговые окна
- •Глава 16. Глобальный справочник
Глава 5. Программирование, управляемое событиями
-----------------------------------------------------------------
Цель программного средства Turbo Vision - обеспечить прог-
раммиста рабочей оболочкой для создания прикладных программ, для
того, чтобы он мог сосредоточиться на разработке основного содер-
жания программ. Двумя основными средствами Turbo Vision являются
встроенная поддержка организации окон и обработка событий. В гла-
ве 4 разъяснялись вопросы, связанные с представлением и просмот-
ром, а в данной главе мы расскажем о том, как ориентировать прог-
раммы на обработку событий.
Turbo Vision и решение основных проблем
-----------------------------------------------------------------
Мы уже описывали прикладные программы Turbo Vision как прог-
раммы, управляемые по событиям, и давали краткое определение со-
бытий как воздействий, на которые должна реагировать программа.
Чтение входных данных пользователя
----------------------------------
В традиционной программе с процедурами вы обычно создаете
циклический фрагмент программы, который выполняет чтение данных
пользователя, вводимых с клавиатуры, с помощью "мыши" или другими
способами, и принимаете решения на основе этих входных данных в
цикле. Вы вызовете процедуры или функции или выполните переход в
циклический фрагмент в другом месте программы, что вызовет пов-
торное чтение входных данных пользователя:
quit = False;
do
{
B = ReadKey();
switch( B )
{
case 'i':
case 'I':
invertArray();
break;
case 'e':
case 'E':
editArray();
break;
case 'g':
case 'G':
graphicDisplay();
break;
case 'q':
case 'Q':
quit = True;
Turbo Vision для С++ = 144 =
break;
default;
break;
}
} while (!quit);
Структура программы, управляемой по событиям не очень отли-
чается от этой программы. В действительности трудно представить
себе интерактивную программу, которая не действует таким же обра-
зом. Однако, для самого программиста программа, использующая уп-
равление по событиям, выглядит несколько иначе.
В прикладной программе, разработанной с помощью Turbo
Vision, вам не придется выполнять чтение входных данных пользова-
теля, т.к. Turbo Vision сама выполняет эту операцию. Она упаковы-
вает входные данные в записи, называемые событиями (объекты типа
struct TEvent) и распределяет события по соответствующим отобра-
жаемым объектам в программе. Это означает, что вашему фрагменту
программы необходимо лишь знать, как обращаться с соответствующи-
ми входными данными, и не требуется выполнять сортировку потока
входных данных и поиск событий для обработки.
Например, если пользователь нажимает кнопку "мыши", находясь
в неактивное окне, Turbo Vision считает это действие "мыши", упа-
кует его в запись события и передаст ее в неактивное окно.
Если у вас имеется опыт обычного программирования, вы можете
подумать: "Ну хорошо, мне больше не потребуется считывать входные
данные пользователя. Вместо этого я должен буду научиться считы-
вать запись события, связанного с нажатием кнопки "мыши" и сооб-
щить неактивному окну, каким образом оно может стать активным".
На самом деле вам не потребуется писать даже такой фрагмент прог-
раммы.
Отображаемые объекты могут самостоятельно обрабатывать боль-
шую часть входных данных пользователя. Окно знает, как открыться,
закрыться, переместиться, быть выделенным, изменить размер и мно-
гое другое. Меню "знает", как открываться, взаимодействовать с
пользователем и закрываться. Кнопки знают, как реагировать на на-
жатие, как взаимодействовать друг с другом и как изменять цвет.
Строки прокрутки знают, как с ними работать. Неактивное окно мо-
жет превратиться в активное без вашего участия.
Какие же функции остаются для программиста? Вы будете опре-
делять новые отображаемые объекты с помощью новых действий, кото-
рым потребуется информация об отдельных определяемых вами видах
событий. Вы должны также обучить свои отображаемые объекты реаги-
ровать на стандартные команды и даже посылать свои собственные
команды ("сообщения") для других отображаемых объектов. Механизм
уже отработан: вам остается лишь генерировать команды и обучать
видимые элементы реагировать на них.
Turbo Vision для С++ = 145 =
Что же конкретно представляют собой события для вашей прог-
раммы, и как Turbo Vision их обрабатывает?
Природа событий
-----------------------------------------------------------------
События можно представить как небольшие пакеты информации,
описывающие отдельные воздействия, на которые должна реагировать
прикладная программа. Каждое нажатие клавиши, действие с помощью
"мыши" и какое-то из определенных условий, генерируемых другими
компонентами программы, составляют отдельное событие. События
нельзя разбивать на более мелкие части; т.о., набор слова пользо-
вателем будет не единичным событием, а последовательностью от-
дельных событий нажатий клавиш.
Сердцевиной записи каждого объекта (TEvent) является поле
what типа ushort . Численное значение поля what отражает вид про-
исшедшего события, а в оставшейся части записи события хранится
специфическая информация об этом событии: скэн-код клавиатуры для
события нажатия клавиши, информация о положении "мыши" и состоя-
нии ее кнопок для события использования "мыши" и т.д.
Поскольку различные виды событий прокладывают путь к своим
целевым объектам различными способами, мы должны сначала рассмот-
реть различные виды распознаваемых событий.
Виды событий
Рассмотрим возможные значения поля TEvent::what более под-
робно. Имеются четыре основных класса событий: события, связанные
с действиями "мыши", события, связанные с клавиатурой, события
связанные с сообщениями и события, означающие "никаких действий".
Для каждого класса определена маска. Следовательно, ваши объекты
могут быстро определить, событие какого общего типа произошло, не
определяя его специфическую разновидность. Например, вместо того,
чтобы определять каждое из четырех событий, связанных с действия-
ми "мыши", вы лишь должны определить, установлен ли соответствую-
щий флаг события в маске. Вместо выражения:
TEvent event;
...
if event.what and (evMouseDown or evMouseUp or evMouseMove or
evMouseAuto) != 0 { ... }
Turbo Vision для С++ = 146 =
вы можете использовать выражение:
if (event.what and evMouse) != 0 { ... }
Для разделения событий служат маски: evNothing (для событий
"никаких действий"), evMouse для событий, связанных с "мышью",
evKeyBoard для событий, связанных с клавиатурой и evMessage для
сообщений.
Turbo Vision для С++ = 147 =
Разряды маски события определены на рисунке 5.1.
┌─┬─┬─┬─┬─┬─┬─┬─────────────────── evMessage = OXFF00
│ │ │ │ │ │ │ │ ┌─────────── evKeyboard = OX0010
│ │ │ │ │ │ │ │ │ ┌─┬─┬─┬─── evMouse = OX000F
╔══╧╤╧╤╧╤╧╤╧╤╧╤╧╤╧╤═╤═╤═╤╧╤╧╤╧╤╧╤╧══╗
║msb│ │ │ │ │ │ │ │ │ │ │ │ │ │ │lsb║
╚═══╧═╧═╧═╧═╧═╧╤╧╤╧═╧═╧═╧╤╧╤╧╤╧╤╧╤══╝
│ │ │ │ │ │ └─── evMouseDown = OX0001
│ │ │ │ │ └───── evMouseUp = OX0002
│ │ │ │ └─────── evMouseMove = OX0004
│ │ │ └───────── evMouseAuto = OX0008
│ │ └─────────── evKeyDown = OX0010
│ └─────────────────── evCommand = OX0100
└───────────────────── evBroadcast = OX0200
Рисунок 5.1. Битовый массив элемента данных TEvent.what
События, связанные с "мышью"
Имеются четыре основных вида событий, связанных с "мышью".
Это нажатие и отпускание каждой клавиши "мыши", изменение положе-
ния или "автособытие", связанное с "мышью". Нажатие клавиши "мы-
ши" вызывает событие evMouseDown. Отпускание кнопки "мыши" вызы-
вает событие evMouseUp. Перемещение "мыши" производит к событию
evMouseMove. А если вы удерживаете кнопку "мыши" в нажатом состо-
янии, то Turbo Vision будет периодически генерировать событие
evMouseAvto, позволяя вашей прикладной программе выполнять такие
действия, как повторяющуюся "прокрутку". Все данные о событии,
связанных с устройством типа "мышь", включают положение "мыши",
следовательно, объекту, выполняющему обработку события, известно
местонахождение "мыши" в момент наступления события.
События, связанные с клавиатурой
События, связанные с клавиатурой, еще более просты. После
нажатия вами клавиши, Turbo Vision генерирует событие evKeyDown,
которое отслеживает, какая клавиша была нажата.
События, связанные с сообщениями
Эти события выступают в трех формах: команды, передача сооб-
щений и сообщения пользователя. Разница между ними заключается в
способах их обработки, которые изложены ниже. В целом, команды
отмечаются в поле what с помощью значения evCommand, передачи со-
общений - с помощью значения evBroadcast, а сообщения пользовате-
лей - какой-либо определенной пользователем константой.
Turbo Vision для С++ = 148 =
Событие "никаких действий"
Это событие можно назвать "мертвым". Оно перестало быть со-
бытием, т.к. было полностью обработано. Если элемент данных what
в данных о событии содержит значение evNothing, то эта запись не
содержит никакой полезной информации для обработки.
Когда объект Turbo Vision завершает обработку события, он
вызывает метод clearEvent, которая снова присваивает полю what
значение evNothing, указывающее, что событие было обработано.
Объекты должны просто игнорировать события evNothing, т.к. они
уже обработаны другим объектами.
События и команды
-----------------------------------------------------------------
События, в конечном итоге, оканчивают свое существование,
будучи транслированными в какие-либо команды. Например, нажатие
клавиши "мыши" на элементе строки состояния генерирует событие,
связанное с "мышью". Когда это событие достигает объекта строки
состояния, то он реагирует на событие, генерируя командное собы-
тие с установкой значения поля command, соответствующего команде,
связанной с пунктом строки состояния. Нажатие "мышью" на Alt-X
Exit посылает команду cmQuit, которая интерпретируется прикладной
программой как указание на прекращения выполнения программы и за-
вершение работы.
Turbo Vision для С++ = 149 =
Маршрутизация событий
-----------------------------------------------------------------
Отображаемые объекты Turbo Vision функционируют по принципу
"говорить только тогда, когда к тебе обращаются". Это означает,
что вместо того, чтобы активно осуществлять поиск данных, они
пассивно ожидают, пока диспетчер событий сообщит им о событии, на
которое им следует реагировать.
Для того, чтобы ваши программы Turbo Vision действовали по
вашему плану, вы должны не только сообщать отображаемым объектам
об их функциях при наступлении определенных событий, но и пони-
мать, каким образом события достигают ваших отображаемых объек-
тов. Ключом к помещению событий в нужные места является правиль-
ная маршрутизация событий. Ряд событий передается на всем протя-
жении выполнения программы, а другие события узко направлены на
выполнение отдельных частей программы.
Что является обработчиком событий?
Как было сказано в главе 1, главный цикл обработки объекта
TApplication, метод run вызывает метод TGroup::Execute, который
является в основе своей циклом. Выглядит он примерно следующим
образом:
TEvent event;
event.what = evNothing; // указывает что нет событий
do {
if (event.what != evNothing eventError(event);
getEvent(event); // извлечь событие из очереди
handleEvent(event); // обработать событие
} while (endState == Continue);// до момента установки флага
// завершения
В сущности, функция getEvent анализирует ситуацию и выполня-
ет проверку наступления события. Если событие имело место,
getEvent создает соответствующую запись о событии. Функция
handleEvent направляет событие соответствующим отображаемым объ-
ектам. Если событие не было обработано (и сброшено) к моменту
возвращения в этот цикл, то выполняется вызов eventError, для
обозначения несостоявшегося события. По умолчанию, eventError не
выполняет никаких действий.
Примечание. Функции getEvent, handleEvent и eventError подробнее
описаны ниже в данной главе в соответствующих разде-
лах.
Описание маршрута событий
Маршрут событий начинается всегда с текущего модального ото-
бражаемого объекта. Для обычных операций этим отображаемым объек-
Turbo Vision для С++ = 150 =
том является, как правило, объект вашей прикладной программы. При
работе с модальной панелью диалога объектом этой панели диалога
является модальный отображаемый объект. В любом случае модальный
отображаемый объект - это объект, инициализирующий обработку со-
бытий. Дальнейший маршрут события определяется его природой.
Маршруты событий в зависимости от вида события формируются
тремя способами. Эти способы включают трассировку событий позици-
онных, выделенных и событий, связанных с передачей сообщений.
Важно понять принцип определения маршрута для каждого вида собы-
тия.
Позиционные события
В сущности, позиционными всегда являются события, связанные
с "мышью" (evMouse).
Модальный отображаемый объект первым получает позиционное
событие, а затем обращается к своим отображаемым подобъектам в
соответствии с Z-последовательностью для поиска объекта, содержа-
щего позицию, где произошло событие. Далее модальный отображаемый
объект передает событие данному отображаемому объекту. Поскольку
возможно наложение отображаемых объектов, то такое место может
находиться в ряде отображаемых объектов. Просмотр отображаемый
объектов в Z-последовательности гарантирует, что событие попадет
к самому верхнему объекту в данном положении. Ведь пользователь
нажимал кнопку именно на этом отображаемом объекте!
Примечание: О Z-последовательности было рассказано в главе 4,
"Отображаемые объекты".
Этот процесс продолжается до того момента, когда объект
больше не сможет отыскать отображаемый объект, в который необхо-
димо передать событие, либо потому что он является терминальным
отображаемым объектом (не имеющим отображаемых объектов), либо в
месте наступления события (таком, как нажатие кнопки в открытом
пространстве в панели диалога) не было отображаемого объекта. В
данной точке событие достигло объекта, где имело место позицион-
ное событие, и этот объект выполнит обработку события.
Выделенные события
Выделенные события - это обычно нажатия клавиш (evKeyDown)
или команды (evCommand), и они передаются по цепочке выделения.
Примечание: Подробнее о выделенных отображаемый объектах и цепоч-
ке выделения см. в разделе "Выбранные и выделенные
отображаемые объекты" в главе 4, "Отображаемые объек-
ты".
Вначале, текущий модальный отображаемый объект достигает вы-
Turbo Vision для С++ = 151 =
деленного события и передает его в его выбранный отображаемый по-
добъект. Если этот отображаемый подобъект элемент имеет выделен-
ный отображаемый подобъект, то он передает ему событие. Этот
процесс продолжается до достижения терминального отображаемого
объекта: им будет выделенный отображаемый объект. Выделенный
отображаемый объект принимает и обрабатывает выделенное событие.
Если выделенный отображаемый объект не знает, как обрабаты-
вать отдельное событие, он передает его обратно по цепочке выде-
лений его владельцу. Этот процесс повторяется до тех пор, пока
событие не будет обработано или снова дойдет до модального отоб-
ражаемого объекта. Если модальный отображаемый объект не знает,
как обрабатывать возвращенное событие, то он вызывает eventError.
Такая ситуация носит название несостоявшегося события.
Примечание: Невыделенные отображаемые объекты могут обрабатывать
выделенные события. См. об этом в разделе "Фаза" в
данной главе.
События, связанные с клавиатурой, наглядно иллюстрируют
принцип выделенных событий. Например, в интегрированной среде
разработчика (IDE) фирмы Borland в окнах редактирования в рабочей
области вы можете открыть несколько файлов. Когда вы нажимаете
клавишу, вы знаете, в какой файл вы хотите поместить символ.
Рассмотрим теперь, как Turbo Vision реализует ваше намерение.
Нажатием клавиши вы посылаете событие evKeyDown, которое пе-
редается в текущий модальный отображаемый объект, а именно в объ-
ект TApplication. TApplication передает событие в свой выбранный
отображаемый объект, в рабочую область (рабочая область всегда
является выбранным отображаемым объектом TApplication). Рабочая
область передает событие в ее выбранный отображаемый объект, ко-
торым служит активное окно (окно с двойной рамкой). Это окно ре-
дактирования также имеет видимые элементы - рамку, прокручиваемый
внутренний отображаемый объект и две строки прокрутки. Среди них
выбираемым является только внутренний отображаемый объект (и,
следовательно, выбранным, по умолчанию), т.о. событие, связанное
с клавиатурой, переходит к нему. Внутренний отображаемый объект,
редактор, не имеет отображаемых подобъектов, следовательно, он
должен решать, как обрабатывать символы в событии evKeyDown.
События, связанные с передачей сообщений
Такими событиями являются передачи сообщений (evBroadcast)
или определенные пользователем сообщения.
События, связанные с передачей сообщений, не являются столь
же ориентированными, как позиционные или выделенные события. По
определению, передача сообщений не знает назначения сообщения,
поэтому оно посылается всем отображаемым подобъектам текущего мо-
дального отображаемого объекта.
Turbo Vision для С++ = 152 =
Текущий модальный отображаемый объект принимает событие и
начинает передавать его в его отображаемые подобъекты в Z-после-
довательности. Если какие-то из этих отображаемых объектов обра-
зуют группу, то она также передает событие своим отображаемым по-
добъектам, также в порядке Z. Процесс продолжается до тех пор,
пока все отображаемые объекты, принадлежащие (прямо или косвенно)
модальному отображаемому объекту, не примут событие.
События, связанные с передачей сообщений обычно используются
для связи между отображаемыми объектами. Например, когда вы нажи-
маете с помощью "мыши" на строку прокрутки в окне просмотра фай-
лов, то эта строка должна сообщить текстовому отображаемому объ-
екту, что он будет изображать другой свой участок. Она выполняет
это с помощью передачи вида и сообщения "Я изменилась!", которое
получат другие отображаемые объекты, включая текст, и среагируют
на него. Подробнее об этом см. в разделе "Связь между отображае-
мыми объектами" в данной главе.
Замечание: Передачи сообщений могут быть направлены объекту с по-
мощью функции message.
События определяемые пользователем
При более близком знакомстве с Turbo Vision и событиями вы
уже можете пожелать определять целые новые категории событий, ис-
пользуя старшие разряды в поле what. По умолчанию Turbo Vision
будет выполнять маршрутизацию этих событий как событий, связанных
с передачей сообщений. Однако, вы можете пожелать, чтобы ваши но-
вые события были выделенными или позиционными, и Turbo Vision
предоставит вам такую возможность.
Turbo Vision определяет две маски, positionalEvents, и
focusedEvents, содержащие разряды, соответствующие событиям в
поле what, маршрутизация которых должна выполняться по местона-
хождению и по выделению, соответственно. По умолчанию маска
positionalEvents содержит все разряды evMouse, а маска
focusedEvents - все разряды (evKeyboard │ evCommand). Если вы оп-
ределите, что другой разряд будет новым видом события, маршрути-
зацию которого вы хотите выполнить либо по местонахождению, либо
по выделению, то вы должны просто добавить этот разряд в соот-
ветствующую маску.
Примечание: Оперирование разрядами в маске излагается в главе 10
"Краткие советы".
Turbo Vision для С++ = 153 =
Маскирование событий
Каждый объект отображаемого элемента имеет битовый элемент
данных по имени EventMask, который используется для определения,
какие события будет обрабатывать отображаемый объект. Разряды в
поле eventMask соответствуют разрядам в поле TEvent::what. Если
разряд для заданного вида события установлен (на 1), то отобража-
емый объект примет этот вид события для обработки. Если разряд
для заданного вида события сброшен (установлен на 0), то отобра-
жаемый объект его проигнорирует.
Фаза
Существуют ситуации, когда обработку выделенных событий
(особенно нажатий клавиш) желательно поручить не выделенному
отображаемому объекту. Например при просмотре прокручиваемого
текста в окне вы можете пожелать нажимать клавиши для прокрутки
текста, но поскольку текстовое окно является выделенным отобража-
емым объектом, то выделенные события передаются в него а не к
строкам прокрутки, которые могут выполнять прокрутку отображаемо-
го объекта.
Turbo Vision располагает механизмом, позволяющим невыделен-
ным отображаемым объектам просматривать и обрабатывать выделенные
события. Хотя описанная в разделе "Выделенные события" данной
главы схема маршрутизации вполне верна, из схемы маршрутизации по
цепочке выделений имеются два исключения.
Когда выделенное событие поступает для обработки в модальный
отображаемый объект, в трассировке его перемещения можно выделить
три "фазы":
- Событие передается в какой-либо отображаемый объект (в
Z-последовательности) в котором установлены флаги
ofPreProcess.
- Если событие не очищается ни одним из них, то оно передается
в выделенный отображаемый объект.
- Если и после этого событие не очищено, то оно передается
(опять же в Z-последовательности) в отображаемые объекты с
установленными флагами ofPostProcess.
Таким образом, если в предыдущем примере требуется, чтобы
строка прокрутки просматривала последовательности нажатия клавиш,
которые представляют интерес для вида выделенного текста, то она
должна инициализироваться с помощью установки флага ofPreProcess.
Если вы взглянете на пример программы TVGUID09.CPP, вы увидите,
что во всех строках прокрутки для внутренних отображаемых объек-
тов установлены их разряды ofPostProcess. Если вы измените фраг-
мент программы на фрагмент, в котором данные разряды не установ-
лены, то прокрутка с клавиатуры будет заблокирована.
Turbo Vision для С++ = 154 =
Обратите внимание также, что в этом примере установка разря-
дов ofPreProcess либо ofPostProcess не представляет существенного
различия, т.к. будет действовать лишь один из них. Т.к. выделен-
ный отображаемый объект в данном случае не будет обрабатывать со-
бытие (сам объект TScroller не выполняет никаких действий по на-
жатиям клавиш), то строки прокрутки могут просматривать события
либо до, либо после того, как событие попадает к устройству прок-
рутки.
Однако, в целом, в подобном случае вы пожелаете использовать
ofPostProcess, т.к. он предоставляет большую гибкость. Позднее вы
сможете добавить дополнительные функциональные возможности внут-
реннему отображаемому объекту, который выполняет проверку нажатий
клавиш. Однако, если нажатия клавиш были восприняты строкой прок-
рутки до того, как достигли выделенного отображаемого объекта
(ofPreProcess), ваш внутренний отображаемый объект не сможет на
них воздействовать.
Внимание!!!
Хотя может случиться, что вам потребуется захватить выделен-
ные события до того, как выделенный отображаемый объект смо-
жет их воспринять, правильно будет оставить открытыми как
можно больше количество опций, чтобы вы (или кто-то другой)
смогли в будущем породить что-либо из этого объекта.
Поле phase
Каждая группа имеет флаг поля типа enum phaseType:
enum phaseType (phFocused, phPreProcess, phPostProcess)
С помощью проверки флага phase владельца отображаемого объ-
екта может сообщить, попадает ли в него обрабатываемое им событие
до, во время или после выделенной маршрутизации. Это может ока-
заться необходимым, т.к. некоторые отображаемые объекты выполняют
поиск различных событий или реагируют на одни и те же события
различным образом, в зависимости от фазы.
Рассмотрим пример простой панели диалога, которая содержит
строку ввода и "кнопку" с меткой "All right", где A - сокращенное
название клавиши для "кнопки". При работе с обычными элементами
управления панелью диалога, вы не должны думать о фазе. В боль-
шинстве элементов управления разряд ofPostProcess установлен по
умолчанию, следовательно, нажатия клавиш (выделенные события)
достигнут их и позволят им захватить выделение, если оно является
буквой их сокращенного названия (которое было набрано). Нажатием
A выделение перемещается к "кнопке" "All right".
Предположим, однако, что строка ввода выделена, и поэтому
нажатия клавиш будут обрабатываться и вставляться строкой ввода.
Turbo Vision для С++ = 155 =
Нажатием клавиши "A" помещается в строку ввода, и кнопка никогда
не "увидит" события, т.к. оно было обработано выделенным отобра-
жаемым объектом. Вашим первым побуждением может быть выполнение
"кнопкой" проверки перед обработкой клавиши A, поэтому он может
обработать оперативную клавишу до того, как она будет обработана
выделенным отображаемым объектом. К сожалению это будет препятс-
твовать вашему набору буквы "A" в строке ввода!
Решение здесь достаточно просто: кнопка должна выполнять
проверку различных оперативных клавиш до и после обработки собы-
тия выделенным отображаемым объектом. В честности, по умолчанию,
"кнопка" будет выполнять поиск оперативной клавиши в предвари-
тельной обработке вида Alt-буква и последующей обработке только
буквенной формы. Поэтому вы всегда можете использовать буквенные
сокращения Alt в панели диалога, но когда выделенный элемент уп-
равления не "съедает" нажатия клавиш немедленно, использовать
только обычные буквы.
Это довольно просто сделать. Кнопки, по умолчанию, имеют ус-
тановленные разряды ofPreProcess и ofPostProcess одновременно,
следовательно, они могут просматривать выделенные события как до,
так и после того, как это сделает выделенный отображаемый объект.
Однако внутри handleEvent, если выделенный элемент управления уже
просмотрел событие, кнопка лишь выполняет проверку определенных
нажатий клавиш:
switch (event)
{
...
case evKeyDown:
{
c = hotKey(title);
if ( (event.KeyCode == getAltCode(c)) ||
(owner->phase == phPostProcess) && (c != '0') &&
(toupper(event.charCode) == c) ||
((state & sfFocused) != 0) &&
(event.charCode == ' ') )
{
pressButton();
clearEvent(event);
}
}
break;
...
}
Turbo Vision для С++ = 156 =
Команды
-----------------------------------------------------------------
Большинство позиционных и выделенных событий, будучи преоб-
разованными в команды обрабатывающими их объектами, заканчивают
существование. Это означает, что объект часто реагирует на нажа-
тие кнопки "мыши" или клавиши, посылая событие связанное с коман-
дой.
Например, при нажатии кнопки в строке состояния вы генериру-
ете позиционное событие (связанное с "мышью"). Программа опреде-
ляет, что нажатие было в области, управляемой строкой состояния,
поэтому она передает событие объекту *statusLine строки состоя-
ния.
Этот объект определяет, какие его элементы управляют об-
ластью нажатия и считывает запись элемента состояния для этого
элемента. Обычно имеется команда, связанная с этим элементом, по-
этому объект statusLine с помощью элемента what, установленного
evCommand, и элемента данных Command, установленного на команду,
связанную с его элементом состояния, создаст запись "повисшего"
события. Затем он очищает событие, связанное с "мышью", имея в
виду, что следующим обнаруженным getEvent событием будет только
что сгенерированное событие, связанное с командой.
Определение команд
-----------------------------------------------------------------
Turbo Vision располагает большим количеством предопределен-
ных команд, однако многие команды вы должны определить сами. Ког-
да вы создаете новый отображаемый объект, вы также создадите ко-
манду для активизации отображаемого объекта. Команды могут назы-
ваться как угодно, однако в Turbo Vision есть соглашение, соглас-
но которому идентификатор команды должен начинаться с "cm". Меха-
ника создания команд чрезвычайно прост - вы просто создаете конс-
танту:
const cmConfuseTheCat = 100;
Turbo Vision резервирует команды от 0 до 99 и от 256 до 999
для собственных нужд. В ваших прикладных программах вы можете
использовать для обозначения команд числа от 100 до 255 и от 1000
до 65535.
Причиной использования двух диапазонов команд служит то, что
заблокированы могут быть лишь команды от 0 до 255. Turbo Vision
резервирует часть команд, которые могут блокироваться (запрещать-
ся), и часть команд, которые не могут блокироваться, в качестве
своих стандартных команд и внутренних рабочих элементов. Осталь-
ные команды находятся в вашем полном распоряжении.
Turbo Vision для С++ = 157 =
Диапазоны имеющихся команд приведены в Таблице 5.1.
Таблица 5.1. Диапазоны команд Turbo Vision.
-----------------------------------------------------------------
────────────────────────────────────────────────
Диапазон Зарезервировано Может быть
запрещено
────────────────────────────────────────────────
0..99 Да Да
100..255 Нет Да
256..999 Да Нет
1000..65535 Нет Нет
────────────────────────────────────────────────
Привязка команд
Когда вы создаете элемент меню или строки состояния, то вы
"привязываете" к нему команду. Когда пользователь выбирает этот
элемент, то посылаются данные о событии, с полем what, которому
присвоено значение evCommand, и полем command, которому присвоено
значение, связанное с командой. Такой командой может быть либо
стандартная команда Turbo Vision, либо определенная вами команда.
В то же время вы связываете вашу команду с командой меню или
строки состояния, или же с оперативной клавишей. Т.о., пользова-
тель может активизировать команду нажатием одной клавиши с сокра-
щенным названием, используя меню или "мышь".
Важно помнить, что определение команды не определяет, какое
действие будет предпринято, когда эта команда появится в
данных о событии. Вы должны будете сообщить соответствующим
объектам о том, как им реагировать на эту команду.
Блокировка и разблокировка команд
Бывают случаи, когда вам нужно, чтобы определенные команды
были недоступны для пользователя на некоторое время. Например,
если у вас нет открытых окон, то для пользователя не имеет смысла
возможность генерации команды cmClose - стандартной команды зак-
рытия окна. Turbo Vision располагает способом блокировки и разб-
локировки наборов команд.
В частности, для того, чтобы блокировать или разблокировать
группу команд, вы должны использовать класс TCommandSet, который
является набором чисел от 0 до 255. (Именно поэтому заблокировать
можно только команды в диапазоне 0...255.) В следующем фрагменте
программы выполняется разблокировка двух команд, связанных с ок-
нами:
TCommandSet windowCommands;
Turbo Vision для С++ = 158 =
...
windowCommands += cmNext;
windowCommands += cmPrev;
disableCommands(windowCommands);
Примечание. Обратите внимание на естественное использование пере-
определяемой операции +=. См. о TCommandSet в главе
13.
Turbo Vision для С++ = 159 =
Обработка событий
-----------------------------------------------------------------
После того, как вы определили команду и установили способ
управления ее генерацией, например, с помощью элемента меню или
кнопки панели диалога, вы должны "обучить" отображаемый объект
реагировать на эту команду.
Каждый отображаемый элемент наследует метод handleEvent, ко-
торый способен реагировать на большую часть входных данных поль-
зователя. Если вы хотите, чтобы отображаемый элемент выполнил ка-
кую-либо операцию для вашей прикладной программы, то вам следует
переопределить его метод HandleEvent и обучить новый метод выпол-
нению двух операций - реагировать нужным вам образом на опреде-
ленные вами новые команды и реагировать на события, связанные с
"мышью" и клавиатурой.
Метод handleEvent определяет поведение отображаемого элемен-
та. Два отображаемых элемента с идентичными методами handleEvent
будут одинаково реагировать на события. При порождении нового ти-
па отображаемого элемента, вы хотели бы, чтобы его поведение в
целом более или менее повторяло поведение предшествующего отобра-
жаемого элемента, с некоторыми изменениями. Наиболее простым спо-
собом здесь является вызов метода handleEvent, предшествующего
отображаемого элемента в качестве составной части метода
handleEvent нового объекта.
Общая схема метода handleEvent порожденного отображаемого
элемента выглядит следующим образом:
virtual void TNewView::handleEvent( TEvent event )
{
// code to change or eliminate base view behavior
TBaseView::handleEvent(event);
// code to perform additional functions
}
Другими словами, если вы хотите, чтобы новый объект обраба-
тывал определенные события иначе, чем его предшественник (или
совсем их не обрабатывал), то вы должны прервать эти события до
передачи события методу handleEvent предшествующего отображаемого
элемента. Если вы хотите, чтобы поведение нового объекта было
аналогично поведению его предшественника, но чтобы он имел и ряд
дополнительных функций, вы должны добавить соответствующий фраг-
мент программы после вызова метода handleEvent предшествующего
отображаемого элемента.
Turbo Vision для С++ = 160 =
Данные о событии
-----------------------------------------------------------------
До сих пор в данной главе события рассматривались в теорети-
ческом плане. Описывались различные виды событий (связанные с
мышью, клавиатурой, сообщениями и "пустыми" действиями), опреде-
ляемыми полем what. Упоминалось также об использовании поля
command для событий, связанных с командами.
Теперь рассмотрим, что представляет собой объект события.
Файл заголовка SYSTEM.H определяет структуру TEvent следующим об-
разом:
struct TEvent
{
ushort what;
union
{
MouseEventType mouse;
KeyDownEvent keyDown;
MessageEvent message;
};
void getMouseEvent();
void getKeyEvent();
};
Два метода getMouseEvent и getKeyEvent вызываются с помощью
TProgram::getEvent; обычно вам не потребуется выполнять их непос-
редственный вызов самостоятельно. Эти методы подробно описаны в
главе 13. Вкратце, getMouseEvent считывает информацию о событиях,
связанных с "мышью", которые обрабатываются с помощью обработчика
ошибок Turbo Vision. Если произошло событие, связанное с "мышью",
то поле TEvent::what получает значение evMousexxx (где xxx - это
значения Down, Up, Move или Auto). Вы коротко ознакомитесь с тем
как поле, связанный с "мышью", получает значение, указывающее на
информацию о кнопке и положении. Если событий связанных с
"мышью", не произошло, поле TEvent::what получает значение
evNothing.
Для проверки наступления события, связанного с клавиатурой,
getKeyEvent вызывает сервисное средство BIOS INT 16H. Если такое
событие произошло, то TEvent::what получает значение evKeyDown,
а поле keyDown содержит код нажатой клавиши. В случае отсутствия
события, связанного с клавиатурой, поле TEvent::what получает
значение evNothing.
В зависимости от значения TEvent::what содержимое объедине-
ния данных в TEvent будут интерпретироваться как события типа
mouse, keyDown или message. Рассмотрим подробнее каждый из этих
типов. Первый из них, MouseEventType, является другой структурой,
определяемой следующим образом:
struct MouseEventType
Turbo Vision для С++ = 161 =
{
uchar buttons;
Boolean doubleClick;
TPoint where;
};
Примечание. Напоминаем, что в С++ struct является просто классом
с общедоступными значениями, задаваемыми по умолчанию.
Следовательно, событие, связанное с "мышью", сообщает вам
местоположение курсора, набор использовавшихся кнопок, и имело ли
место двойное нажатие кнопки "мыши".
Если поле TEvent::what имеет тип evKeyDown, то вы будете
осуществлять доступ к данным события через структуру
KeyDownEvent. Она содержит следующее объединение:
struct KeyDownEvent
{
union
{
ushort keyCode;
CharScanType charScan;
};
};
где, CharScanType также является структурой:
struct CharScanType
{
uchar charCode;
uchar scanCode;
};
Это означает, что событие, связанное с нажатием клавиши мо-
жет интерпретироваться либо как keyCode типа ushort, либо в виде
пары байт: charCode и scanCode.
Третий элемент структуры TVEvent представляет собой тип
MessageEvent, определяемый следующим образом:
struct MessageEvent
{
ushort command;
union
{
void *infoPtr;
long infoLong;
ushort infoWord;
short infoInt;
uchar infoByte;
char infoChar;
};
Turbo Vision для С++ = 162 =
};
Эти значения сообщений в Turbo Vision используется различным
образом. Отображаемые элементы могут самостоятельно генерировать
события и передавать их другим отображаемым элементам, и при этом
они часто используют поле infoPtr. Вопросы связи между отображае-
мыми элементами и полями infoPtr рассматриваются в данной главе в
разделе "Связь между отображаемыми элементами".
Очистка событий
Метод отображаемого элемента handleEvent завершает процесс
обработки события вызовом метода clearEvent. Этот метод присваи-
вает полю event.what значение события evNothing, а полю
event->infoPtr значение this, которые служат универсальными сиг-
налами того, что событие обработано. Если событие передается за-
тем другому объекту, то этот объект проигнорирует это событие
("никакого действия").
Несостоявшиеся события
Обычно какой-либо отображаемый элемент выполняет обработку
события в вашей прикладной программе. Если такой отображаемый
элемент не обнаруживается, то модальный отображаемый элемент вы-
зывает eventError. eventError вызывает eventError владельца отоб-
ражаемого элемента и т.д. вверх по дереву отображаемых элементов
до вызова TApplication::eventError.
По умолчанию метод TApplication::eventError не выполняет ни-
каких действий. Он может использоваться в процессе разработки
программы для переопределения метода eventError, чтобы привести в
действие панель диалога сообщений об ошибках или подать звуковой
сигнал. Т.к. конечный пользователь вашей прикладной программы не
несет ответственности за ее неспособность обработать событие, та-
кую панель диалога сообщений об ошибках в пересылаемой версии бу-
дет, вероятно, вызывать раздражение.
Метод clearEvent также способствует осуществлению связи меж-
ду отображаемыми элементами. Не следует забывать, что обработка
события не может быть закончена без вызова метода clearEvent.
Turbo Vision для С++ = 163 =
Модификация механизма обработки событий
-----------------------------------------------------------------
Основным в текущем модальном отображаемом элементе является
следующий цикл:
TEvent event;
event.what = evNothing;
do {
if (event.what != evNothing) eventError(event);
getEvent(event);
handleEvent(event);
} (while endState != continue);
Централизованный сбор событий
Одним из важнейших преимуществ объектно-ориентированного
программирования является то, что вашему фрагменту программы мо-
жет быть не известен источник событий. Объекту окна, например,
требуется лишь знать, что когда он получает в событии команду
cmClose, окно должно закрыться. Не имеет значения, получена ли
команда от нажатия кнопки "мыши" или кнопки закрытия окна, выбора
команды меню, оперативной клавиши или сообщения от другого объек-
та в программе. Ему даже не требуется определять, для него ли
предназначена эта команда. Ему необходимо лишь знать, что ему пе-
редано событие для обработки, и он его будет обрабатывать в соот-
ветствии с его осведомленностью в этой области.
Ключом к подобным событиям из "черного ящика" служит метод
getEvent прикладной программы. Метод getEvent является единствен-
ной частью вашей программы, которой требуется знать источник со-
бытий. Объекты в вашей прикладной программе просто вызывают метод
getEvent и полностью на него полагаются при получении событий,
связанных с "мышью", клавиатурой или "отложенных" событий, гене-
рируемых другими объектами.
Если вы хотите создать новые виды событий (например, чтение
символов из последовательного порта), то вы должны просто переоп-
ределить метод TApplication::getEvent в объекте вашей прикладной
программы. Как можно видеть из фрагмента программы TApplication::
getEvent, цикл getEvent считывает информацию от "мыши" и с клави-
атуры и затем вызывает метод Idle. Для того, чтобы ввести новый
источник событий, вы должны либо переопределить Idle для поиска
символов из последовательного порта и генерировать события на их
основе, либо переопределить сам метод getEvent, чтобы добавить в
цикл вызов getComEvent(Event), где getComEvent возвращает запись
события, если имеется символ в предназначенном ему последователь-
ном порте.
Переопределение метода getEvent
Turbo Vision для С++ = 164 =
Метод getEvent текущего модального отображаемого элемента
вызывает метод getEvent его владельца и т.д. на всем протяжении
вверх по дереву отображаемых элементов до TApplication::getEvent,
являющегося обычным местом выбора следующего события.
Поскольку Turbo Vision всегда использует для выполнения фак-
тического выбора событий TApplication::getEvent, вы можете моди-
фицировать события для всей вашей прикладной программы с помощью
переопределения этого метода. Например, для реализации макроко-
манд с клавиатуры вы можете просматривать события, возвращаемые
методом getEvent, перехватывать определенные нажатия клавиш и
развертывать их в макрокоманды. Далее для прикладной программы
будет известно, что поток событий будет идти прямо от пользовате-
ля.
virtual void TMyApp::getEvent(TEvent& event)
{
TApplication::getEvent(event);
// { здесь выполняется специальная обработка }
Использование простоя программы
Центральная роль метода TApplication::getEvent имеет еще и
то преимущество, что он вызывает метод TApplication::Idle, даже
если события еще не поступали. TApplication::Idle - это "пустой"
метод, который вы можете переопределять, чтобы выполнять обработ-
ку отображаемого элемента, параллельно обработке данного отобра-
жаемого элемента.
Предположим, например, что вы определяете отображаемый эле-
мент по имени THeapView, который использует метод UpDate для
отображения имеющейся динамической памяти. Если вы переопределите
метод TApplication::Idle следующим методом, то пользователь полу-
чит возможность непрерывно просматривать динамическую память не-
зависимо от того, в каком месте программы он находится.
Примечание: Пример устройства просмотра динамической памяти име-
ется в составе примеров программ на ваших дистрибутив-
ных дисках.
virtual void TMyApp::idle()
{
THeapView::update();
}
Turbo Vision для С++ = 165 =
Связь между отображаемыми элементами
-----------------------------------------------------------------
Предположим, что объекту требуется обменяться информацией с
другим объектом в вашей программе - в традиционной программе, ко-
торая представляет собой простое копирование информации из одной
структуры данных в другую, или в объектно-ориентированной прог-
рамме, которая может быть не такой простой, т.к. объекты могут не
знать, как обнаружить друг друга.
Если вам требуется осуществить связь между отображаемыми
элементами, то первым возникает вопрос о том, насколько правильно
вы распределили задачи между отображаемыми элементами. Здесь мо-
гут проявиться недостатки в разработке программы. Возможно, сле-
дует объединить два отображаемых элемента в один, или переместить
часть одного отображаемого элемента в другой.
Промежуточные отображаемые элементы
Если разработка программы неплохая, но, тем не менее, требу-
ет осуществления связи между отображаемыми элементами, то пра-
вильным решением будет создать промежуточный отображаемый эле-
мент.
Предположим, например, что вы хотите вставить какой-либо
фрагмент из электронной таблицы в текстовый процессор, и наобо-
рот. В прикладной программе, разработанной с помощью Turbo
Vision, вы можете это сделать с помощью прямой связи между отоб-
ражаемыми элементами. Предположим, что позднее вам потребуется
добавить к этой группе объектов, к примеру, базу данных и произ-
водить вставки в эту базу и извлечение из нее. Для этого вам пот-
ребуется распространить установленную вами связь между первыми
двумя объектами на третий объект.
Лучшим решением здесь будет установка промежуточного отобра-
жаемого элемента - в данном случае, буфера вырезанного изображе-
ния ("кармана"). Объекту потребуется лишь знать, как заносить в
него запись или изымать запись. Вне зависимости от того, сколько
новых объектов вы добавите к группе, ваша работа от этого не ус-
ложнится.
Обмен сообщениями между отображаемыми элементами
Если вы внимательно анализировали ситуацию и уверены в раз-
работке вашей программы и вам не требуется создание промежуточно-
го отображаемого элемента, вы можете реализовать простую связь
между двумя отображаемыми элементами.
Прежде, чем будет установлена связь между отображаемыми эле-
ментами, отображаемый элемент должен обнаружить другой отображае-
мый элемент и даже удостовериться, существует ли он вообще.
Turbo Vision для С++ = 166 =
Приведем наглядный пример. Библиотека Stddlg содержит панель
диалога TFileDialog. TFileDialog содержит метод TFileList, пока-
зывающий каталог диска и метод FilеInputLine, демонстрирующий
файл, выбранный для загрузки в данный момент. Всякий раз, когда
пользователь выбирает в списке файлов FileList другой файл, дан-
ный список должен требовать от FileInputLine вывода имени нового
файла.
В данном случае FileList может быть уверен, что
FileInputLine существует, т.к. оба они существуют в одном и том
же объекте FileDialog. Каким же образом FileList сообщает
FileInputLine, что пользователь выбрал новое имя?
FileList создает и передает сообщение. В данном случае име-
ется метод TFileList::FocusItem, который передает событие и метод
(объекта FileInputLine) handleEvent, который его принимает:
void TFileList::focusItem( short item )
{
TSortedListBox::focusItem( item );
// вначале вызывает наследуемый метод
message(owner, evBroadcast, cmFileFocused,List()->at(item));
}
void TFileInputLine::handleEvent( TEvent& event )
{
TInputLine::handleEvent( event);
if( event.what == evBroadcast &&
event.message.command == cmFileFocused &&
! (state & sfSelected))
{
if( (((TSearchRec *)event.message.infoPtr)->attr &
FA_DIREC)
!= 0 )
{
strcpy( data, ((TSearchRec *)event.message.infoPtr->
name );
strcat( data, "\\" );
strcat( data, ((TFileDialog *)owner)->wildCard );
}
else
strcpy( data, ((TSearchRec *)event.message.infoPtr)->
name );
drawView();
}
}
Здесь message - это функция, которая посылает событие, свя-
занное с сообщением и возвращает указатель на объект (если тако-
вой имеется), который выполняет обработку события.
Кто управляет передачей сообщений?
Turbo Vision для С++ = 167 =
Предположим, прежде чем вы приступите к выполнению како-
го-либо действия. вам требуется узнать, имеется ли в рабочей об-
ласти открытое окно. Каким же образом вы сможете это сделать? Для
этого ваш фрагмент программы должен передать событие, связанное с
передачей сообщения, на которое окна смогут отреагировать. "Под-
пись", оставленная объектом, обрабатывающим событие, укажет вам
его обработчик. Этот процесс можно проследить на примере реализа-
ции TView::clearEvent:
void TView::clearEvent( TEvent& event )
{
event.what = evNothing;
event.message.infoPtr = this;
}
Объект вида v сообщает об успешном выполнении обработки пе-
реданного события с помощью вызова метода clearEvent, т.о.
infoPtr получает значение &v, позволяя определить v.
Все ли в порядке?
Приведем конкретный пример. В интегрированной среде разра-
ботки программ фирмы Borland, если пользователю требуется открыть
окно просмотра, то выполняющей это программе необходимо сделать
проверку на открытие такого окна ранее. Если такое окно не откры-
то, то программа его откроет; если оно не открыто, то программа
переместит его наверх.
Выполнить передачу сообщения достаточно просто. Для этого
можно использовать функцию message:
AreYouThere := message(deskTop, evBroadcast, cmFindWindow, 0);
В программе для метода handleEvent окна просмотра имеется
проверка на реагирование на cmFindWindow посредством "очистки"
события:
switch (event.message.command)
{
...
case cmFindWindow:
clearEvent(event);
break;
...
}
Не следует забывать, что clearEvent не только присваивает
полю what данных о событии значение evNothing, но также и уста-
навливает поле infoPtr в значение this. Функция message выполняет
чтение из этих полей, и, если событие было обработано, возвращает
указатель на объект, который обрабатывал событие, связанное с со-
Turbo Vision для С++ = 168 =
общением. В данном случае этим объектом будет окно просмотра.
Т.о., далее за строкой, которая посылает сообщение, мы включаем
следующее:
if (areYouThere == 0)
createWatchWindow();// если такового нет, его следует
// создать
else areYouThere->select; // в противном случае поставить
// его вперед
Пока окно просмотра будет единственным объектом, который
способен реагировать на передачу cmFindWindow, то по завершении
программы поверх отображаемых элементов в рабочей области будет
наверняка находиться только одно окно просмотра.
Какое окно расположено над всеми окнами в рабочей области?
Используя изложенный ранее способ, вы можете также опреде-
лить, например, какое окно является самым верхним отображаемым
элементом этого типа в рабочей области. Т.к. событие, связанное с
передачей сообщения, передается каждому из отображаемых элементов
модального вида в Z-последовательности (порядок обратной встав-
ки), то отображаемым элементом, который вставлен вставленным, бу-
дет "верхний" отображаемый элемент в рабочей области.
Рассмотрим кратко ситуацию в интегрированной среде разработ-
ки программ фирмы Borland, при которой пользователь имеет откры-
тое окно просмотра наверху в рабочей области при прохождении
программы через окно редактирования. Окно просмотра может быть
активным окном (с двойной рамкой, вершиной стека), однако строка
выполнения в окне программы должна отслеживать выполняющую прог-
рамму. Если в вашей рабочей области открыто несколько окон редак-
тирования, они не должны накладываться, а интегрированная среда
разработки должна знать, в каком из окон редактирования она будет
выполнять отслеживание выполнения программы.
Этим окном должно быть переднее или самое верхнее окно ре-
дактирования, которое определяется как последнее вставленное ок-
но. Для того, чтобы указать, какое окно находится "сверху", ин-
тегрированная среда разработки программ передает сообщение, на
которое смогут отреагировать только окна редактирования. Первым
окном редактирования, которое получит сообщение, будет окно,
вставленное последним; оно будет обрабатывать событие посредством
"очистки", и интегрированная среда поэтому будет знать, какое ок-
но использовать для трассировки программы с помощью чтения возв-
ращаемого функцией message результата.
Вызов метода handleEvent
-----------------------------------------------------------------
Вы можете также создать или модифицировать событие, а затем
Turbo Vision для С++ = 169 =
вызвать непосредственно метод handleEvent. Вы можете вызвать ме-
тод handleEvent для любого отображаемого элемента; этот отобража-
емый элемент будет передавать событие вниз по дереву.
Контекст справочной системы
-----------------------------------------------------------------
В Turbo Vision имеются встроенные средства, которые способс-
твуют реализации контекстной подсказки в вашей прикладной прог-
рамме. Вы можете присвоить отображаемому элементу номер контекс-
тной подсказки, и Turbo Vision гарантирует, что как только
отображаемый элемент будет выделен, то номер его контекстной
подсказки станет номером текущей контекстной подсказки программы.
Для создания глобальной системы контекстной подсказки вы мо-
жете реализовать helpView, которому известны определенные вами
номера контекстных подсказок. При активизации helpView (обычно
при нажатии пользователем клавиши F1 или другой оперативной кла-
виши), он запросит у владельца текущую контекстную подсказку с
помощью вызова метода getHelpCtx. После этого helpView сможет
считать и выдать на экран правильный текст подсказки. Несколько
подобных примеров находится среди демонстрационных программ.
Контекстная подсказка - это одна из последних функций, кото-
рую вы захотите реализовать в вашей программе, поэтому объекты
Turbo Vision инициализируются с заданным по умолчанию контекстом
hcNoContext, который является предопределенным контекстом, не из-
меняющим текущий контекст. В свое время вы сможете разработать
систему номеров подсказок, затем вставить правильный номер в со-
ответствующий отображаемый элемент с помощью вызова сразу после
создания отображаемого элемента helpCtx.
Контексты подсказки используются также в строке состояния
для определения отображаемых элементов для вывода на экран. Пом-
ните, что при создании строки состояния вы вызываете метод
TStatusDef, который определяет набор элементов состояния для за-
данного диапазона значений контекста подсказки. Когда новый отоб-
ражаемый элемент становится выделенным, то контекст подсказки для
этого элемента определяет, какая строка состояния изображена на
экране.
Turbo Vision для С++ = 170 =