
- •«Озерский технический колледж» Курсовой проект в сфере разработки «Delphi» Разработка программы "Текстовый редактор"
- •Введение.
- •Пользовательский интерфейс.
- •Аналоги.
- •Среда программирования.
- •Структура программы.
- •Принципы графических алгоритмов.
- •Системные требования.
- •Заключение.
- •Список используемой литературы.
Структура программы.
Весь исходный текст программы очень большой (»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;
Вся программа построена на основе большого количества классов, каждый из которых отвечает за отдельную функцию. Это помогает локализовать, разбить по частям всю программу, а не создавать огромные процедуры, обработчики событий, что, конечно же, идет на пользу и является подтверждением преимуществ объективно-ориентированного метода программирования.