Контекстная помощь

В Turbo Vision предусмотрены средства, облегчающие создание контекстно-зависимой справочной службы. С этой целью каждый видимый элемент имеет специальное шестнадцатиразрядное поле TView.HelpCtx, содержимым которого Вы можете распоряжаться по своему усмотрению. Обычно каждому видимому элементу присваивается свой код (целое число в диапазоне от 0 до 65535), устанавливаемый в поле HelpCtx. В этом случае при нажатии на заранее обусловленную командную клавишу, открывающую доступ к справочной службе (обычно это клавиша F1), программа может получить текущий контекст (прямым чтением поля HelpCtx или с помощью метода GetHelpCtx) и передать его в качестве параметра вызова справочной службе.

Где обрабатывать событие, связанное с нажатием клавиши вызова справочной службы? Идеальным местом для этого является источник всех событий - метод GetEvent. Этот метод связан с любым видимым элементом, в том числе и с терминальным видимым объектом, и поэтому без труда может получить текущий контекст.

В следующем примере на экране создается диалоговое окно с двумя кнопками. Клавиша F1 используется для доступа к справочной службе. Если активна (выбрана) левая кнопка, нажатие на F1 даст сообщение «Левая кнопка», если правая - «Правая кнопка». Если на экране нет диалогового окна (оно вызывается клавишей F2), появится сообщение «Нет окна».

Uses CRT,App,Dialogs,Obj ects,Drivers,Views,Menus; 

type

PProg = TProg;

TProg = object (TApplication)

Procedure HandleEvent(var Event: Tevent); Virtual; 

Procedure GetEvent(var Event: Tevent); Virtual; 

Procedure InitStatusLine; Virtual;

end;

Procedure TProg.HandleEvent(var Event: TEvent); 

Procedure Dialoglnit; 

var

R: TRect;

Dia: PDialog; 

B1,B2: PButton;

с: Word; 

begin

ClearEvent(Event);

R.Assign(20,9,60,17);

Dia := New(PDialog, Init(R,''));

R.Assign(3,4,19,6);

Bl := New(PButton,Init(R,'Левая',0,0));

El*.HelpCtx := 1;

DiaA.insert (B1);

R.Assign(20,4,35,6);

B2 := New(PButton,Init(R,'Правая',0,0));

В2. HelpCtx := 2;

Dia.Insert (B2) ; 

с := ExecView(Dia) 

end ; {Dialоg Init} 

begin {TProg.HandleEvent }

TApplication.HandleEvent (Event) ; 

if (Event. What = evCommand)

(Event. Command = cmMenu) then 

Dialoglnit

end; {TProg. Handl eEvent} 

Procedure TProg. InitStatusLine; 

var

R: TRect; 

begin

GetExtent (R) ; 

R.A.Y := pred(R.B.Y) ;

StatusLine := New(PStatusLine, Init(R, 

NewStatusDef (О, О, {Начальная строка статуса} 

NewStatusKey ( ' ~Alt-X~ Выход' , kbAltX, cmQuit, 

NewStatusKey ( '~F1~ Справка' , kbFl,cmHelp, 

NewStatusKey ( '~F2~ Окно диалога' , kbF2, cmMenu, NIL))), 

NewStatusDef (1, 2 , {Строка статуса с диалоговым окном} 

NewStatusKey ( ' ~Esc~ Выход' , kbEsc, cmCancel, 

NewStatusKey ('~F1~ Справка' , kbFl, cmHelp, NIL)), .NIL))));

end; {TProg. InitStatusLine}

Procedure TProg. GetEvent (var Event: TEvent) ; 

const

txt: array [0..2] of String = ('Нет окна', 'Левая кнопка' , 'Правая кнопка'); 

begin

TApplication. GetEvent (Event) ; 

if Event . Command = cmHelp then 

begin

GotoXY(60,l) ; 

TextColor (Black+Blink); 

TextBackGround (White) ; 

Write (Txt [GetHelpCtx] ) ; 

Delay (2000) ; 

GotoXY(60,l) ; 

Write ('                  ') 

end

end; {TProg. GetEvent} 

var

Prog: TProg; 

begin

Prog.Init; 

Prog . Run ; 

