Главная arrow Язык программирования Pascal arrow Турбо Паскаль Начальный курс В.В.Фаронов arrow 15.13. Диалоговое окно выбора режима Турбо Паскаль В.В. Фаронов

15.13. Диалоговое окно выбора режима Турбо Паскаль В.В. Фаронов

Подведем некоторые итоги. Мы создали программу, которая погружает пользователя в среду объектно-ориентированного диалога 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).
Image
Рис.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.