Введение в Turbo Vision


В этой главе мы попробуем разработать программу, которая использует некоторые возможности Turbo Vision. Пусть, например, нам необходимо создать простейшую информационную систему - нечто вроде электронной записной книжки. Предполагается, что данные, используемые этой системой, будут храниться в виде записей в дисковом файле. Наша задача - разработать удобную диалоговую программу, облегчающую доступ к файловым данным.
Разработка программы, разумеется, не является самоцелью - ведь для нас это только повод для конкретного знакомства с Turbo Vision. Поэтому мы будем создавать программу постепенно, каждый раз фиксируя достигнутые результаты. Если Вас интересует собственно информационная программа, используйте ее окончательный вариант, приведенный в прил.П.5.4
 
Простейшая программа в Turbo Vision
Работа большинства прикладных программ проходит в три этапа: подготовка к работе, собственно работа и, наконец, ее завершение. В нашем случае к подготовительному этапу можно отнести такие действия, как анализ существования файла данных и его (файла) подготовка к работе. На этапе завершения мы должны обеспечить необходимые действия по сохранению файла/Все остальные действия относятся к среднему этапу. С учетом этого можно написать следующую простейшую программу:
begin
{Подготовить работу программы} 
{Выполнить необходимые действия} 
{Завершить исполнение программы} 
end.
Если Вы попытаетесь выполнить эту программу, ничего не произойдет - ведь мы еще никак не конкретизировали необходимые действия. Так обстоит дело в Турбо Паскале, но не так - в Turbo Vision! Для любой прикладной программы Turbo Vision сразу же создает некоторую минимальную программную реализацию, которую Вы можете затем постепенно наращивать в ходе детализации программы. Вот начальный вариант программы с использованием Turbo Vision:
Uses Арр; {Используется модуль АРР библиотеки Turbo Vision}
var
Notebook: TApplication;
begin
Notebook.Init; {Подготовить работу программы} 
Notebook.Run; {Выполнить необходимые действия} 
Notebook.Done {Завершить исполнение программы}
end.
В этой программе объявляется использование стандартного для Turbo Vision модуля Арр (от application - приложение, прикладная программа). Такое объявление открывает доступ прикладной программе к мощным возможностям Turbo Vision. Чтобы использовать эти возможности, мы объявили переменную Notebook (notebook - записная книжка) типа TApplication. Как Вы вскоре заметите, на букву Т в Turbo Vision начинаются идентификаторы объектов. Таким образом, Notebook - это экземпляр объекта TApplication, т.е. объединение данных (полей) и методов обработки этих данных (процедур, функций, конструкторов, деструкторов). В объекте TApplication предусмотрены методы Init, Run и Done. Вызов этих методов и составляет исполняемую часть нашей программы. Если Вы подготовите и запустите программу, на экране ПК появится изображение, показанное на  1.
Для выхода из программы необходимо, как это следует из надписи в левом нижнем углу экрана, нажать Alt-X или подвести к этой надписи указатель мыши (если, разумеется, Ваш ПК оснащен этим устройством) и нажать ее левую кнопку.
Как видите, даже простейшая программа «знает», как создать экран, распознает команду Alt-X и может работать с мышью. Совсем не плохо для трех исполняемых операторов, не так ли? Такие возможности доступны потому, что в объекте TApplication предусмотрены соответствующие методы. В этом смысле использование объектов напоминает использование подпрограмм из библиотек. Однако в отличие от подпрограммы любой объект имеет все необходимые ему данные. Говоря об объектах, я часто буду использовать такие слова, как «знает», «умеет», «может», подчеркивая тем самым главную отличительную особенность объектов от традиционных подпрограмм - их «разумность»: последовательное проведение в жизнь принципа инкапсуляции (объединения) данных и всех необходимых для их обработки методов придает объекту определенную независимость от других элементов программы; объекты как бы «живут» в программе своей независимой жизнью.
Простейшая программа не может выполнять никаких других действий, кроме уже перечисленных, так как именно эти действия запрограммированы в методах Init и Run объекта TApplication. В ходе их выполнения на экране создается изображение, имеющее три зоны: верхняя строка, нижняя строка и вся остальная часть экрана. Верхняя строка обычно используется для размещения опций главного меню (не забывайте, что Turbo Vision - это оболочка для диалоговых программ!). Нижняя строка - строка статуса: в ней указываются так называемые командные клавиши, т.е. клавиши или комбинации клавиш, которые вызывают нужные действия без перехода к промежуточному диалогу. Вся остальная часть экрана составляет «рабочий стол» программы - сюда будут помещаться сообщения, здесь будут размещаться окна, «выпадающие» меню (меню нижнего уровня) и т.п.
 