Prog . Done 

end.

Для упрощение программы справочное сообщение выводится стандартными средствами Турбо Паскаля. Сообщение появляется в верхнем правом углу экрана и через 2 сек стирается, в течение этого промежутка времени доступ к клавиатуре и мыши блокируется.

Контекст видимого элемента может управлять содержимым строки статуса. С этой целью в методе InitStatusLine используется два или более вызова NewStatusDef со своим диапазоном контекста (см. предыдущий пример).

В состав демонстрационных модулей Turbo Vision включен файл HelpFile.pas и компилятор TVHC.pas, существенно упрощающие процесс создания и использования контекстно-чувствительной помощи.

Средства модуля HelpFile позволяют по заданному контексту найти в особом файле справочной службы нужную справку и вывести ее на экран. Текст справки помещается в окно со скроллером, границы которого могут изменяться. Справочная служба контролирует размер окна и форматирует текст так, чтобы строки не выходили за границы окна. В тексте справки могут использоваться перекрестные ссылки, представляющие собой выделенные цветом фрагменты текста. Справочная служба обеспечивает доступ к этим ссылкам так, как это реализовано в среде Турбо Паскаля: ссылку можно выбрать клавишей Tab или отметкой мышью, после чего нажатие на Enter приведет к раскрытию нового справочного окна с соответствующей справкой.

Для использования этих средств необходимо предварительно создать файл справочной службы, содержащий текстовые данные и средства управления ими. Файл справочной службы создается программой TVHC.PAS из обычного текстового файла, в котором используются следующие соглашения:

Заголовок темы содержит идентифицирующее справку уникальное кодовое слово, и связанный с ним контекст. Например:

.topic Viewer=2

Здесь Viewer - кодовое слово; 2 - контекст справочной службы.

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

.topic FileOpen=3 

File Open

---------

Эта опция меню используется для загрузки файла

Здесь строки

File Open

---------

начинаются пробелом и поэтому не форматируются, т.е. сохраняют свой вид независимо от границ окна, в то время как при выводе строки

Эта опция меню используется для загрузки файла

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

Любой фрагмент строки справочного сообщения, обрамленный фигурными скобками, рассматривается как перекрестная ссылка. Перекрестная ссылка может содержать кодовое слово заголовка нужной справки или произвольный текст, за которым указывается двоеточие и кодовое слово. Например:

С помощью опции {FileOpen} можно загрузить файл.

или

Окно обеспечивает {просмотр файла: Viewer} в режиме скроллера.

В первом случае будет выведена строка

С помощью опции FileOpen можно загрузить файл.

причем слово FileOpen будет выделено цветом и может использоваться как перекрестная ссылка на справку, заголовок темы которой имеет вид

.topic FileOpen = ... 

Во втором случае в окне выводится строка

Окно обеспечивает просмотр файла в режиме скроллера.

Слова просмотр файла выделяются цветом и используются как перекрестная ссылка на справку с заголовком

.topic Viewer = ... 

В заголовке темы можно указывать несколько кодовых слов, например:

.topic FileOpen=3, OpenFile=103, FFileOpen 

Доступ к такой справке возможен для контекстов

const

chFileOpen = 3; 

chOpenFile = 103; 

chFFileOpen= 104;

Обратите внимание: за кодовым словом FFileOpen не указывается контекст, в этом случае считается, что связанный с ним контекст есть предыдущий контекст, увеличенный на 1, т.е.

chFFileOpen = 103 + 1 = 104

Файл DEMOHELP. TXT содержит пример исходного текстового файла, подготовленного с учетом описанных требований для преобразования программой TVHC.PAS в файл справочной службы.

  1. Подготовка справочного файла и его использование осуществляется в следующей последовательности.
  2. Подготавливается текстовый файл NAMETEXT, содержащий заголовки тем, справки и перекрестные ссылки.
  3. Вызывается программа TVHC.EXE (исходный текст этой программы содержится в файле \BP\EXAMPLES\DOS\TVDEMOS\TVHC.PAS) для создания файла справочной службы NAMEHELP и вспомогательного модуля NAMEPAS. Обращение к программе описано ниже.

Действия 3,6,..., 3,д осуществляются каждый раз, когда необходимо выдать ту или иную справку.

