Контекстная помощь
В 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 в файл справочной службы.
- В программе, использующей средства модуля HelpFile:
- вызывается процедура RegisterHelpFile для регистрации объектов модуля HelpFile в потоке;
- открывается поток, связанный с созданным файлом NAMEHELP; в) создается экземпляр объекта THelpFile и ему передается поток и нужный контекст;
- инициируется работа созданного экземпляра;
- ликвидируется экземпляр объекта THelpFile.
Действия 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 - текущий контекст.