Формирование строки статуса
Стандартный вид экрана, показанный на  1, можно изменять. Попробуем придать ему некоторый специфический для нашей программы вид. Например, заменим в строке статуса стандартное сообщение
Alt-X Exit 
на русифицированное
Alt-X Выход
Таким образом, нам необходимо модифицировать стандартное поведение объекта Notebook. Для этого мы должны отыскать в типе TApplication метод, ответственный за создание строки статуса. Если мы обратимся к прил.П6, то обнаружим, что объект типа TApplication содержит методы Init и Done, с помощью которых создаются и уничтожаются экземпляры объекта, но в нем нет метода, ответственного за строку статуса. Однако из таблицы наследования нетрудно определить, что этот метод (InitStatusLine) он наследует от своего родителя TProgram. Как изменить работу метода? В рамках объектно-ориентированной библиотеки для этого поступают следующим образом: объявляется объект-потомок от стандартного объекта, поведение которого необходимо изменить, и в новом объекте описывается свой метод, ответственный за это поведение.
Изменим программу следующим образом;
Uses Арр, Objects, Menus, Drivers, Views; 
type
TNotebook = object (TApplication) {Создаем объект-потомок от TApplication} 
Procedure InitStatusLine; Virtual; {Перекрываем старый метод InitStatusLine новым} 
end;
{-----------}
Procedure TNotebook. InitStatusLine;
{Описание нового метода, с помощью которого создается строка статуса}
var
R: TRect; {Границы строки статуса} 
begin
GetExtent (R) ; {Получаем в R координаты всего экрана} 
R.A.Y := pred(R.B.Y) ; {Помещаем в R координаты строки статуса}
{Создаем строку статуса:} 
StatusLine := New(PStatusLine, Init(R, 
{Определяем один вариант строки статуса:} 
NewStatusDef (0, $FFFF, {Устанавливаем для этого варианта максимальный диапазон контекстной справочной службы}
{Определяем единственную клавишу Alt-X: } 
NewStatusKey('~Alt-X~ Выход' , kbAltX, cmQuit, 
NIL), {Нет других клавиш} 
NIL) {Нет других строк статуса}
))
end; {TNotebook. InitStatusLine}
{---------}
var
Notebook: TNotebook;{Изменен тип переменной!}
begin
Notebook. Init;
Notebook. Run;
Notebook. Done 
end .
Как видим, программа сразу же усложнилась. Во-первых, в ней используются идентификаторы, которые определены в других модулях Turbo Vision, - эти модули мы перечислили в предложении Uses. Во-вторых, нам потребовалось объявить новый объект TNotebook как потомок от объекта TApplication. Объект-потомок наследует от своего объекта-родителя все поля и методы и при необходимости может их дополнять своими полями и методами, а также перекрывать методы родителя. Как раз для того, чтобы перекрыть унаследованный от TProgram стандартный метод InitStatusLine, ответственный за создание строки статуса, нам и понадобилось объявление нового типа TNotebook. Строка
Procedure InitStatusLine; Virtual;
в объявлении этого типа указывает, что новый объект будет пользоваться одноименным, но иным, чем объект-родитель, методом. Возможность замены методов на одноименные, но с другим содержанием называется полиморфизмом.
Процедура TNotebookJnitStatusLine раскрывает суть нового метода. В ней используется обращение к методам NewStatusDef vi NewStatusKey, с помощью которых создается динамический объект типа TStatusLine. Программа TApplication обращается к методам этого объекта для обслуживания строки статуса.
Turbo Vision позволяет определять несколько вариантов строки статуса. Каждый вариант создается с помощью метода NewStatusDef. В зависимости от текущего состояния программы (от контекста программы) Turbo Vision автоматически помещает в строку статуса нужный вариант. Так как в нашей программе используется единственный вариант строки статуса, мы указали максимально возможный диапазон контекста программы при обращении к методу NewStatmDef.
С помощью метода NewStatusKey в строке статуса определяется очередная командная клавиша. При обращении к методу сначала указывается текст, высвечиваемый в строке статуса, причем символом «~» выделяется та часть сообщения, которая будет подсвечена в строке статуса другим цветом: таким способом в Turbo Vision указываются командные клавиши. Идентификатор kbAltX задает комбинацию клавиш, а cmQuit - связанную с ней команду.
В программе объявляется переменная R типа TRect. С помощью такого типа переменных программист задает координаты прямоугольного участка экрана. Эта переменная необходима нам для указания того места на экране, где будет помещено сообщение
Alt-X Выход
определяющее командные клавиши Alt-X. Для правильного задания этих координат мы использовали два предложения:
GetExtent(R);
R.A.Y := pred(R.B.Y);
В первом вызывается стандартный метод Turbo Vision GetExtent, с помощью которого в R помещаются координаты доступной в данный момент части экрана. Во втором - номер той строки (строки статуса), куда будет выводиться сообщение. В Turbo Vision тип TRect объявляется в виде следующей записи:
type
TRect = record
A: record {Координаты верхнего левого угла} 
X: Byte; Y: Byte 
end;
В: record {Координаты правого нижнего угла} 
X: Byte; Y: Byte 
end 
end;
Таким образом, второе предложение лишь уменьшает на единицу вертикальную координату самой нижней доступной строки и устанавливает полученное значение в поле R.A. Y (это поле задает вертикальную координату верхнего левого угла прямоугольного участка). Заметим, что в Turbo Vision минимальные координаты задаются значением 0, в то время как в стандартном модуле CRT Турбо Паскаля минимальные координаты имеют значение 1.
Обратите внимание на характерный прием, широко используемый в Turbo Vision: при обращении к методам NewStatusDef и NewStatusKey последним параметром указывается переменная типа Pointer. Внутри методов эта переменная трактуется как ссылка на новый метод, что позволяет организовать цепочку последовательных определений. Вложенная последовательность вызовов заканчивается зарезервированной константой NIL, указывающей на конец цепочки. Если бы мы, например, захотели добавить в строку статуса определение клавиши F10, связав ее с закрытием активного окна, мы могли бы использовать такую конструкцию:
NewStatusDef(0, $FFFF,
NewStatusKey('~Alt-X~ Выход', kbAltX, cmQuit,
NewStatusKey('~F10~ Закрыть окно', kbFl0, cmClose,
NIL)), {Нет других клавиш} 
NIL) {Нет других определений}
Описанный пример позволяет нам сделать очень важный вывод:
Чтобы модифицировать стандартное поведение объекта, необходимо создать объект-потомок от этого объекта и перекрыть в нем нужный метод.
  