Для преобразования текстового файла во внутренний формат, используемый средствами модуля HelpFile, предназначена программа, исходный текст которой поставляется в файле TVHC.PAS. Перед использованием этой программы ее необходимо оттранслировать в ЕХЕ-файл. Формат вызова программы TVHC.EXE:

TVHC NAMETEXT [NAMEHELP [NAMEPAS]]

(в квадратных скобках указаны необязательные параметры). Здесь NAMETEXT - имя исходного текстового файла, NAMEHELP - имя выходного файла справочной службы, NAMEPAS - имя выходного файла, содержащего текст модуля с контекстами в виде констант chXXXX. Если имена выходных файлов опущены, будут созданы файлы с именем исходного файла и расширением HLP для файла справочной службы, PAS для текста модуля.

Текст файл NAMEPAS имеет следующий вид:

unit namepas;

interface

const

chTopicl = nl; 

chTopic2 = n2;

.....

chTopicN = nN; 

implementation 

end.

Поскольку этот файл создается программой TVHC.EXE автоматически, будьте внимательны при обращении к ней. Не рекомендуется опускать имена NAMEHELP и NAMEPAS: если имя исходного текстового файла совпадает с именем программы или

любого другого PAS-файла, старый файл будет стерт и на его месте будет создан файл с текстом модуля!

Для иллюстрации техники использования средств модуля HelpFile рассмотрим следующий пример. Пусть текст справочной службы помещен в файл HelpTest.txt и имеет следующий вид:

.topic NoContext=0

Добро пожаловать

в справочную службу системы Turbo Vision!

В текстовом файле для справочной службы Вы должны подготовить {заголовки тем: topic} и {перекрестные ссылки: CrossRef}. Весь текст от одного заголовка до другого представляет собой текст справки и выводится в окне справочной службы. При подготовке текста учитываются следующие соглашения:

если очередная строка начинается символом пробел, эта строка не будет форматироваться с учетом границ окна;

во всех остальных случаях выводимый в окне текст форматируется с учетом границ окна: слово, не умещающееся на строке, переносится на следующую строку экрана. Для преобразования текстового файла в файл справочной службы вызывается программа TVHC.EXE:

TVHC NAMETXT [NAMEHELP [NAMEPAS]]

Здесь NAMETXT - имя исходного текстового файла; NAMEHLP -имя выходного файла справочной службы; NAMEPAS - имя выходного файла, содержащего текст PAS-модуля с определением всех контекстов в виде констант chXXXX. Имя файла NAMEHELP можно не указывать - в этом случае выходной файл будет иметь имя входного файла и расширение HLP. Если не указан файл HELPPAS, будет создан файл с именем исходного и расширением PAS.

По умолчанию программа использует расширение ТХТ для входного файла, HLP для выходного файла справочной службы и PAS - для файла констант. .topic Topic=l Заголовок темы имеет следующий формат:

.topic Name[=N] [, Namel[=N2] [...]]

Здесь Name - имя темы (может состоять только-из латинских букв и цифр; разница в высоте букв игнорируется); N -контекст справочной службы, при котором выдается данная справка.

В квадратных скобках показаны необязательные параметры. Если опущен контекст N, программа присваивает соответствующей перекрестной ссылке контекст NPrev + 1, где NPrev - предыдущий определенный в программе контекст. .topic CrossRef=2

В произвольное место текста справки можно вставить так называемую перекрестную ссылку:

(text[:title])

Здесь () - фигурные скобки; text - произвольный текст или заголовок темы; title - заголовок темы; этот параметр вместе с двоеточием опускается, если text - заголовок темы.

Если Вы подготовите такой файл, то после вызова

tvhc helptest

будут созданы два файла: файл справочной службы helptest.hlp и файл модуля с определениями констант helptest.pas. Содержимое этого последнего файла будет таким:

unit helptest;

interface

const

hcCrossRef = 2;

hcNoContext= 0;

hctopic = 1; 

implementation 

end.

Следующая программа будет выдавать контекстно-зависимые справочные сообщения

из файла helptest.hlp при каждом нажатии на F1.

Uses App, Menus, Drivers, Views, Objects, HelpFile, Dialogs; 

