или воздействует мышью на кнопку Закрыть окно, на экране должно раскрыться диалоговое окно выбора режима, предлагающее одно из пяти возможных продолжений. Для этого, в уже созданный обработчик данных событий TInterior.HandleEvent вводим обработку событий cmClose.
Функция Control используется для создания диалогового окна выбора продолжения. В качестве значения этой функции будет возвращаться одна из пяти новых команд. Control должна создать диалоговое окно выбора режима, получить с его помощью команду, идентифицирующую выбранный режим, и вернуть эту команду в качестве своего значения.
.Обработка команд пользователя
Обработчик событий диалогового окна поддерживает только стандартные команды cmClose, cmOk, cmCancel. Но мы используем другой метод. Для этого вводим новый объект TDlgWin как потомок объекта TDialog и перекрываем ему метод HandleEvent. В новом методе сначала вызываем стандартный обработчик, а затем анализируем событие, если оно не очищено и содержит команду, значит была нажата какая-то командная кнопка, и нам следует заставить обработчик закрыть окно и вернуть эту команду как результат диалога с пользователем.
Метод EndModal предназначен для того, чтобы завершить работу с диалоговым окном и вернуть команду в программу, использующую это окно.
.Режим поиска записи
С помощью этого окна пользователь может задать несколько начальных букв, являющихся ключом для поиска записи. Получив данные из этого окна, процедура SearchItem организует поиск первой от начала коллекции строки, для которой не выполняется условие: Pattern >= Item.
В реализации процедуры SearchItem указанная проверка осуществляется для строк, предварительно преобразованных к прописным буквам с помощью внутренней процедуры UpString, то есть поиск игнорирует возможную разницу в высоте букв шаблона и строк коллекции.
Итоги
Итак, наша программа обеспечивает довольно высокий уровень диалога с пользователем: в ней есть командные клавиши, «всплывающие» меню, удобные диалоговые окна, поддержка мыши. Данная программа обладает простым интуитивно понятным интерфейсом, а ее функциональные возможности позволяют производить весь набор операций необходимый для ее нормальной работы.
Список литературы
1.Епанешников А. М. Епанешникова В. А. Программирование в среде Turbo Vision, М.: Диалог-Мифи, 2002г.
2.В. М. Бондарев, В. И. Рублинецкий, Е. Г. Качко. Основы программирования. - Харьков, Фолио; Ростов на Дону, Феникс, 1998, 368 с.
.Никлаус Вирт «Алгоритмы и структуры данных» издательство "Невский Диалект" · 2001 г. · 352 стр.
Приложение. Программный код
Notebook;
{Программа работает с файлами данных Записной книжки}
Uses App, Objects, Menus, Drivers, Views, StdDlg, DOS, Memory, Dialogs;
type
{Объект TWorkWin создает окно рамки с полосами прокрутки для управления
встроенным в него объектом TInterior}
PWorkWin =^TWorkWin;=object (TWindow)Init(Bounds: TRect);;
{Объект TDlgWin создает диалоговое окно для выбора режима работы}
PDlgWin =^TDlgWin;= object (TDialog)HandleEvent (var Event: TEvent); Virtual;
end;
{Следующий объект обслуживает внутреннюю часть рамочного окна TWorkWin.
Он создает скроллируемое окно с записями из архивного файла и с помощью
диалогового окна TDlgWin управляет работой с этими записями}
PInterior =^TInterior;= object (TScroller): PStringCollection;: Word;Init(var Bounds: TRect; HS,VS: PScrollBar);Draw; Virtual;ReadFile;Done; Virtual;HandleEvent(var Event: TEvent); Virtual;
end;
{Объект-программа TNotebook поддерживает работу с меню и строкой статуса}
TNotebook = object (TApplication)InitStatusLine; Virtual;InitMenuBar; Virtual;HandleEvent(var Event: TEvent); Virtual;FileSave;ChangeDir;DOSCall;FileOpen;Work;;
const
{Множество временно недоступных команд}
WinCom1: TCommandSet = [cmSave, cmWork];: TCommandSet = [cmOpen];= 25; {Длина поля Name}= 11; {Длина поля Phone}= 40; {Длина поля Addr}= LName+LPhone+LAddr; {Длина строки}= record {Тип данных в файле}: String [LName]; {Имя}: String [LPhone];{Телефон}: String [LAddr]; {Адрес};: file of DataType; {Файловая переменная}: Boolean; {Флаг открытого файла}
{-------------Реализация объекта TWorkWin-------------}TWorkWin.Init(Bounds: TRect);
{Создание окна данных},VS: PScrollBar; {Полосы-указатели}
Interior: PInterior; {Указатель на управляемое текстовое окно}.Init(Bounds,'',0); {Создание нового окна с рамкой}(Bounds); {Получаем координаты минимальной
перерисовываемой части окна}.Grow(-1,-1); {Устанавливаем размеры окна с текстом}
{Дальше включаем стандартные по размеру и положению полосы-указатели}
VS := StandardScrollBar(sbVertical+sbHandleKeyBoard);:= StandardScrollBar(sbHorizontal+sbHandleKeyBoard);
{Далее создаем текстовое окно}:= New(PInterior,Init(Bounds, HS, VS));
Insert(Interior) {Включаем его в основное окно}
end;
{-------------}TDlgWin.HandleEvent;HandleEvent(Event);Event.What=evCommand then(Event.Command);
{-------------}TNotebook.FileOpen;
{Открывает файл данных}: PFileDialog; {Диалоговое окно выбора файла}: Word;: PathStr;
{Далее создаем экземпляр динамического объекта}(PF, Init('*dat','Выберите нужный файл:','Имя файла',fdOpenButton,0));
{С помощью следующего оператора окно выводится на экран и результат
работы пользователя с ним помещается в переменную Control}:= DeskTop^.ExecView(PF);
{Далее анализируем результат запроса}Control of.cmFileOpen,cmOk:{Пользователь указал имя файла}^.GetFileName(s); {s содержит имя файла}
Assign(DataFile,s);(DataFile);IOResult <> 0 then(DataFile);:= IOResult=0;OpFileF then(WinCom2);(WinCom1);{Переходим к работе};;; {case Control}(PF, Done) {Уничтожаем экземпляр}; {FileOpen}
{-------------}TNotebook.FileSave;
{Закрывает файл данных}(DataFile);:= False;(WinCom2); {Разрешаем открыть файл}
DisableCommands(WinCom1) {Запрещаем работу и сохраняем}
end; {TNotebook.FileSave}
{-------------}TNotebook.ChangeDir;
{Изменяет текущий каталог}: PChDirDialog; {Диалоговое окно смены каталога}
Control: Word;(PD, Init(cdNormal,0)); {Создаем диалоговое окно}:= DeskTop^.ExecView(PD); {Используем окно}
ChDir(PD^.DirInput^.Data^); {Устанавливаем новый каталог}
Dispose(PD, Done) {Удаляем окно}; {TNotebook.ChangeDir
{-------------}TNotebook.DOSCall;
{Временный выход в Винду}= 'Для возврата введите EXIT в ответ'+' на приглашение Windows..';; {Закрыть обработчик событий}; {Закрыть монитор экрана}; {Закрыть монитор памяти}(HeapPtr); {Освободить кучу}(txt); {Сообщить о выходе}; {Установить стандартные векторы}
{Передать управление командному процессору Винды (далее)}(GetEnv('COMPEC'),'');
{Вернуться из Винды (далее)}; {Восстановить векторы}(HeapEnd); {Восстановить кучу}; {Открыть монитор памяти}; {Открыть монитор экрана}; {Открыть обработчик событий}; {Открыть обработчик ошибок}{Восстановить вид экрана}; {DOSCall}
{-------------}TInterior.Init;
{Создает окно скроллера}
begin.Init(Bounds, HS, VS);;:= gfGrowHiX+gfGrowHiY;(LLine, PS^.Count);
{-------------}TInterior.Done;(PS,Done);Done;
{-------------}TInterior.ReadFile;
{Читает содержимое файла данных в массив LINES}
var: Integer;: String;: DataType;: text;:= New(PStringCollection, Init(100,10));(DataFile,0);not (EOF(DataFile) or LowMemory) do(DataFile, data);data do:= Name;Length(s) < LName do:= s+' ';:= s+Phone;Length(s) < LName+LPhone do:= s+' ';:= s+Addr;s<>'' then PS^.Insert(NewStr(s));:= 0;; {ReadFile}
{-------------}TInterior.Draw;
{Выводит данные в окно просмотра}, {Текущая строка экрана} k {Текущая строка массива} : Integer;
B: TDrawBuffer;: Byte;: PString;Delta.Y>Location then:= Delta.Y;Location>Delta.Y+pred(Size.Y) then:= Delta.Y+pred(Size.Y);n := 0 to pred(Size.Y) do
{Size.Y - количество строк окна}
begin:= Delta.Y+n;k=Location then:= GetColor(2):= GetColor(1);(B,' ',Color,Size.X);k < pred(PS^.Count) then:= PS^.At(k);(B, Copy(p^,Delta.X+1,Size.X),Color);;(0,N,Size.X,1,B);;; {TInterior.Draw}
{-------------}Control: Word;
{Получает команду из основного диалогового окна}
const= 1;= 12;= 13;: array [0..4] of String [13] = {Надписи на кнопках}
('`1` Выход ','`2`Убрать ','`3` Искать ','`4` Изменить ','`5` Добавить ');
Txt: array [0..3] of String [52] = ({Справочный текст}
'Убрать - удалить запись, выделенную цветом',
'Искать - искать запись, начинающуюся нужными буквами',
'Изменить - изменить поле (поля) выделенной записи',
'Добавить - добавить новую запись=)');
var: TRect;: PDlgWin;: Integer;.Assign(7,6,74,15);
D := New(PDlgWin,Init(R, 'Выберите продолжение:'));
with D^ dok := 0 to 3 do {Вставляем поясняющий текст}.Assign(1,1+k,65,2+k);(New(PStaticText,Init(R,#3+Txt[k])));;k := 0 to 4 do {Вставляем кнопки}.Assign(X+k*DX,6,X+k*DX+L,8);(New(PButton,Init(R,But[k],cmCan+k,bfNormal)));(False); {Активизируем первую кнопку};:= DeskTop^.ExecView(D); {Выполняем диалог}; {Control}
{-------------}TInterior.HandleEvent;DeleteItem;
{Удаляет указанный в Location элемент данных}: Integer;: PString;: String;: DataType;:= PS^.At(Location); {Получаем текущую запись}:= copy(PStr^,1,LName);(DataFile,0);
D := -1; {D - номер записи в файле}{Цикл поиска по совпадению поля Name}
inc(D);(DataFile,Data);Data do while Length(Name) < LName do:= Name+' 'Data.Name=s;(DataFile,pred(FileSize(DataFile)));(DataFile,Data); {Читаем последнюю запись}(DataFile,D);
write(DataFile,Data); {Помещаем ее на место удаляемой}
seek(DataFile,pred(FileSize(DataFile)));(DataFile); {Удаляем последнюю запись}PS^ do D := IndexOf(At(Location));
PS^.AtFree(D); {Удаляем строку из коллекции}{Обновляем окно}; {DeleteItem}
{-------------}AddItem(Edit: Boolean);
{Добавляет новый или редактирует старый элемент данных}
const= 1;= 2;= LName+LPhone+LAddr;: DataType;: TRect;: PDialog;, BPhone, BAddr: PInputLine;: Word;: Word;: String;: PString;(DataFile,FileSize(DataFile)); {Добавляем записи в конец файла}{Цикл ввода записей}Edit then {Готовим заголовок}:= 'Редактирование:'(FileSize(DataFile)+1,s);Length(s) < 3 do:= '0'+s;
s := 'Вводится запись N '+s;
end;(Data,SizeOf(Data),' '); {Заполняем поля пробелами}.Assign(15,5,65,16);:= New(PDialog, Init(R, s)); {Создаем окно}InWin^ do{Формируем окно}.Assign(2,y+1,2+LName,y+2);:= New(PInputLine, Init(R,LName));(BName); {Поле имени}.Assign(2,y,2+Lname,y+1);(New(PLabel,Init(R, 'Имя',BName)));.Assign(2,y+dy+1,2+LPhone,y+dy+2);:= New(PInputLine, Init(R,LPhone));(BPhone); {Поле телефона}.Assign(2,y+dy,2+LPhone,y+dy+1);(New(PLabel, Init(R, 'Телефон',BPhone)));.Assign(2,y+2*dy+1,2+LAddr,y+2*dy+2);:= New(PInputLine, Init(R,LAddr));(BAddr); {Поле адреса}.Assign(2,y+2*dy,2+LAddr,y+2*dy+1);(New(PLabel, Init(R, 'Адрес',BAddr)));
{Вставляем две командные кнопки(далее)}
R.Assign(2,y+3*dy+1,12,y+3*dy+3);(New(PButton, Init(R, 'Ввести',cmOk,bfDefault)));.Assign(2+20,y+3*dy+1,12+20,y+3*dy+3);(New(PButton, Init(R, 'Выход',cmCancel,bfNormal)));(False) {Активизируем первую кнопку}; {Конец формирования окна}Edit then with Data do
s := p^;:= copy(s,1,LName);:= copy(s,succ(LName),LPhone);:= copy(s,succ(LName+LPhone),LAddr);
InWin^.SetData(Data) {Вставляем текст в поля ввода}
end;:= DeskTop^.ExecView(InWin); {Выполняем диалог}Control=cmOk then with Data doEdit then; {Удаляем старую запись}:= BName^.Data^;:= BPhone^.Data^;:= BAddr^.Data^;[0] := chr(L);(s[1],L,' ');(Name[1],s[1],Length(Name));(Phone[1],s[succ(LName)],Length(Phone));(Addr[1],s[succ(LName+LPhone)],Length(Addr));
OldCount := PS^.Count; {Прежнее количество записей}^.Insert(NewStr(s)); {Добавляем в коллекцию}
{Проверяем добавление}
if OldCount <> PS^.Count then(DataFile,Data) {Да - добавляем в файл};Edit or (Control=cmCancel);; {AddItem}
{-------------}SearchItem;
{Ищет нужный элемент}UpString(s: String): String;
{Преобразует строку в верхний регистр}
var: Integer;k := 1 to Length(s) dos[k] in ['a'..'z'] then[k] := chr(ord('A')+ord(s[k])-ord('a'))if s[k] in ['а'..'п'] then[k] := chr(ord('А')+ord(s[k])-ord('а'))if s[k] in ['р'..'я'] then[k] := chr(ord('Р')+ord(s[k])-ord('р'));:= s; {UpString}: PDialog;: TRect;: String;: PInputLine;: Word;{SearchItem}.Assign(15,8,65,16);:= New(PDialog, Init(R,'Поиск записи:'));InWin^ do.Assign(2,2,47,3);:= New(PInputLine, Init(R,50));(p);.Assign(1,1,40,2);(New(PLabel, Init(R, 'Введите образец для поиска:',p)));.Assign(10,5,20,7);(New(PButton, Init(R,'Ввести',cmOk,bfDefault)));.Assign(25,5,35,7);(New(PButton, Init(R,'Выход',cmCancel,bfNormal)));(False);;DeskTop^.ExecView(InWin) = cmCancel then;:= p^.Data^;:= 0;(UpString(s) >= UpString(PString(PS^.At(Location))^))(Location < pred(PS^.Count)) do(Location);(Location < Delta.Y) or (Location >Delta.Y+pred(Size.Y)) then(Delta.X,Location); {SearchItem}
{-------------}: TPoint;Cls;.HandleEvent(Event);Event.What of:Event.Command of:
begin:Control of {Получить команду из основного диалогового окна}
cmCan, cmCancel: EndModal(cmCancel);: AddItem(True);: DeleteItem;: SearchItem;: AddItem(False);;;: exit;;: {Реакция на щелчок мышью}(MouseWhere, R); {Получаем в R координаты указателя мыши}:= Delta.Y+R.Y;;: {Реакция на клавиши + -}Event.KeyCode of: goto Cls;: if Location > Delta.Y then(Location);;: if Location < Delta.Y+pred(Size.Y) then(Location);;;;; {TInterior.HandleEvent}
{-------------}TNotebook.Work;
{Работа с данными}: TRect;: PWorkWin;: Word;.Assign(0,0,80,23);:= New(PWorkWin, Init(R));:= DeskTop^.ExecView(PW);(PW,Done);
{-------------}TNotebook.HandleEvent(var Event: TEvent);
{Обработчик событий программы}{TNotebook.HandleEvent}.HandleEvent(Event); {Обработка стандартных команд cmQuit и cmMenu}Event.What = evCommand thenEvent.Command of
{Обработка новых команд}
cmOpen: FileOpen; {Открыть файл}
cmSave: FileSave; {Закрыть/Сохранить файл}
cmChangeDir: ChangeDir; {Сменить диск}
cmDOSShell: DOSCall; {Временный выход в Винду}
cmWork: Work; {Обработать данные}{Не обрабатывать другие команды};(Event) {Очистить событие после обработки}
end; {TNotebook.HandleEvent}
{-------------}TNotebook.InitMenuBar;
{Создание меню}: TRect;(R);.B.Y := succ(R.A.Y); {R - координаты строки в меню}
MenuBar := New(PMenuBar, Init(R,
NewMenu( {Создаем меню}
{Первый элемент нового меню представляет собой подменю}
NewSubMenu('~F~/Файл', hcNoContext,
{Описываем элемент главного меню}( {Создаем подменю}( {Первый элемент}
'~1~/ Открыть','F3',kbF3,cmOpen,hcNoContext,( {Второй элемент}
'~2~/ Закрыть','F2',kbF2,cmSave,hcNoContext,( {Третий элемент}
'~3~/ Сменить диск','',0,cmChangeDir,hcNoContext,( {Строка-разделитель}('~4~/ Заглянуть в Винду','',0,cmDOSShell,hcNoContext,('~5~/ Конец работы','Alt-X',kbAltX,cmQuit,hcNoContext,)))))) {Нет других элементов подменю}
),
{Создаем второй элемент главного меню}('~W~/ Работа','',kbF4,cmWork,hcNoContext,) {Нет других элементов главного меню}
)))); {TNotebook.InitMenuBar}
{-------------}TNotebook.InitStatusLine;
{Формирует строку статуса}: TRect; {Границы строки статуса}(R); {Получаем в R координаты всего экрана}
R.A.Y := pred(R.B.Y);:= New(PStatusLine,(R, {Создаем строку статуса}
NewStatusDef(0, $FFFF, {Устанавливаем максимальный диапазон
текстной справочной службы}('~Alt-X~ Выход', kbAltX, cmQuit,
NewStatusKey('~F2~ Закрыть', kbF2, cmSaveFile,('~F3~ Открыть', kbF3, cmOpenFile,('~F4~ Работа', kbF4, cmWork,('~F10~ Меню', kbF10, cmMenu,))))), {Нет других клавиш}) {Нет других определений}
));(WinCom1) {Запрещаем недоступные команды}
end; {TNotebook.InitStatusLine}
{-------------}: TNotebook;.Init;.Run;
Nbook.Done;.