Формирование меню
Вернемся к смысловой части нашего примера и подумаем о том, какие еще свойства следует придать программе. Поскольку мы предполагаем работу с файлом, можно включить в программу код, реализующий строку меню с опцией «Файл», связав с этой опцией такие действия, как открытие уже существующего файла данных и/или создание нового. Здесь же можно предусмотреть возможность альтернативного выхода из программы. Кроме того, в главное меню следует поместить еще одну опцию, назовем ее «Работа». Эта опция должна открыть доступ к содержательной части программы. С учетом сказанного программу нужно дополнить следующими строками:
const
{Команды для обработчиков событий:}
cmWork = 203; {Обработать данные}
cmDOS = 204; {Временно выйти в ДОС}
WinComl: TCommandSet = [cmSave,cmWork]; {Множество временно недоступных команд}
Эти строки следует вставить сразу после предложения Uses; они определяют коды команд, которые будут затем использоваться для вызова соответствующих частей программы. Кроме того, объявление объекта TNotebook нужно дополнить строкой
type
TNotebook = object (TApplication)
.......
Procedure InitMenuBar; Virtual; {Перекрываем стандартный метод InitMenuBar}
end;
в которой перекрывается прежний метод InitMenuBar, ответственный за формирование строки меню. И, наконец, в разделе объявлений программы следует поместить описание метода InitMenuBar и видоизменить описание метода InitStatusLine:
Procedure TNotebook.Ini tMenuBar; 
{Создание верхнего меню}
var
R: TRect; 
begin
GetExtent (R) ;
R.B.Y := succ(R.A.Y) ; {R - координаты, строки меню} 
MenuBar := New ( PMenuBar , Init(R, NewMenu ( {Создаем меню}
{Первый элемент нового меню представляет собой подменю (меню второго уровня) . Создаем его} NewSubMenu( '~F~/ Файл', hcNoContext, 
{Описываем элемент главного меню} 
NewMenu ( {Создаем подменю} 
NewItem( {Первый элемент} 
'~1~/ Открыть ', 'F3' , kbF3,cmOpen, hcNoContext, 
NewItem( {Второй элемент} 
'~2~/ Закрыть ', 'F2', kbF2, cmSave,hcNoContext, 
NewItem( {Третий элемент}
'~3~/ Сменить диск' , ' ' , 0, cmChangeDir,hcNoContext, 
NewLine ( {Строка-разделитель} 
NewItem('~4~/ Вызов ДОС' , ' ' , 0, cmDOSShell,
hcNoContext, 
NewItem('~5~/ Конец работы' , 'Alt-X' ,
kbAltX, cmQuit, hcNoContext,
NIL) ) ) ) ) ) {Нет других элементов подменю} ),
{Создаем второй элемент главного меню} 
NewItem( '~W~/ Работа', ' ', kbF4, cmWork, hcNoContext, 
NIL) {Нет других элементов главного меню} )))) 
end; {TNotebook. InitMenuBar}
{---------}
Procedure TNotebook. InitStatusLine;
{Формирует строку статуса} 
var
R: TRect; {Границы строки статуса} 
begin
GetExtent (R,) ; {Получаем в R координаты всего экрана} 
R.A.Y := pred(R.B.Y) ; StatusLine := New(PStatusLine,
Init(R, {Создаем строку статуса} 
NewStatusDef (О, $FFFF, {Устанавливаем максимальный диапазон контекстной справочной службы}
NewStatusKey('~Alt-X~ Выход', kbAltX, cmQuit, 
NewStatusKey('~F2~ Закрыть', kbF2, cmSave, 
NewStatusKey('~F3~ Открыть', kbF3,cmOpen,
NewStatusKey('~F4~ Работа', kbF4,cmWork, 
NewStatusKey('~F10~ Меню', kbF10,cmMenu, NUL))))),{Нет других клавиш} 
NUL){Нет других определений}
));
DisableCommands(WinComl) {Запрещаем недоступные команды} 
end; {TNotebook.InitStatusLine}
В новом варианте программы мы продвинулись дальше по пути конкретизации ее действий. Если Вы запустите программу и нажмете клавиши Alt-F (вызов опции «Файл» главного меню), на экране появится изображение, показанное на   
Определение опций меню во многом напоминает определение командных клавиш в строке статуса. Отличие заключается лишь в том, что с любой опцией меню может быть при необходимости связана встроенная справочная служба. В нашей программе мы не используем эту возможность, для чего задаем стандартный идентификатор hcNoContext (нет контекстно-зависимой справки) при описании каждой опции.
Подобно клавишам строки статуса командные клавиши меню выделяются символом «~». Заметим, что не имеет смысла назначать в качестве командных клавиш клавиши кириллицы, так как при их анализе Turbo Vision игнорирует коды 128...255. Если бы, например, мы задали в качестве командной клавиши для опции «Файл» клавишу «Ф», нажатие Alt-Ф не вызвало бы развертывания подменю, связанного с этой опцией (как и в Турбо Паскале, в Turbo Vision опции главного меню вызываются комбинацией А1t-<клавиша>, а опции меню нижнего уровня - просто нажатием нужной командной клавиши).
Команды
Необходимо пояснить назначение вновь введенных констант стХХХХ. Это так называемые команды, точнее их коды (шифр). Сразу же замечу, что префикс cm в идентификаторах команд не является следствием каких-либо требований со стороны Turbo Vision, просто он принят для предопределенных (стандартных) команд, таких как cmQuit и cmClose. Вновь вводимые команды не являются предопределенными, при их описании я заимствовал стандартный префикс только по соображениям стилистики.
Что же такое команды Turbo Vision? Внимательный анализ предыдущего варианта программы показывает, что.эти коды еще никак не используются, они понадобились лишь для синтаксически правильного обращения к стандартным методам инициации строк меню и статуса. В новом варианте программной реализации Вы можете вызвать любую опцию главного меню или нажать любую командную клавишу - это не приведет ни к каким последствиям: пока работает только команда Alt-X, завершающая работу программы, и клавиши F2, F3 и F10. Происходит это потому, что эти клавиши мы связали со стандартными командами cmQuit, cmSave, cmOpen и стМепи и обрабатываются они где-то внутри Turbo Vision. Новые команды не известны системе, и их обработку мы должны взять на себя.
Как мы увидим дальше, в Turbo Vision есть средства контроля командных клавиш. Эти средства определяют факт нажатия на клавишу с помощью генерации кода соответствующей команды, который (код) будет в этом случае передан нашей программе. Таким образом, обработка команд заключается в расшифровке получаемых от Turbo Vision кодов и передаче управления соответствующим частям программы.
Для шифровки команд в Turbo Vision используется 16-разрядное слово, что позволяет определить до 65535 различных команд. Некоторые из этих кодов зарезервированы для использования внутри Turbo Vision, остальные доступны программисту:


Код команды

Зарезервировано

Можно запретить

0. . .99

Да

Да

100.. .255

Нет

Да

256. . .999

Да

Нет

1000. . .65535

Нет

Нет

Команды с кодами от 0 до 255 при необходимости могут быть временно запрещены, остальные команды запретить нельзя - вот почему используется два диапазона доступных для программиста кодов команд. Временное запрещение команд связано с тем очевидным свойством диалоговых программ, что отнюдь не любая команда может исполняться в каждом возможном состоянии программы. Например, бессмысленно использовать команду «Закрыть файл», если файл еще не открыт. Наоборот, если файл уже открыт, команда «Открыть файл» может стать временно недоступной пользователю. Механизм маскирования (временного запрещения) команд позволяет избавиться от многочисленных проверок контекстуальной корректности тех или иных команд: программист может их запретить впредь до наступления какого-либо события, а запрещенные команды игнорируются средствами Turbo Vision и в программу пользователя не передаются.
В нашей программе имеет смысл запретить команды cmSave и cmWork до тех пор, пока пользователь не откроет нужный файл с данными. Запрет команд достигается обращением к стандартной процедуре DisableCommands (см. предыдущий вариант программы). Указанные в обращении к ней команды задаются в виде множества кодов (мощность любого множества в Турбо Паскале не может превышать 256, вот почему могут быть запрещены только первые 256 команд) и становятся недоступны впредь до обращения к процедуре EnableCommands (разрешить команды).
Запрещенные опции меню (как и временно недоступные командные клавиши) выделяются на экране оттенком (пониженной яркостью).
 