const

cmChangeCtx =1000; 

type

PCtxView = ^TCtxView; 

TCtxView = object (TView)

Constructor Init; 

Procedure Draw; Virtual;

end; 

MyApp = object (TApplication) 

Ctx: PCtxView; 

Constructor Init;

Procedure InitStatusLine; Virtual; 

Procedure HandleEvent(var Event: TEvent); Virtual; 

end ;

PMyHelpWindow = AMyHelpWindow; 

MyHelpWindow = object (THelpWindow)

Function GetPalette: PPalette; Virtual; 

end;

Procedure MyApp.InitStatusLine; 

var

R: TRect;

begin

GetExtent(R); 

R.A.Y := pred(R.B.Y); 

StatusLine := New(PStatusLine,Init(R,

NewStatusDef(0, $FFFF,

NewStatusKey('~Alt-X~ Выход', kbAltX, cmQuit,

NewStatusKey('~F1~ Помощь',kbF1, cmHelp, 

NewStatusKey('~F2~ Изменить контекст',kbF2,

cmChangeCtx, 

NewStatusKey('~F5~ Распахнуть окно1, kbF5,

cmZoom, NIL)))}, 

NIL))) 

end;

Constructor MyApp.Init; 

begin

TApplication.Init; 

Ctx := NewtPCtxView, Init);

Insert(Ctx); 

RegisterHelpFile 

end;

Procedure MyApp.HandleEvent; 

var

HF: PHelpFile; 

HS: PDosStream; 

HW: PMyHelpWindow; 

const

HelpOpen: Boolean = False; 

Procedure DoHelp;

{Обеспечивает доступ к контекстно-зависимой справочной службе} 

var

С: Word;. 

begin

ClearEvent(Event);

{ Открываем DOS-поток: }

HS := New(PDosStream, Init('HELPTEST.HLP', stOpenRead));

{ Создаем и инициируем экземпляр объекта THelpFile: }

HF := New(PHelpFile, Init(HS));

HelpOpen := HSA.status = stOk;

if HelpOpen then

begin

{Создаем окно справочной службы и связываем его с потоком HS и текущим контекстом:}

HW := New(PMyHelpWindow, Init(HF, GetHelpCtx)); 

if ValidView(HW) <> NIL then 

begin

С := ExecView(HW); {Выдаем справку} 

Dispose(HW) {Ликвидируем окно} 

end;

HelpOpen := False 

end 

else

Dispose (HF, Done) 

end; 

begin

TApplication.HandleEvent (Event) ; 

case Event . Command of

cmHelp: if not HelpOpen then

DoHelp;  {Выдаем справку} 

cmChangeCtx: {Изменяем контекст по клавише F2} 

begin

if HelpCtx = 3 then

HelpCtx := 0 

else

inc (HelpCtx) ;

Ctx^.Draw;

ClearEvent (Event) 

end

end 

end;

Function MyHelpWindow.GetPalette; 

const

P = #16#17#18#19#20#47#21#13;

C: String [8] = P; 

begin

GetPalette := @C 

end ;

Constructor TCtxView. Init; 

var

R: TRect; 

begin

R. Assign (67 , 0, 80, 1) ;

TView.Init(R) ; 

end;

Procedure TCtxView. Draw; 

var

S: String;

B: TDrawBuffer;

C: Byte; 

begin

Str (Application^. HelpCtx, S) ;

S := 'Контекст = '+S;

С := GetColor(2) ;

MoveChar(B, ' ', C, Size.X) ;

MoveStr(B, S, C) ;

WriteLine(0, 0,Size.X,1,B) 

end; 

var

Р: МуАрр; 

begin

P.Init;

P.Run;

P.Done 

end.

В программе предусмотрена смена текущего контекста с помощью клавиши F2. Разумеется, в реальной программе смена контекста будет, судя по всему, происходить иначе: обычно в текст конструктора Init видимого элемента вставляется оператор

HelpCtx := NNN;

где NNN - нужный контекст.

Для визуализации текущего контекста в программе используется простой объект TCtxView, с помощью которого в верхнем правом углу экрана выводится строка

Контекст = N 

N - текущий контекст.