TURBO PASCAL |
Новости
|
Программа Notebook
Описание программы см. п.. 15. Program Notebook; {Программа обслуживает файлы данных "записной книжки". Описание программы см. в гл.15} Uses App, Objects, Menus, Drivers, Views, StdDlg, DOS, Memory, Dialogs; type {Объект TWorkWin создает рамочное окно с полосами скроллинга для управления встроенным в него объектом TInterior} PWorkWin =TWorkWin; TWorkWin = object (TWindow) Constructor Init(Bounds: TRect); end; {Объект TDlgWin создает диалоговое окно для выбора режима работы} PDlgWin =TDlgWin; TDlgWin = object (TDialog) Procedure HandleEvent(var Event: TEvent); Virtual; end; {Следующий объект обслуживает внутреннюю часть рамочного окна TWorkWin. Он создает скроллируемое окно с записями из архивного файла и с помощью диалогового окна TDlgKin управляет работой с этими записями} PInterior =TInterior; TInterior = object (TScroller) PS: PStringCollection; Location: Word; Constructor Init(var Bounds: TRect; HS,VS: PScrollBar); Procedure Draw; Virtual; Procedure ReadFile; Destructor Done; Virtual; Procedure HandleEvent(var Event: TEvent); Virtual; end; {Объект-программа TNotebook поддерживает работу с меню и строкой статуса} TNotebook = object (TApplication) Procedure InitStatusLine; Virtual; Procedure InitMenuBar; Virtual; Procedure HandleEvent(var Event: TEvent); Virtual; Procedure FileSave; Procedure ChangeDir; Procedure DOSCall; Procedure FileOpen; Procedure Work; end; const {Команды для обработчиков событий:} cmChDir = 202; {Сменить каталог} cmWork = 203; {Обработать данные} cmDOS= 204; {Временно выйти в ДОС} cmCan= 205; {Команда завершения работы} cmDelete= 206; {Уничтожить текущую запись} cmSearch = 207;{Искать нужную запись} cmEdit = 209;{Редактировать запись} cmAdd = 208;{Добавить запись} {Множество временно недоступных команд:} WinCom1: TCommandSet = [cmSave,cmWork]; WinCom2: TCommandSet = [cmOpen];
LName = 25; {Длина поля Name} LPhone= 11; {Длина поля Phone} LAddr =40; {Длина поля Addr} LLine = LName+LPhone+LAddr; {Длина строки} type DataType = record {Тип данных в файле} Name : String [LName]; {Имя} Phone: String [LPhone]; {Телефон} Addr : String [LAddr] {Адрес} end; var DataFile: file of DataType; {Файловая переменная} OpFileF : Boolean; {Флаг открытого файла} {-----------------------} Реализация объекта TWorkWin {-----------------------} Constructor TWorkWin.Init(Bounds: TRect); {Создание окна данных} var HS,VS: PScrollBar; {Полосы-указатели} Interior: PInterior; {Указатель на управляемое текстовое окно} begin TWindow.Init(Bounds,0);{Создаем новое окно с рамкой} GetClipRect(Bounds); {Получаем в BOUNDS координаты минимальной перерисовываемой части окна} Bounds.Grow(-1,-1);{Устанавливаем размеры окна с текстом} {Включаем стандартные по размеру и положению полосы-указатели:} VS := StandardscrollBar (sbVertical+sbHandleKeyBoard) ; HS := StandardscrollBar (SbHorizontal+sbHandleKeyBoard) ; {Создаем текстовое окно:} Interior := New (PInterior, Init (Bounds, HS, VS) ) ; Insert (Interior) {Включаем его в основное окно} end; {TWorkWin.Init} {----------------------} Procedure TDlgWin.HandleEvent; begin Inherited HandleEvent (Event) ; if Event. What=evCommand then EndModal (Event. Command) end; {-----------------} Procedure TNotebook.FileOpen; {Открывает файл данных} var PF: PFileDialog; {Диалоговое окно выбора файла} Control: Word; s: PathStr; begin {Создаем экземпляр динамического объекта:} New(PF, Init('*.dat','Выберите нужный файл:', 'Имя файла',fdOpenButton,0)) {С помощью следующего оператора окно выводится на экран и результат работыпользователя с ним помещается в переменную Control:} Control := DeskTop.ExecView(PF); {Анализируем результат запроса:} case Control of StdDlg.cmFileOpen,cmOk: begin {Пользователь указал имя файла:} PF.GetFileName(s); {s содержит имя файла} Assign(DataFile,s); {$I-} Reset(DataFile) ; if IOResult <> 0 then Rewrite(DataFile); OpFileF := IOResult=0; {$I+} if OpFileF then begin DisableCommands(WinCom2); EnableCommands(WinCom1); Work {Переходим к работе} end end; end; {case Control} Dispose(PF, Done) {Уничтожаем экземпляр} end; {FileOpen} {-----------------} Procedure TNotebook.FileSave; {Закрывает файл данных} begin Close(DataFile); OpFileF := False; EnableCommands(WinCom2); {Разрешаем открыть файл) DisableCommands(WinCom1) {Запрещаем работу и сохранение} end; {TNotebook.FileSave} {------------------} Procedure TNotebook.ChangeDir; {Изменяет текущий каталог} var PD: PChDirDialog; {Диалоговое окно смены каталога/диска} Control: Word; begin New(PD, Init(cdNormal,0)); {Создаем диалоговое окно} Control := DeskTop.ExecView(PD); {Используем окно} Choir(PD.DirInput.Data); {Устанавливаем новый каталог} Dispose(PD, Done) {Удаляем окно из кучи} end; {TNotebook.ChangeDir} {---------------------} Procedure TNotebook.DOSCall; {Временный выход в ДОС} const txt ='Для возврата введите EXIT в ответ'+ ' на приглашение ДОС...'; begin DoneEvents; {Закрыть обработчик событий} DoneVideo; {Закрыть монитор экрана} DoneMemory; {Закрыть монитор памяти} SetMemTop(HeapPtr); {Освободить кучу} WriteLn(txt); {Сообщить о выходе} SwapVectors; {Установить стандартные векторы} {Передать управление командному процессору ДОС:} Exec(GetEnv('COMSPEC'),''); {Вернуться из ДОС:} SwapVectors; {Восстановить векторы} SetMemTop(HeapEnd); {Восстановить кучу} InitMemory;{Открыть монитор памяти} InitVideo; {Открыть монитор экрана} InitEvents; {Открыть обработчик событий} InitSysError; {Открыть обработчик ошибок} Redraw {Восстановить вид экрана} end; {DOSCall} {---------------} Constructor TInterior.Init; {Создает окно скрроллера} begin TScroller.Init(Bounds, Hs, VS); ReadFile; GrowMode := gfGrowHiX+gfGrowHiY; SetLimit(LLine, РS.Count) end; {--------------} Destructor TInterior. Done; begin Dispose (PS, Done) ; Inherited Done end ; {--------------} Procedure TInterior. ReadFile; {Читает содержимое файла данных в массив LINES} var k: Integer; s: String; Data: DataType; f: text; begin PS := New(PStringGollection, Init (100, 10) ); seek(DataFile,0) ; while not (EOF(DataFile) or LowMemory) do begin ReadfDataFile, data) ; with data do begin s : = Name ; while Length (s) < LName do s : = s+ ' ' ; s := s+Phone; while Length (s) < LName+LPhone do s : = s+ ' ' ; s := s+Addr end; if so'' then PS. insert (NewStr (S) ) end; Location := 0; end; {ReadFile} {-----------} Procedure TInterior.Draw; { Выводит данные в окно просмотра} var n, {Текущая строка экрана} k: Integer; {Текущая строка массива} В: TDrawBuffer; Color: Byte; p: PString; begin if Delta.Y>Location then Location := Delta.Y; if Location>Delta.Y+pred(Size.Y) then Location := Delta. Y+pred (Size. Y) ; for n := 0 to pred(Size.Y) do {Size. Y - количество строк окна} begin k := Delta. Y+n; if k=Location then Color := GetColor(2) else Color := GetColor(1); MoveCharfB,' ', Color, Size. X) ; if k < pred(PS. count) then begin p := PS.At(k) ; MoveStr(B, Copy (р, Delta. X+1, Size. X) , Color) ; end; WriteLine(0,N,Size.X,1,B) end end; {Tlnterior.Draw} {---------------} Function Control: Word; {Получает команду из основного диалогового окна} const X = 1; L = 12; DX= 13; But: array [0..4] of String [13] = {Надписи на кнопках:} ('~l~ Выход ' , ' ~2~ Убрать ','~3~ Искать ','~4~ Изменить ','~5~ Добавить'); Txt: array [0..3] of String [52] = ( {Справочный текст:} 'Убрать - удалить запись, выделенную цветом ', 'Искать - искать запись, начинающуюся нужными буквами', 'Изменить - изменить поле (поля) выделенной записи', 'Добавить - добавить новую запись'); var R: TRect; D: PDlgWin; k: Integer; begin R.Assign(7,6,74,15) ; D := New (PDlgWin, Init (R, 'Выберите продолжение:')); with D do begin for k := 0 to 3 do{Вставляем поясняющий текст} begin R.Assign(1,1+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,bf Normal) ) ) end; SelectNext (False) ; {Активизируем первую кнопку} end; Control := DeskTop.ExecView(D) ; {Выполняем диалог} end; {Control} {-----------------} Procedure TInterior.HandleEvent; Procedure DeleteItem; {Удаляет указанный в Location элемент данных} var D: Integer; PStr: PString; s: String; Data: DataType; begin PStr := PS.At(Location); {Получаем текущую запись} s := copy(PStr,1,LName); seek(DataFile,0); D := -1; {D - номер записи в файле} repeat {Цикл поиска по совпадению поля Name:} inc(D) ; read(DataFile,Data); with Data do while Length(Name) < LName do Name := Name+' ' until Data.Name=s; seek(DataFile,pred(FileSize(DataFile))); read(DataFile,Data); {Читаем последнюю запись} seek(DataFile,D); write(DataFile,Data); {Помещаем ее на место удаляемой} seek(DataFile,pred(Filesize(DataFile))); truncate(DataFile); {Удаляем последнюю запись} with PS do D := IndexOf(At(Location)); PS.AtFree(D); {Удаляем строку из коллекции} Draw {Обновляем окно} end; {DeleteItem} {-------------} Procedure AddItemfEdit: Boolean); {Добавляет новый или редактирует старый элемент данных} const у = 1; dy= 2; L = LName+LPhone+LAddr; var Data: DataType; R: TRect; InWin: PDialog; BName,BPhone,BAddr: PInputLine; Control: Word; OldCount: Word; s: String; p: PString; begin Seek(DataFile,Filesize(DataFile));{Добавляем записи в конец файла} repeat {Цикл ввода записей} if Edit then {Готовим заголовок} s := 'Редактирование:' else begin Str(Filesize(DataFile)+1,s); while Length(s) < 3 do s := '0'+s; s := 'Вводится запись N '+s end; FillChar(Data,SizeOf(Data),' ');{Заполняем поля пробелами} R.Assign(15,5,65,16); InWin := New(PDialog, Init(R, s));{Создаем окно} with InWin do begin R.Assign(2,y+1,2+LName,y+2); {Формируем окно:} BName := New(PInputLine, Init(R,LName)) Insert(BName); {Поле имени} R.Assign(2,y,2+LName,y+1) ; Insert(New(PLabel, Init(R, 'Имя',BName))); R.Assign(2,y+dy+1,2+LPhone,y+dy+2); BPhone := NewtPInputLine, Init(R,LPhone)); Insert(BPhone); {Поле телефон} R.Assign(2,y+dy,2+LPhone,y+dy+1); Insert(New(PLabel, Init(R, 'Телефон',BPhone))); R.Assign(2,y+2*dy+1,2+LAddr,y+2*dy+2) ; BAddr := New(pinputLine, Init(R,LAddr)); Insert(BAddr); {Поле адреса} R.Assign)2,y+2*dy,2+LAddr,y+2*dy+1); Insert(New(PLabel, Init(R, 'Адрес',BAddr))); {Вставляем две командные кнопки:} R.Assign(2,y+3*dy+1,12,y+3*dy+3); Insert(New(PButton, Init(R, 'Ввести',cmOK,bfDefault))) ; R.Assign(2+20,y+3*dy+1,12+20,y+3*dy+3) ; Insert(NewfPButton, Init(R, 'Выход',cmCancel,bfNormal) SelectNext(False) {Активизируем первую кнопку} end; {Конец формирования окна} if Edit then with Data do begin {Готовим начальный текст:} p := PS.At(Location); {Читаем данные из записи} s := p; Name := copy(s,1,LName); Phone:= copy(s,succ(LName),LPhone); Addr := copy(s,succ(LName+LPhone),LAddr); InWin.setData(Data) {Вставляем текст в поля ввода} end; Control := DeskTop.ExecView(InWin); {Выполняем диалог} if Control=cmOk then with Data do begin if Edit then DeleteItem; {Удаляем старую запись} Name := BName.Data; Phone:= BPhone.Data; Addr := BAddr.Data; s[0] := chr(L) ; FillChar(s [1] , L, ' ') ; move (Name [1] ,s [1] ,Length (Name)) ; move(Phone[1],s[succ(LName)],Length(Phone)); move(Addr[1],s[succ(LName+LPhone)],Length(Addr) OldCount := PS. Count; {Прежнее количество записей} PS . Insert (NewStr (s) ) ; {Добавляем в коллекцию} {Проверяем добавление } if OldCount <> PS. Count then Write (DataFile, Data) {Да - добавляем в файл} end until Edit or (Control=cmCancel) ; Draw end; {AddItem} {-----------------} Procedure SearchItem; {Ищет нужный элемент} Function UpString(s: String): String; {Преобразует строку в верхний регистр} var k: Integer; begin for k := 1 to Length(s) do if s[k] in ['a'..'z'] then s[k] := chr(ord('A')+ord(s [k] ) -ord('a') ) else if s[k] in ['a'..'n'] then s[k]:= chr(ord('A')+ord(s[k] )-ord('a') ) else if s[k] in ['p'..'я'] then s[k] := chr(ord('P')+ord(s [k] ) -ord('p') ) UpString := s end; {UpString} var InWin: PDialog; R: TRect; s: String; p: PInputLine; k: Word; begin {SearchItem} R.Assign(15,8,65,16) ; InWin := New (PDialog, Init (R, 'Поиск записи:')) with InWin do begin R.Assign(2,2,47,3) ; p := New (PInputLine,Init(R,50)); Insert (p) ; R.Assign(1,1,40,2) ; Insert (New (PLabel, Init(R,'Введите образец для поиска:',р))); R.Assign(10,5,20,7) ; Insert (New (PButton,Init(R,'Ввести',cmOk,bfDefault))); R.Assign(25,5,35,7) ; Insert (New (PButton,Init (R,' Выход' ,cmCancel,bf Normal))); SelectNext (False) end; if DeskTop.ExecView(InWin) = cmCancel then exit; s :=p.Data; Location := 0; while (UpString(s) >= UpString (PString(PS. At (Location)))) and (Location < pred(PS. Count) ) do inc (Location) ; if (Location < Delta.Y) or (Location > Delta.Y+pred(Size.Y)) then ScrollTo (Delta.X, Location) else Draw end; {SearchItem} {-----------------} var R: TPoint; label Cls; begin TScroller. 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: {Реакция на щелчок мышью} begin MakeLocal(MouseWhere, R);{Получаем в R локальные координаты указателя мыши} Location := Delta.Y+R.Y; Draw end; evKeyDown: {Реакция на клавиши + -} case Event.KeyCode of kbEsc: goto Cls; kbGrayMinus: if Location > Delta.Y then begin dec(Location); Draw end; kbGrayPlus: if Location < Delta.Y+pred(Size.Y)then begin inc(Location); Draw end; end end end; {Tlnterior.HandleEvent} {------------------} Procedure TNotebook.Work; {Работа с данными} var R : TRect ; PW : PWorkWin ; Control: Word; begin R.Assign(0,0,80,23) ; PW := New (PWorkWin, Init (R) ) ; Control := DeskTop.ExecView(PW) ; Dispose (PW, Done) end; {-------------------} Procedure TNOtebook.HandleEvent (var Event: TEvent) ; {Обработчик событий программы} begin {TNOtebook.HandleEvent} TApplication.HandleEvent (Event) ;{Обработка стандартных команд cmQuit и cmMenu} if Event.What = evCommand then case Event.Command of {Обработка новых команд:} cmOpen: FileOpen; {Открыть файл} cmSave: FileSave; {Закрыть файл} cmChangeDir : ChangeDir; {Сменить диск} cmDOSShell : DOSCall; {Временный выход в ДОС} cmWork : Work; {Обработать данные} else exit {Не обрабатывать другие команды} end; ClearEvent(Event) {Очистить событие после обработки} end; {TNOtebook.HandleEvent} {-------------} Procedure TNotebook. InitMenuBar; {Создание верхнего меню} var R: TRect; begin GetExtent(R) ; R.B.Y := succ (R.A.Y) ; {R - координаты строки меню} MenuBar := New(PMenuBar, Init(R, NewMenu ( {Создаем меню} {Первый элемент нового меню представляет собой подменю (меню второго уровня) . Создаем его} NewSubMenu ( '~F~/Файл' , hcNoContext, {Описываем элемент главного меню} NewMenu ( {Создаем подменю} NewItem( {Первый элемент} '~1~/ Открыть', 'F3 ', kbF3,cmOpen, hcNoContext, NewItem( {Второй элемент} '~2~/ Закрыть', 'F2',kbF2,cmSave,hcNoContext, NewItem( {Третий элемент} '~3~/ Сменить диск1 , ' ' , 0, cmChangeDir, hcNoContext, NewLine( {Строка-разделитель} NewItem( '~4~/ Вызов ДОС' , ' ' , 0, cmDOSShell, hcNoContext, NewItem( '~5~/ Конец работы' , 'Alt-X' , kbAltX, cmQuit,hcNoContext, NIL)))))) {Нет других элементов подменю} ), {Создаем второй элемент главного меню} NewItem('~W~/ Работа', ' ', kbF4,cmWork, hcNoContext, NIL) {Нет других элементов главного меню} )))) end; {TNotebook. InitMenuBar} {-----------------} Procedure TNotebook. InitStatusLine; {Формирует строку статуса} var R: TRect; {Границы строки статуса} begin GetExtent (R) ; {Получаем в R координаты всего экрана} R.A.Y := pred(R.B.Y) ; StatusLine := New(PStatusLine, Init(R, {Создаем строку статуса} NewStatusDef (0, $FFFF, {Устанавливаем максимальный диапазон контекстной справочной службы} NewStatusKey('~Alt-X~ Выход1, kbAltX, cmQuit, NewStatusKey(I~F2~ Закрыть', kbF2, cmSaveFile, NewStatusKey ( '~F3~ Открыть', kbF3, cmOpenFile, NewStatusKey ( '~F4~ Работа', kbF4, cmWork, NewStatusKey ( '~F10~ Меню1, kbF10, craMenu, NIL) ) ) ) ) , {Нет других клавиш} NIL) {Нет других определений} )); DisableCommands (WinCom1) {Запрещаем недоступные команды} end; {TNotebook . InitStatusLine} {------------------} var Nbook: TNotebook; begin Nbook. Init ; Nbook. Run; Nbook . Done end.
|
(с)Все права защищены По всем интересующим вопросам прошу писать на электронный адрес |