События и их обработка
Весьма важным принципом Turbo Vision является принцип отделения процесса создания видимых изображений от процесса обработки данных. Это означает, что все действия по созданию разнообразных окон, меню и прочих видимых элементов можно осуществлять, не заботясь о тех командах (действиях пользователя), которые будут связаны с ними. Именно так мы поступили при определении меню и строки статуса -коды команд дают возможность распознать соответствующие действия пользователя, однако сами эти действия пока еще никак не раскрыты. И наоборот, мы можем разрабатывать части программы, ответственные за обработку действий пользователя, не связывая прямо эти части с созданием нужных видимых элементов.
Turbo Vision поддерживает два возможных способа действия пользователя - с помощью клавиш клавиатуры и с помощью мыши. Любое такое действие пользователя с точки зрения Turbo Vision приводит к появлению события, т.е. к созданию небольшого информационного пакета, описывающего вновь возникшую ситуацию. События распространяются от одной части программы к другой до тех пор, пока не обнаружится подпрограмма, ответственная за обработку данного события. Эта подпрограмма обычно очищает информационный пакет и таким образом блокирует дальнейшее перемещение события.
Пожалуй, именно механизм событий кардинально отличает Turbo Vision от других библиотек Турбо Паскаля. На первых порах это может вызвать определенные трудности, связанные с отладкой программ. Принцип независимости обработки событий от процесса создания видимых элементов приводит фактически к появлению двух параллельных процессов в рамках одной программы: процесса создания видимых элементов и процесса обработки событий. Говоря о программах Turbo Vision, следует помнить, что эти программы управляются событиями. Их трассировка (прослеживание работы) в среде Турбо Паскаль обычно достигается установкой и использованием контрольных точек.

Подпрограммы, ответственные за обработку действий пользователя, называются обработчиками событий. Любой стандартный для Turbo Vision объект, обеспечивающий создание видимого элемента, имеет собственный обработчик

