Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
курсовой проект Текстовый редактор.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
349.18 Кб
Скачать

Структура программы.

Весь исходный текст программы очень большой (»10000 строк), поэтому он размещён в разных файлах, каждый из которых играет определённую роль в построении приложения. Основой всей программы является главное окно программы (класс TMainForm; файл MainFrm.pas). На нем расположены все панели инструментов, строка состояния, меню и сама область рисования, расположенная в рабочей области прокрутки. Некоторые элементы управления – это стандартные компоненты Delphi (TMainMenu, TScrollBox, TScrollBar и т. д.), другие же – это переделанные компоненты (TFeSpeedButton, TFePanel, TFeStatusBar) с целью уменьшить размер исполняемого файла, третьи – это специальные компоненты (TFePaint, TFePropsButton, TColorPickerButton), созданные на основе базовых классов Delphi.

Ядром программы, отвечающим за создание и преобразование рисунков, является класс (компонент) TFePaint. Именно этот класс обрабатывает все действия мыши в области рисования, именно он организует взаимодействие пользователя и программы, связанные с рисованием и созданием эффектов. TFePaint является дочерним классом от TCustomControl, так как является владельцем для других классов (TFeImage, TSelectImage, TPut). Он имеет свойство DrawMethod типа TDrawMethod, которое указывает на инструмент, выбранный пользователем (dmPen, dmLine, dmEllipse, dmRectSelect). Изменение значения этого свойства происходит следующим образом: при запуске программы свойству Tag(этикетка) каждой кнопке на панели инструментов присваивается определённое значение:

PenBtn.Tag := Integer (dmPen);

LineBtn.Tag := Integer (dmLine);

При нажатии на кнопку вызывается обработчик события общий для всех кнопок на данной панели:

procedure TMainForm.SpeedBtnClick(Sender: TObject);

begin

MainRis.DrawMethod := TDrawMethod(TFeSpeedButton(Sender).Tag);

end;

Таким образом, нет необходимости создавать для каждой кнопки собственный обработчик щелчка мыши. Всё делается с помощью преобразования типов. Тот же способ применён и по отношению к пунктам меню, так как в противном случае код оказался бы очень большим и однообразным, потому что пунктов меню очень много. Но в данном случае не присваивается значений какому-либо свойству, а вызывается специальная процедура:

procedure TMainForm.MenuClick(Sender: TObject);

begin

MainRis.Doing(TDrawAction(TMenuItem(Sender).Tag));

end;

procedure TFePaint.Doing(const Action: TDrawAction);

var Fon, AGrid: Boolean;

UCount: Byte;

Size: TPoint;

Bmp: TBitmap;

begin

if not GetCan(Action) then Exit;

Ended;

case Action of

daClear: begin

CanChangeImage;

ClearImage;

ChangedImage;

end;

daCopyToFile: Save(True, False);

end;

end;

Нестандартный способ решения задачи применён и к алгоритму отмены и повтора действий пользователя. Создан специальный класс TBmpMemory, который хранит изображения в памяти. После каждого действия, будь то рисование прямоугольника или увеличение контрастности, изображение сохраняется в отдельной ячейке (Cell) динамического массива, длина которого равна числу возможных отмен + 1. Данный массив представляет собой двусвязный список. Тип каждой ячейки определён следующим образом:

PBitmapCell = ^TBitmapCell;

TBitmapCell = record

NextCell: PBitmapCell; // указатель на следующую ячейку

PrevCell: PBitmapCell; // указатель на предыдущую ячейку

Bitmap: TBitmap;

end;

Таким образом, каждый элемент списка имеет указатель на предыдущий и на следующий элемент. Указатель PrevCell первой ячейки указывает на последнюю, а указатель NextCell последней ячейки указывает на первую ячейку. Получается замкнутое кольцо без входа и выхода. Это сделано по той причине, что после отмены действия, для восстановления требуется то изображение, которое было отменено. Например: пользователь нарисовал круг, а затем линию. В первой ячейке записано изображение, которое было до рисования круга, во второй – после рисования круга, а в третьей – после рисования линии. После отмены последнего действия указатель перемещается на предыдущую ячейку (ячейка с кругом, но без линии):

procedure TBmpMemory.Undo(Bitmap: TBitmap);

begin

if CanUndo then begin

Dec(FNumUndo); //уменьшаем число возможных отмен

Bitmap.Assign(FActiveCell^.Bitmap); //передаём изображение с активной ячейки

FActiveCell := FActiveCell^.PrevCell;//переносим указатель на предыдущую ячейку

end;

end;

Если же пользователь передумал и решил вернуть нарисованное, то он может вызвать повтор последнего отменённого действия (если после отмены ничего не было сделано):

procedure TBmpMemory.Redo(Bitmap: TBitmap);

begin

if CanRedo then begin

Inc(FNumUndo); //увеличиваем число возможных отмен

FActiveCell := FActiveCell^.NextCell; //переносим указатель на следующую ячейку

Bitmap.Assign(FActiveCell^.NextCell^.Bitmap); //передаём изображение

//со следующей после активной ячейки, т. к. активная ячейка та,

//которая должна быть отменена

end;

end;

Вся программа построена на основе большого количества классов, каждый из которых отвечает за отдельную функцию. Это помогает локализовать, разбить по частям всю программу, а не создавать огромные процедуры, обработчики событий, что, конечно же, идет на пользу и является подтверждением преимуществ объективно-ориентированного метода программирования.