|
Диалоговое окно выбора режима
Подведем некоторые итоги.
Мы создали программу, которая погружает пользователя
в среду объектно-ориентированного диалога Turbo Vision:
она поддерживает командные клавиши, работу с мышью,
может сменить каталог или диск, выбрать нужный файл
и загрузить его в окно просмотра. Не так плохо для 300
строк программного текста! Наша дальнейшая задача -
реализовать другие режимы работы (поиск нужной строки,
добавление и уничтожение строк, их изменение). Для двух
из них (уничтожение и редактирование строки) в программе
необходимо каким-то образом указать ту строку, с которой
будет работать пользователь. Мы уже реализовали эту
возможность, предусмотрев в окне просмотра текста управляемый
указатель. Поэтому режим просмотра можно принять в качестве
основного режима работы с данными. В связи с этим следует
несколько изменить метод TNotebook-HandleEvent, предусмотрев
в нем автоматический переход в режим просмотра данных
в случае успешного открытия файла с данными:
Procedure TNotebook.HandleEvent(var
Event: TEvent);
{Обработчик событий программы}
begin
Inherited HandleEvent(Event);
if Event.What = evCommand then
case Event.Command of
cmOpenFile:
begin
FileOpen;
if OpFileF then Work
end;
.......
end; {TNotebook.HandleEvent}
Как из режима просмотра данных перейти
к другим режимам? Возможно несколько решений. Я предлагаю
для этих целей воспользоваться командой cmClose (закрыть
окно просмотра): в момент, когда пользователь в режиме
просмотра данных нажмет клавишу Esc или воздействует
мышью на кнопку «Закрыть окно», на экране должно раскрыться
диалоговое окно выбора режима, предлагающее одно из
пяти возможных продолжений:
- закрыть окно просмотра;
- удалить текущую запись;
- искать нужную запись;
- редактировать текущую запись;
- добавить запись (записи).
Для реализации этой идеи в уже созданный
нами обработчик событий TInterior.HandleEvent следует
ввести обработку события cmClose:
const
{Команды для обработчиков событий:}
.......
cmCan=205;
cmDelete=206;
cmSearch = 207;
cmEdit = 208;
cmAdd = 209;
Function Control: Word; {Создает и использует
диалоговое окно выбора режима
работы)
begin
Control := cmCan
end; {Control}
{-----------------}
Procedure TInterior.HandleEvent (var
Event: TEvent) ;
{Обработчик событий для окна данных}
Procedure DeleteItem;
{Удаляет указанный в Location элемент
данных}
begin
end; {DeleteItem}
{-----------------}
Procedure AddItem(Edit: Boolean);
{Добавляет новый или редактирует старый
элемент данных}
begin
end; {AddItem}
{-----------------}
Procedure SearchItem;
{Ищет нужный элемент}
begin
end; {SearchItem}
{-----------------}
var
R: TPoint; label Cls;
begin {TInterior.HandleEvent}
Inherited HandleEvent (Event) ;
case Event. What of evCommand:
case Event . Command of
cmClose:
begin
Cls:
case Control of{Получить команду из
основного диалогового окна}
cmCan,
cmCancel:EndModal (cmCancel) ;
cmEdit:AddItem (True);
cmDelete:DeleteItem;
cmSearch:SearchItem;
cmAdd:AddItem (False);
end
end;
cmZoom: exit;
end;
evMouseDown: {Позиционировать мышью}
.....
evKeyDown: {Позиционировать клавишами
+ -}
case Event.KeyCode of
kbEsc: goto Cls;
kbGrayMinus: if Location > Delta.Y
then
.....
end; {TInterior.HandleEvent}
В этом фрагменте мы расширили набор
нестандартных команд (константы стпСап, ..., cmAdd),
ввели новую функцию Control и предусмотрели необходимые
процедуры в теле обработчика событий. Заметим, что режимы
редактирования записи и добавления новой записи очень
схожи по организации диалога с пользователем, поэтому
он» реализуются в рамках одной процедуры AddItem и управляются
параметром обращения к ней.
Функция Control используется для создания
диалогового окна выбора продолжения. В качестве значения
этой функции будет возвращаться одна из пяти новых команд.
В начальном варианте функция возвращает команду стСап,
что интерпретируется обработчиком событий как указание
на завершение работы с диалоговым окном. Поэтому, если
Вы вставите указанный текст в программу и запустите
ее, поведение программы останется прежним.
Займемся реализацией функции Control.
Она должна создать диалоговое окно выбора режима, получить
с его помощью команду, идентифицирующую выбранный режим,
и вернуть эту команду в качестве своего значения:
Function Control: Word;
{Получает команду из основного диалогового
окна}
const
X = 1;
L = 12;
DX= 13;
But: array [0. .4]of String [13] = {Надписи
на кнопках:}
('~1~ Выход ','~2~Убрать ','~3~ Искать
',
'~4~ Изменить ','~5~ Добавить ') ;
Txt: array [0..3]of String [52] = (
{Справочный текст:}
'Убрать - удалить запись, выделенную
цветом', 'Искать - искать запись, начинающуюся нужными
буквами', 'Изменить - изменить поле (поля) выделенной
записи', 'Добавить - добавить новую запись'); var
R: TRect;
D: PDialog;
k: Integer;
begin
R.Assign(7,6,74,15) ;
D := New{PDialog,Init(R, 'Выберите продолжение:'));
with D do
begin
for k := 0 to 3 do {Вставляем поясняющий
текст}
begin
R.Assign(l,l+k,65,2+k);
Insert(New(PStaticText,Init(R,#3+Txt[k])))
end;
for k := 0 to 4 do {Вставляем кнопки:}
begin
R.Assign(X+k*DX,6,X+k*DX+L,8);
Insert(New(PButton, Init(R,But[k],cmCan+k,bfNormal)))
end;
SelectNext(False); {Активизируем первую
кнопку}
end;
Control := DeskTopA.ExecView(D); {Выполняем
диалог}
end; {Control}
Сначала создается диалоговое окно с
заданными размерами (чтобы программе стал доступен тип
TDialog, укажите в предложении Uses модуль Dialogs).
Затем в цикле
for k := 0 to 3 do
в окно вставляется поясняющий текст
(см. рис.15.10).

Рис.15.10. Диалоговое
окно функции Control
Этот текст не связан с диалогом и называется
статическим. Для вставки статической строки в любой
видимый элемент используется конструктор TStaticTextJnit,
которому в качестве параметров передаются координаты
строки и сама строка. Как Вы уже могли заметить, идентификаторы
объектов в Turbo Vision начинаются на букву Т, а идентификаторы
типов-указателей на экземпляры этих объектов начинаются
на букву Р. Таким образом, PStaticText - это тип-указатель
на экземпляр объекта TStaticText, поэтому оператор
Insert(New (PStaticText, Init(R,'Текст'))
помещает строку «Текст» на место, заданное
координатами переменной R. Отметим, что если строка
начинается на символ #3, то при выводе на экран она
будет размещаться в центре прямоугольника R. Мы используем
это соглашение и дополняем каждую выводимую строку этим
символом. В цикле
for k := 0 to 4 do {Вставить кнопки:}
в окно вставляются пять кнопок. При
их инициации используется то обстоятельство, что определенные
нами команды cmCan, ..., cmAdd образуют непрерывное
множество [205..209].
Особо следует остановится на операторе
SelectNext(False); {Активизируем 1-ю
кнопку}
Дело в том, что по умолчанию активизируется
тот элемент диалогового окна, который задан (вставлен
в окно) последним. Чтобы изменить активность по умолчанию,
используется вызов процедуры SelectNext, которая смещает
активность к следующему элементу. Так как элементы образуют
замкнутую цепь (от последнего элемента активность переходит
к первому), параметр обращения к этой процедуре указывает
направления смещения: если он имеет значение False,
активным станет следующий в цепи элемент, если True
- предыдущий.
Прежде, чем Вы попробуете запустить
эту программу на счет, внесем в нее несколько изменений.
Во-первых, пора убрать имитацию данных, показываемых
в окне просмотра. Для этого в процедуре TInterior.ReadFile
необходимо удалить строки
s := copy(ParamStr(O),1,pos('.',ParamStr(0)))+'pas';
assign(f,s);
.....
exit;
Надеюсь, что Вы заблаговременно подготовили
остальной текст этого метода, если это не так, вставьте
операторы
seek (DataFile, 0);
while not (EOF (DataFile) or LowMemory)
do
begin
.....
end;
Location := 0
Во-вторых, обратили ли Вы внимание на
то, что в процедуре TNotebook. Work указатель
PW инициируется оператором
PW := New(PWorkWin, Init(R));
а динамическая память, выделенная для
размещения экземпляра объекта TWorkWin, не возвращается
обратно в кучу? Если да, то у Вас есть хорошие шансы
избежать многих неприятностей при программировании в
среде Turbo Vision. Конечно же, нам следовало где-то
в программе позаботиться об удалении ненужного нам экземпляра
объекта. Чтобы не усложнять программу, я не стал этого
делать: если вставить оператор
Dispose(PW, Done)
сразу за оператором
DeskTop.Insert(PW)
то вновь созданное окно будет тут же
удалено с экрана, поэтому оператор Dispose нужно разместить
в обработчике событий TNotebook. HandleEvent (подумайте,
где именно).
После включения диалогового окна в цепочку
действий, связанных с инициацией PW, появилась возможность
приостановить исполнение программы в процедуре Work:
вместо оператора
DeskTop.Insert(PW)
вставьте следующие строки:
Control := DeskTop.ExecView(PW);
Dispose(PW, Done)
и добавьте описание переменной Control:
var
.....
Control: Word;
В отличие от процедуры Insert процедура
ExecView не только помещает видимый элемент на экран,
но и приостанавливает дальнейшее исполнение программы
Work до тех пор, пока не закончится диалог с пользователем.
И, наконец, еще одно усовершенствование.
Работа с программой станет удобнее, если сразу после
чтения файла с данными она перейдет к их показу. Реализовать
это очень просто: добавьте вызов процедуры Work в процедуру
FileOpen следующим образом:
Procedure TNotebook.FileOpen;
..... begin
.....
if OpFileF then
begin
.....
Work{Переходим к работе}
end;
.....
end; {FileOpen}
Если Вы внесете в программу все описанные
изменения и запустите ее на счет , то при попытке выйти
из режима просмотра на экране будет развернуто диалоговое
окно, показанное на рис. 15.10. «Нажатие» на любую кнопку
этого окна не приводит ни к каким последствиям - наше
окно пока откликается только на стандартную команду
cmClose, связанную с клавишей Esc.
Файл с данными DataType пока еще не
существует. Чтобы программа смогла нормально
работать, в диалоговом окне открытия
файла укажите произвольное имя, например MYDATA.
После завершения работы программы будет создан пустой
файл MYDATA.DAT.
|