событий (виртуальный метод HandleEvent), который Вы можете перекрыть своим собственным методом, если Вас не устраивает стандартная реакция объекта на то или иное событие. Существует такой метод и в объекте TNotebook. По умолчанию этот объект использует обработчик событий, унаследованный им от объекта-родителя TApplication. Стандартный обработчик знает, как реагировать на команды cmQuit и стМепи, но ему не известны новые команды cmWork, cmOpenFile и другие. Чтобы программа смогла правильно обработать эти команды, мы должны перекрыть стандартный метод HandleEvent объекта TNotebook новым. Добавим в описание объекта TNotebook еще одну строку
type
TNotebook = object (TApplication)
.......
Procedure HandleEvent(var Event: TEvent); Virtual; 
end;
и поместим в раздел объявлений текст новой подпрограммы:
Procedure TNotebook.HandleEvent(var Event: TEvent); 
{Обработчик событий программы} 
begin {TNotebook.HandleEvent} 
Inherited HandleEvent(Event);{Обработка стандартных команд cmQuit и cmMenu}
if Event.What = evCommand then 
case Event.Command of
{Обработка новых команд:}
cmOpen : FileOpen; {Открыть файл}
cmSave:FileSave; {Закрыть файл}
cmChangeDir:ChangeDir; {Сменить диск}
cmDOSShell:DOSCall; {Временный выход в ДОС}
cmWork:Work; {Обработать данные} 
else
exit {Не обрабатывать другие команды} 
end;
ClearEvent (Event) {Очистить событие после обработки}
end; {TNotebook.HandleEvent}
Чтобы новый вариант программы можно было выполнить, следует предусмотреть «заглушки» для несуществующих пока процедур FileOpen, FileSave и т.д. Например:
Procedure FileOpen;
begin
end;
Поведение вновь созданного варианта программы внешне ничем не отличается от предыдущего: также будут созданы меню, строка статуса и основное поле экрана, программа по-прежнему будет распознавать команды Alt-X и F10. Однако теперь она будет реагировать и на новые команды. Чтобы убедиться в этом, установите контрольные точки в заглушках FileOpen и FileSave и запустите программу вновь: нажатие на клавишу F3 вызовет останов в контрольной точке FileOpen - ведь именно с этой клавишей мы связали команду cmOpen в процедуре InitStatusLine, в то время как нажатие на клавишу F2 не приведет к срабатыванию контрольной точки FileSave, поскольку команда cmSave пока еще запрещена и обработчик HandleEvent ее просто не «увидит».
Чтобы использовать нестандартные команды меню или строки статуса, мы должны перекрыть обработчик событий программы, в новом обработчике выделить из потока событий команды и распознать их коды.
Чтобы стали более понятны действия обработчика событий, отметим, что тип TEvent в Turbo Vision определен как запись такого вида:
type
TEvent = record 
What: Word; {Определяет тип события} 
case Word of {"Пустое" событие} 
evMouse: ( {Событие от мыши:} 
Buttons: Byte; {Состояние кнопок} 
Double: Boolean;{Признак двойного нажатия кнопки мыши}
Where: TPoint); {Координаты курсора мыши} 
evKeyDown: ( {Событие от клавиатуры:} 
case Integer of
0: (KeyCode: Word);{Код клавиши} 
1: (CharCode: Byte; ScanCode: Byte)); 
evMessage: ( {Событие-сообщение:} 
Command: Word; {Код команды} 
case Word of
0:(InfoPtr: Pointer); 
1:(InfoLong: Longlnt); 
2:(InfoWord: Word); 
3:(Infolnt: Integer);
4:(InfoByte:Byte);
5:(InfoChar:Char));
end;
Стандартная маска evCommand позволяет выделить из потока событий только те, которые связаны с передачей команд между различными обработчиками событий. Именно таким способом стандартный обработчик TApplication.HandleEvent сообщает новому обработчику TNotebookHandleEvent о возникновении события, связанного с вновь определенной командой. Если бы мы не предусмотрели вызов стандартного обработчика с помощью оператора
Inherited HandleEvent(Event);
нам пришлось бы самим анализировать положение мыши или нажатую клавишу и интерпретировать их как соответствующие команды. Включение вызова TApplication.HandleEvent в тело нашего обработчика событий избавляет нас от этой рутинной работы.
В конце обработчика мы вызвали стандартную процедуру ClearEvent, с помощью которой в переменную Event помещается сообщение Nothing («пустое» событие). Это событие игнорируется всеми обработчиками, так что программа будет повторять проверку состояния мыши и клавиатуры до тех пор, пока не произойдет нового события. Фактически тело процедуры TApplication.Run (см. раздел исполняемых операторов нашей программы) состоит из бесконечно повторяющегося цикла проверки мыши и клавиатуры и передачи событий по цепи обработчиков событий. После получения любого события обработчик должен либо обработать это событие и очистить переменную Event, либо просто вернуть управление обработчику верхнего уровня, если эта команда не предназначена для него, либо, наконец, сформировать и передать новое событие для реализации команд, которые распознаны им, но которые он выполнять не умеет или не должен.
Программирование диалоговых запросов
В обработчике событий TNotebook.HandleEvent мы предусмотрели вызовы нескольких процедур, с помощью которых реализуются конкретные действия программы. Настала пора запрограммировать эти действия.
Начнем с процедуры FileOpen. Ее задача - выбрать один из возможных файлов с данными и подготовить его к работе. Конечно, программу можно было бы сделать менее гибкой, раз и навсегда «привязав» ее к какому-то одному файлу, скажем, с именем notebook.dat. Но даже и в этом случае следует решить проблему с местоположением файла данных, а также определить, что должна делать программа, если нужный файл не найден. Наша программа будет весьма гибкой в этом отношении: она позволит указать интересующий нас файл мышью или клавишами курсора, либо ввести имя файла с помощью клавиатуры или взять его из буфера ранее введенных имен. Иными словами, поведение нашей программы будет в точности повторять поведение среды Турбо Паскаль в момент нажатия на клавишу F3.
Если Вы когда-либо программировали подобные действия в Турбо Паскале, Вы по достоинству оцените простоту их реализации в Turbo Vision:
Procedure FileOpen; {Открывает файл данных} 
var
PF: PFileDialog; {Диалоговое окно выбора файла} 
Control: Word; 
s: PathStr; 
begin
{Создаем экземпляр динамического объекта:} 
New(PF, Init('*.dat','Выберите нужный файл:','Имя файла',fdOpenButton,0)); 
{С помощью следующего оператора окно выводится на экран и результат работы пользователя с ним помещается в переменную Control:} 
Control := DeskTop.ExecView(PF); 
{Анализируем результат запроса:} 
case Control of
StdDlg. cmFileOpen, cmOk: 
begin {Пользователь указал имя файла:}
PF.QetFileName(s) ; {s содержит имя файла}
{-----------} {Открыть файл}
end;
end; {case Control} 
Dispose (PF, Done) {Уничтожаем экземпляр} 
end; {FileOpen}
Для реализации этого фрагмента необходимо указать имя модуля StdDlg в предложении Uses - в этом модуле описан тип PFileDialog и предусмотрены все необходимые методы для работы с ним. Кроме того, в программе используется переменная S типа PathStr. Этот тип описан в модуле DOS - сошлитесь также и на него. Сделайте нужные изменения в тексте программы, не раскрывая пока сущности действий
{Открыть файл}
запустите программу на счет и нажмите клавишу F3 - экран приобретет вид, показанный на  3.
Тип PFileDialog - это указатель на объект TFileDialog, создающий и обслуживающий стандартное диалоговое окно выбора файлов. Все действия по созданию и использованию диалогового окна, показанного на  3, реализуются двумя операторами:
NewfPF, Init('*.dat','Выберите нужный файл:',
'Имя файла',fdOpenButton, 0)); 
Control := DeskTopA.ExecView(PF);
Первый оператор инициирует новый экземпляр объекта TFileDialog. Три строковых параметра обращения к конструктору Init этого объекта задают, соответственно, маску выбираемых файлов ('*.dat'), заголовок диалогового окна ('Выберите нужный файл:') и заголовок окна ввода ('Имя файла'). Параметр fdOpenButton указывает на необходимость включить в диалоговое окно кнопку Open. Последним параметром задается идентификатор протокола ввода. Доступ к этому протоколу открывается кнопкой [|] справа от окна ввода. Сам протокол хранится в куче в виде последовательности вводившихся ранее текстовых строк. Идентификатор протокола ввода позволяет при необходимости использовать один и тот же протокол в разных диалоговых окнах.
Второй оператор
Control := DeskTop.ExecView(PF);
помещает вновь созданное окно в основное поле экрана программы (ссылка DeskTop) и инициирует диалог с пользователем. Результат диалога возвращается в переменной Control, значение этой переменной анализируется оператором
case Control of
.......
end;
Если Control содержит коды команд cmOk или cmFileOpen, то с помощью метода GetFileName объекта TFileDialog в переменную S записывается полное имя файла (с предшествующим путем).
В методе TFileDialog.GetFileName (var Name: Pathstr) параметр обращения должен иметь тип PathStr. Этот тип определен в модуле DOS,- вот почему нам понадобилось сослаться на этот модуль в предложении Uses. Если указать компилятору на необходимость смягчить проверку строковых типов (директива компилятора {$V-}), то при обращении к GetFileName можно использовать переменнуюлюбого строкового типа, в том числе String.
Перед выходом из процедуры FileOpen экземпляр объекта TFileDialog уничтожается (удаляется из кучи) обращением к деструктору Done.
По описанной схеме в Turbo Vision создаются и используются любые другие диалоговые окна.
Для реализации диалогового запроса необходимо создать диалоговое окно и с помощью функции ExecView объекта-владельца (программы) инициировать диалог с пользователем. Результат, возвращаемый этой функцией, будет содержать выбранную пользователем команду.
Чтобы запрограммировать действия, связанные с открытием файла, следует вначале решить, какие именно данные он будет содержать. Напомню, что мы разрабатываем диалоговую программу управления «записной книжкой». Структура типичной записи в такой книжке состоит из трех полей: имя, телефон, адрес. Учитывая это, будем считать, что данные в файле хранятся в виде следующих записей:
const
LName = 25;{Длина поля Name}
LPhone= 11;{Длина поля Phone}
LAddr =40;{длина поля Addr}
type
DataType = record {Тип данных в файле}
Name : String[LName]; {Имя}
Phone: String[LPhone] {Телефон} 
Addr : String[LAddr] {Адрес}
end;
Поместим эти строки в начале программы, а перед описанием процедуры FileOpen вставим определения следующих глобальных переменных:
var
DataFile: file of DataType; {Файловая переменная} 
OpFileF : Boolean; {Флаг открытого файла}
Дополним текст процедуры FileOpen такими строками:
case Control of
StdDlg.cmFileOpen,cmOk: 
begin
PFA.GetFileName(s);
Assign(DataFile,s); {Отсюда начинаются новые строки}
{$I-}
Reset(DataFile);
if lOResult <> 0 then
Rewrite{DataFile); OpFileF := IOResult=0; 
{$I+}
if OpFileF then 
begin
DisableCommands(WinCom2);
EnableCommands(WinComl)
end
end; 
end;
С помощью оператора DisableCommands мы временно запрещаем набор команд, указанный в константе WinComl. Эта константа в нашем случае должна содержать команду стОреn; ее определение нужно включить сразу за определением константы WinComl:
const
WinComl: TCommandSet = [cmSave, cmWork]; 
WinCom2: TCommandSet = [cmOpen];
Обращение к процедуре EnableCommands разрешает использовать команды cmSave vicmWork.
 
Инкапсуляция новых полей и методов
При попытке откомпилировать полученный вариант программы Турбо Паскаль сообщит о неизвестном идентификаторе DisableCommands. На первый взгляд это кажется странным - ведь аналогичное обращение в обработчике событий TNotebook.HandleEvent не вызывало проблем! Все дело в том, что мы работаем с объектами, а следовательно, здесь очень важным становится контекст программ. Обработчик TNotebook-HandleEvent - это метод объекта TNotebook, который унаследовал от своих родителей многие свойства, в том числе и метод DisableCommands. Процедура FileOpen не является потомком объектов Turbo Vision и не имеет доступа к их полям и методам.
В Turbo Vision все новые процедуры обычно инкапсулируются в объекты., если в них необходимо получить доступ к специфическим средствам этих объектов.
Поскольку процедура FileOpen вызывается из обработчика событий объекта TNotebook, нам следует включить ее в виде нового метода этого объекта:
type
TNotebook = object(TApplication)
.......
Procedure FileOpen; 
Procedure FileSave; 
Procedure ChangeDir; 
Procedure DOSCall; 
Procedure Work; 
end;
В этом фрагменте мы инкапсулировали в объект все методы, используемые обработчиком событий. Разумеется, необходимо соответствующим образом изменить заголовок процедуры FileOpen, поскольку она теперь стала методом объекта TNotebook:
Procedure TNotebook.FileOpen;
Аналогичным образом следует изменить и заголовки других инкапсулированных процедур. Теперь трансляция пройдет успешно, а после открытия файла станет недоступна команда F3.
Тексты двух других новых методов объекта TNotebook не нуждаются в особых комментариях:
Procedure TNotebook.FileSave; 
{Закрывает файл данных} 
begin
Close(DataFile);
OpFileF := False;
EnableCommands(WinCom2); {Разрешаем открыть файл}
DisableCommands(WinComl) {Запрещаем работу и сохранение} 
end; {TNotebook.FileSave}
{-----------}
Procedure TNotebook.ChangeDir; 
{Изменяет текущий каталог} 
var
PD: PChDirDialog; {Диалоговое окно смены каталога/диска}
Control: Word; 
begin
New(PD, Init(cdNormal,0));{Создаем диалоговое окно}
Control := DeskTop.ExecView(PD){Используем окно}
ChDir(PD.Dirlnput.Data);{Устанавливаем новый каталог}
Dispose(PD, Done){Удаляем окно из кучи} 
end; {TNotebook.ChangeDir}
Несколько слов по поводу реализации процедуры TNotebook. ChangeDir. В ней используется объект TChDirDialog, входящий в модуль StdDlg. С помощью этого объекта создается диалоговое окно, позволяющее выбрать новый диск или каталог. После создания и использования экземпляра объекта TChDirDialog в его поле
Dirlnput.Data
устанавливается строка типа PathStr, задающая новый каталог (и, возможно, новый диск).
Чуть сложнее обстоит дело с процедурой DOSCall, которая должна реализовать временный выход в ДОС. Дело в том, что перед выходом необходимо сохранить в куче текущее состояние программы, а после возврата нужно восстановить состояние программы, в том числе и вид экрана. Чтобы реализовать имеющиеся в Turbo Vision средства сохранения и восстановления программы, в предложение Uses необходимо добавить ссылку на модуль Memory. Вот текст метода TNotebooLDOSCall:
Procedure TNotebook.DOSCall;
{Временный выход в ДОС} 
const
txt ='Для возврата введите EXIT в ответ'+' на приглашение ДОС...'; 
begin
DoneEvents;{Закрыть обработчик событий}
DoneVideo;{Закрыть монитор экрана}
DoneMemory;{Закрыть монитор памяти}
SetMemTop(HeapPtr) ;{Освободить кучу}
WriteLn(txt);{Сообщить о выходе}
SwapVectors;{Установить стандартные векторы}
{Передать управление командному процессору ДОС:}
Exec(GetEnv('COMSPEC'),''); 
{Вернуться из ДОС:}
SwapVectors; {Восстановить векторы) 
SetMemTop(HeapEnd); {Восстановить кучу} 
InitMemory; {Открыть монитор памяти}
InitVideo;{Открыть монитор экрана} 
InitEvents;{Открыть обработчик событий} 
InitSysError;{Открыть обработчик ошибок}
Redraw {Восстановить вид экрана} 
end; {DOSCall}
Процедуры DoneXXXX завершают работу отдельных частей Turbo Vision, а процедуры InitXXXXосуществляют обратные действия. С помощью процедуры SetMemTop в ДОС передается информация о фактически используемой динамической памяти (по умолчанию программе предоставляется вся доступная память). Этот вызов освобождает неиспользуемую в данный момент часть кучи для размещения в ней командного процессора COMMAND.COM. После возврата из ДОС вызов SetMemTop используется еще раз - для того, чтобы зарезервировать за программой всю ранее выделенную ей память. Процедура Redraw восстанавливает все видимые элементы экрана.
 
Создание и использование групп
Пора заняться основной содержательной частью нашей программы - процедурой Work. Прежде всего следует продумать способ взаимодействия пользователя с данными (интерфейс пользователя). От удачного выбора интерфейса во многом зависит успех разработки диалоговых программ: неудобный способ доступа, связанный с необходимостью ввода каких-либо команд или ответов на многочисленные вопросы, надолго отобьет у пользователя всякое желание работать с программой. Turbo Vision предоставляет в Ваше распоряжение все необходимые средства для разработки современного объектно-ориентированного диалога. В ходе такого диалога пользователь видит на экране объекты, о которых идет речь, он может указать на любой объект и выбрать те действия, которые нужно осуществить над ним.
При работе с электронной записной книжкой хотелось бы, чтобы на экране появилось сразу несколько записей, отсортированных в алфавитном порядке. Пользователь должен иметь возможность «листать» книжку, отыскивать в ней нужную запись, добавлять новые и исключать ненужные записи, редактировать их (вносить изменения). Таким образом, ядром диалога должно стать окно с текстом. При необходимости пользователь может смещать текст в окне в ту или иную сторону, перемещать само окно относительно границ экрана, менять его размеры. Все эти возможности типичны для многочисленных текстовых редакторов, систем программирования, систем управления базами данных и т.п.
Для реализации этих действий в Turbo Vision предусмотрен специальный объект TWindow, экземпляры которого отображаются на экране в виде прямоугольного окна с рамкой и стандартными кнопками изменения размера и закрытия окна. Попробуем создать такое окно в нашей программе. Для этого изменим текст процедуры Work следующим образом:
Procedure TNotebook.Work; 
{Работа с данными}
var
R: TRect; 
begin
R.Assign(0,0,80,23);
Desktop.Insert(New(PWindow,Init(R,'',0)))
end; {Work}
После запуска программы нажмите клавишу F3, укажите в диалоговом окне имя несуществующего файла (файл данных пока еще не создан), нажмите клавиши Enter и F4 - экран приобретет вид, показанный на  4.
Если Ваш ПК оснащен устройством ввода типа мышь, Вы можете перемещать это окно по экрану (надо «схватить» мышью верхнюю рамку окна, т.е. подвести к ней указатель мыши, нажать левую кнопку и, удерживая кнопку нажатой, перемещать мышь), изменять его размеры («схватить» правый нижний угол), использовать стандартные кнопки изменения размера (справа на верхней рамке) и закрытия окна (слева). Ничего другого окно не умеет. А как загрузить в него текст? Как получить хорошо знакомые по среде Турбо Паскаль полосы-указатели и управлять с их помощью положением текста? Для этих целей можно было бы использовать объект TScroller, представляющий собой окно с текстом и с двумя полосами-указателями. Однако по умолчанию такое окно не имеет рамки, а потому не может изменять своего размера, в нем нет стандартных кнопок изменения размера и закрытия окна. Таким образом, и объект TScroller не решает всех проблем. Каков же выход? Нужно создать новый объект, объединяющий в себе свойства и TWindow, и TScroller! В терминах Turbo Vision такие составные объекты называются группами.
Введем в программу следующий объект:
type
PWorkWin =TWorkWin; 
TWorkWin = object (TWindow) 
Constructor Init(Bounds: TRect); 
end;
Новый объект является потомком TWindow и, следовательно, наследует все свойства родителя, в том числе рамку и способность перемещения по экрану. Дополнительные свойства ему должен придать новый конструктор TWorkWin.Init, которому мы в качестве параметра передаем начальное положение и размеры создаваемого окна:
Constructor TWorkWin.Init(Bounds: TRect);
{Создание окна данных}
var
HS,VS: PScrollBar; {Полосы-указатели}
Interior: PScroller; {Указатель на управляемое текстовое окно} 
begin
TWindow.Init(Bounds,'',0); {Создаем новое окно с рамкой}
GetClipRect(Bounds){Получаем в BOUNDS координаты минимальной перерисовываемой части окна}
Bounds.Grow(-1,-1){Устанавливаем размеры окна с текстом}
{Включаем стандартные по размеру и положению полосы-указатели:}
VS := StandardScrollBar(sbVertical+sbHandleKeyBoard);
HS := StandardScrollBar(sbHorizontal+sbHandleKeyBoard); 
{Создаем текстовое окно:}
Interior := New(PScroller,Init(Bounds, HS, VS)); 
Insert(Interior) {Включаем его в основное окно} 
end; {TWorkWin.Init}

С помощью вызова процедуры GetClipRect мы получаем размеры минимального прямоугольника, который следует обновлять при любых перемещениях окна или изменениях его размера. Такой вызов позволяет до минимума сократить время вывода. Процедура Bounds.Grow изменяет вертикальный и горизонтальный размеры прямоугольника Bounds: при положительном параметре соответствующий размер увеличивается, при отрицательном - уменьшается. Параметры -1,-1 учитывают рамку основного окна. Функция StandardScrollBar создает указатель на управляющую полосу стандартного размера. При обращении к ней параметр sbVertical (sbHorizontal) определяет положение полосы, а параметр sbHandleKeyboard разрешает использование клавиатуры для управления ею (если этот параметр не включить, полоса будет управляться только с помощью мыши). Наконец, процедура Insert включает вновь созданное окно TScrollBar в основное окно TWindow, так что теперь оба окна будут функционировать как одно целое.
Для создания группы необходимо в объект-потомок от TGroup (обычно - это объект TWindow или потомок от него) вставлять нужные элементы с помощью метода Insert.
Осталось лишь нужным образом изменить процедуру Work:
Procedure TNotebook.Work;
{Работа с данными}
var
R: TRect;
PW: PWorkWin; 
begin
R.Assign(0,0,80,23) ;
PW := New(PWorkWin, Init(R));
DeskTop.Insert(PW) 
end; {Work}
Если исполнить подготовленную таким образом программу, на экране появится изображение, показанное на  5.
Вывод текста
По сравнению с  4 мы добились немногого, ведь пока еще не решена главная проблема - вывод нужного текста. Разумеется, в Вашем распоряжении всегда имеется процедура WRITELN, однако вывод текста «в лоб» с помощью этой процедуры практически никогда не используется в Turbo Vision, так как в этом случае выведенный текст не будет связан с окнами.
В объекте TScroller для вывода текста предусмотрен абстрактный метод Draw. Абстрактным он называется потому, что не выполняет никакой полезной работы. Однако именно к этому методу обращается обработчик событий объекта TScroller всякий раз, когда понадобится обновить на экране вид окна. Чтобы объект выполнял все заложенные в него функции, нам необходимо перекрыть этот метод новым. Мы уже знаем, что для этого нужно объявить новый объект:
type
PInterior =ATInterior; TInterior = object (TScroller)
Constructor Init(var Bounds: TRect; HS,VS: PScrollBar);
Procedure Draw; virtual;
Procedure ReadFile; 
end;
Мы перекрыли абстрактный метод Draw, стандартный конструктор Init и инкапсулировали в объект новый метод ReadFile. Новый конструктор предназначен для инициации экземпляра объекта TScroller. Кроме того, с помощью метода ReadFile он должен прочитать все записи файла данных и подготовить соответствующий массив строк - это сократит время на обновление текста процедурой Draw.
Перед тем, как двигаться дальше, подумаем о способе хранения строк для процедуры Draw. Если все необходимые действия по чтению нужной записи из файла и преобразования ее к текстовому формату возложить на процедуру Draw, наша программа станет слишком медленной, в особенности, если файл данных записан на дискете. Поэтому предусмотрим такие глобальные переменные:
const
MaxLine = 300; {Максимальная длина массива} 
LLine = LName+LPhone+LAddr; {Длина строки} 
var
NLines: Word; {Истинная длина массива строк} 
Lines: array [1..MaxLine] of String [LLine]; {Массив строк}
Теперь нетрудно подготовить процедуру ReadFile:
Procedure TInterior.ReadFile;
{Читает содержимое файла данных в массив Lines}
var
k: Integer; s: String;
Data: DataType; 
begin
seek(DataFile, 0) ;
NLines := FileSize(DataFile);
if NLines > MaxLine then
NLines := MaxLine; 
for k ':= 1 to NLines do 
begin
Read(DataFile, data); 
with data do 
begin
s := Name;
while Length(s) < LName do
s := s+' '; 
s := s+Phone; 
while Length(s) < LName+LPhone do
s := s+' '; 
s := s+Addr 
end;
Lines[k] := s 
end; 
end; {ReadFile}
В этой процедуре из записей файла данных готовится массив строк Lines, причем начало каждого поля выравнивается так, чтобы поля образовали колонки - такая форма вывода поможет легко найти на экране каждое поле.
Теперь займемся процедурой Draw:
Procedure TInterior.Draw; 
{Выводит данные в окно просмотра}
var
n, {Текущая строка экрана} 
k: Integer; {Текущая строка массива}
В: TDrawBuffer; Color: Byte; 
begin
Color := GetColor(l); {Использовать цвет основного текста} 
for n := 0 to pred(Size.Y) do 
{Size.Y - количество строк окна} 
begin
k := Delta.Y+n+1; {Delta.Y - номер первой выводимой строки} 
MoveChar(B,' ',Color,Size.X);
MoveStr(B, Copy(Lines[k],Delta.X+l,Size.X),Color); 
WriteLine(0,N,Size.X,l,B) 
end 
end; {TInterior.Draw}
Работа процедуры основана на использовании текущих размеров и положения текстового окна относительно текста. Эти параметры хранятся в полях Size и Delta объекта TScroller и обновляются всякий раз, когда пользователь манипулирует полосами управления или изменяет размеры окна. Для вывода текста используются три процедуры: MoveChar, MoveStr, WriteLine. Каждая из них оперирует переменной В типа TDrawBuffer, представляющей собой последовательности кодов выводимых символов и их атрибутов. Процедура MoveChar заполняет переменную В указанным символом (' ') и атрибутом (Color). Процедура MoveStr копирует строку в переменную В, а с помощью WriteLine осуществляется вывод буфера В на экран.
Для вывода изображений (текста) перекрывайте и используйте метод Draw объекта-владельца нужной части экрана. Это обеспечит автоматическое изменение изображения и его прорисовку при изменении границ или положения поля вывода. 
Цветовая палитра
В процедуре Draw переменная Color задает атрибуты (цвет символов и цвет фона) символов, выводимых с помощью методов MoveChar и MoveStr. С помощью функции GetColor она устанавливается таким образом, чтобы символы на экране отображались цветовым сочетанием с номером 1. В Turbo Vision используется гибкая система установки цвета отдельных видимых элементов. Элемент изображения связывается не с каким-то конкретным цветом, а с индексом в таблице цветов, называемой палитрой. Количество элементов палитры зависит от количества цветовых сочетаний, используемых при выводе элемента изображения. Например, в TScroller используется двухэлементная палитра цветов: первый элемент устанавливает цвет нормального текста, второй - выделенного текста ( 6).
 
Числа 6 и 7 в этой палитре указывают не конкретные цвета, а номера позиций в палитре объекта-владельца. Для нашего случая объектом-владельцем будет TWindow. Таким образом, цвет номер 1 палитры TScroller лишь указывает на шестое по счету цветовое сочетание в палитре TWindow ( 7).
Шестой элемент палитры TWindow в свою очередь ссылается на 13-й элемент палитры своего владельца - TProgram. Объект TProgram - это начальный видимый элемент любой программы в Turbo Vision. На нем заканчивается любая цепочка ссылок, т.е. его палитра содержит конкретные атрибуты символов. Тринадцатый элемент этой палитры содержит значение $1Е, что соответствует выводу желтого символа на синем фоне - именно таким образом отображается нормальный текст в окне TScroller, если это окно вставлено в TWindow. Если бы объект TScroller был помещен непосредственно на панель экрана, то значение 6 в первом элементе палитры TScroller указывало бы на 6-й элемент палитры TProgram, содержащий атрибуты $28 (темно-серые символы на зеленом фоне). Цветовые палитры в Turbo Vision содержат такие значения по умолчанию, чтобы любая комбинация цветов давала приятную цветовую гамму. При необходимости пользователь может изменить любую цветовую палитру. Вернемся к нашему примеру и рассмотрим реализацию конструктора Init:
Constructor TInterior.Init(var Bounds: TRect;
HS,VS: PScrollBar); 
{Создает окно для данных} 
begin
Inherited Init(Bounds, HS, VS) ;
ReadFile;
GrowMode := gfGrowHiX + gfGrowHiY;
SetLimit(LLine,NLines) 
end; {Tinterior.Init}
Объект TScroller имеет поле GrowMode, которое определяет, как элемент будет изменять свои размеры, если пользователь потребует этого. Параметр gfGrowHiX предписывает окну TScroller изменяться таким образом, чтобы правая его граница всегда находилась на постоянном расстоянии от правой границы владельца. Точно также gfGrowHiY задает неизменным расстояние нижней границы окна TScroller от нижней границы владельца. Таким образом, окно TScroller всегда будет занимать всю внутреннюю часть окна-владельца TWindow. С помощью процедуры SetLimit (X, Y) мы задаем горизонтальную Х и вертикальную У границы перемещения окна относительно текста. Эти границы будут выдерживаться при управлении окном с помощью клавишей или мыши: какими бы не были текущие размеры окна, нажатие на клавишу End, например, смещает его вправо так, чтобы самым правым видимым символом был Х-й символ текста. Нажатие на клавиши Ctrl-PgDn смещает окно вниз по тексту таким образом, чтобы самая нижняя строка окна соответствовала Y-й строке текста. Иными словами, параметры X и Y задают координаты правого нижнего угла виртуального (воображаемого) экрана неограниченных размеров, на котором находится текст и по которому «скользит» окно. Левый верхний угол виртуального экрана всегда имеет координаты (0,0).
Осталось отредактировать конструктор TWorkWinJnit: нужно изменить тип переменной Interior
var
.......
Interior: PInterior; 
и обращение к конструктору:
Interior := New(PInterior, Init(Bounds, HS, VS));
Но не спешите запускать программу на счет: ведь файла данных пока еще нет, а поэтому Вы ничего не увидите на экране. Чтобы все-таки оценить достигнутые результаты, измените текст процедуры ReadFile - добавьте в него следующие строки:
Procedure TInterior.ReadFile; 
{Читает содержимое файла данных}
 var
.......
f: text;
begin
s := copy(ParamStr(0),l,pos('.',ParamStr(0)))+'pas'; 
assign(f,s);
reset(f); {Открываем файл с текстом программы} 
NLines := 0;
while not EOF(f) and (NLines < MaxLine) do 
begin
inc(NLines);
ReadLn(f/Lines[NLines]) 
end;
close (f) ; 
exit;
.......
end; {ReadFile}
Добавленные строки заставят процедуру прочитать в массив Lines текст самой программы (если Вы будете запускать программу из среды Турбо Паскаль, не забудьте установить компиляцию в дисковый файл опцией COMPILE/DESTINATION, иначе оператор
s:=copy(ParamStr(0),l,pos('.',ParamStr(0)))+'pas';
не сможет установить в S правильное имя файла с текстом Вашей программы). После запуска программы нажмите клавишу F3, задайте имя несуществующего файла, нажмите клавиши Enter и F4 - на экране появится изображение, показанное на  8.
Это окно откликается на нажатие клавиш управления курсором, команды PgUp, PgDn, Ctrl-PgUp и т.д. подобно тому, как ведет себя окно редактора в среде Турбо Паскаль. С помощью мыши Вы можете перемещать его по экрану, изменять размеры, закрывать - все эти действия реализует стандартный обработчик событий объекта TScroller.

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика