Сначала рассмотрим возможности работы с графикой в Delphi.
Для выполнения операций рисования необходим класс TCanvas. С помощью его свойств и методов можно рисовать на поверхности видимых объектов, которые имеют свойство Canvas, таких как форма Form и графический образ Image. Canvas переводится как «поверхность», «холст для рисования». Холст состоит из отдельных точек – пикселей. Положение пикселя характеризуется его горизонтальной (X) и вертикальной (Y) координатами. Левый верхний пиксель имеет координаты (0, 0). Координаты возрастают сверху вниз и слева направо. Значения координат правой нижней точки холста зависят от размера холста.
Любая поверхность рисования включает объекты пера TPen, кисти TBrush и шрифта TFont. Объекты пера и кисти используются для геометрических фигур, а объект шрифта позволяет управлять атрибутами текста, выводимого на поверхности объекта. Основные свойства пера Pen – это цвет (Color), Стиль (Style), Толщина (Width). У кисти Brush наиболее часто используются свойства Цвет (Color) и Стиль (Style).
Свойство Canvas доступно только при выполнении программы, поэтому получаемые с его помощью рисунки являются динамическими. Они существуют только тогда, когда приложение работает.
Для рисования нам понадобятся три события: OnMouseDown (нажатие кнопки мыши), OnMouseMove (перемещение мыши), OnMouseUp (отпускание кнопки мыши).
Процедуры обработчики событий OnMouseDown и OnMouseUp имеют одинаковые параметры
(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer)
- Sender –здесь храниться объект, который сгенерировал событие.
- Button – здесь храниться признак клавиши, которая была нажата. Этот параметр может быть равен: mbLeft (нажата левая кнопка), mbRight (нажата правая кнопка) или mbMiddle (нажата средняя кнопка).
- Shift – состояние дополнительных клавиш клавиатуры. Этот параметр может хранить любые из следующих значений ssShift – нажата клавиша Shift, ssAlt – нажата клавиша Alt, ssCtrl – нажата клавиша Ctrl, ssLeft – нажата левая кнопка мыши, ssRight – нажата правая кнопка мыши, ssMiddle – нажата средняя кнопка, ssDouble – был двойной щелчок мышкой.
- X,Y – последние два параметра – это координаты, в которых была нажата кнопка мыши.
- Опишите в разделе public модуля формы следующие переменные: z типа byte, drawing типа boolean.
- Переменная z будет содержать номер текущего инструмента рисования. Поэтому в событие OnClick кнопки «Карандаш» добавьте код z:=1; аналогично, для Ластика – z:=2; для Линии – z:=3; и т.д. до 7.
Карандаш
Карандаш работает следующим образом:
- при нажатии кнопки мыши на компонент Image1 начинается рисование, и указатель текущей позиции перемещается в положение щелчка мыши;
- при перемещении мыши рисуется линия из текущей позиции до нового положения мыши;
- при отпускании мыши рисование заканчивается.
Для признака рисования будет использоваться переменная drawing типа Boolean. Если эта переменная равна true, то пользователь нажал кнопку мыши и при перемещении мыши должно происходить рисование.
По событию OnCreate для формы мы должны задать переменной drawing значение по умолчанию – false, ведь после старта приложения кнопка мыши еще не нажата мышь, и при перемещении мыши рисование происходить не должно.
- Чтобы избежать случайного попадания в переменную drawing значения True,напишите следующий код (для выделения формы воспользуйтесь Инспектором объектов):
procedure TMainForm.FormCreate(Sender: TObject);
begin
drawing:=false;
end;
- По нажатию кнопки мыши OnMouseDown на компонент Image1 напишите следующий код:
procedure TMainForm.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
drawing:=true;
with Image1.Canvas do
case z of
1: MoveTo(x,y);
end;
end;
Оператор выбора case здесь используется потому, что дальше нам придется выбирать номер текущего инструмента рисования. Если сейчас используется карандаш, то указатель текущего положения смешается в положение мыши X, Y.
- Теперь напишите обработчик события OnMouseMove, который генерируется при каждом перемещении мыши:
procedure TMainForm.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if drawing then with Image1.Canvas do
case z of
1: LineTo(X,Y);
end;
end;
В первой строчке происходит проверка, если переменная drawing равна true, то сейчас происходит рисование и поэтому рисуется линия до точки X, Y.
- По событию OnMouseUp присвойте переменной drawing значение false.
Инструмент «Карандаш» должен быть автоматически выбран при запуске программы, т.е. переменная z должна иметь значение 1, а кнопка «Карандаш» должна находится в нажатом состоянии. Создадим вспомогательную процедуру Start, которая будет устанавливать все исходные свойства используемых компонентов, и будем вызывать ее сначала при создании формы, а затем каждый раз при создании нового документа.
- В разделе type модуля формы опишите процедуру
procedure Start;
- Создайте процедуру
procedure TMainForm.Start;
begin
z:=1; ToolButton1.Down:=True;
end;
- А теперь в обработчике события OnCreate формы MainForm вызовите эту процедуру, т.е. добавьте код
Start;
Ластик
Ластик работает также как и карандаш, только рисует не основным цветом, а цветом фона. Основной цвет рисования содержится в свойстве холста Pen.Color, а цвет фона – в Brush.Color. Поэтому при включении инструмента Ластик необходимо изменить цвет пера на цвет кисти, а после окончания работы с Ластиком восстановить исходное значение.
- В разделе public опишите вспомогательную переменную BufColor типа TColor, в которой будет содержаться старое значение цвета пера.
- В операторе выбора case процедуры Image1MouseDown добавьте еще один вариант:
procedure TMainForm.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
drawing:=true;
with Image1.Canvas do
case z of
1: MoveTo(x,y);
2: begin
BufColor:= Image1.Canvas.Pen.Color;
Image1.Canvas.Pen.Color:=Image1.Canvas.Brush.Color;
MoveTo(x,y);
end;
end;
end;
- При перемещении мыши Ластик выполняет действия, аналогичные Карандашу, поэтому измените обработчик события OnMouseMove следующим образом:
procedure TMainForm.Image1MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
begin
if drawing then with Image1.Canvas do
case z of
1,2: LineTo(X,Y);
end;
end;
- Событие OnMouseUp измените на:
procedure TMainForm.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
drawing:=false;
with Image1.Canvas do
case z of
2: Image1.Canvas.Pen.Color:=BufColor;
end;
end;
Здесь цвет пера восстанавливается из вспомогательной переменной BufColor.
Линия
Линия работает следующим образом:
- при нажатии кнопки мыши на компонент Image1 начинается рисование, мы запоминаем текущие координаты точки, где был произведен щелчок мышью;
- при движении мыши рисуется линия из начальной точки до текущей;
- при отпускании мыши рисование заканчивается и на холсте остается только последняя линия.
Для того чтобы при движении мыши на холсте оставалась только одна линия, а не все промежуточные, нужно затирать старые линии и восстанавливать то, что было под ними.
- Добавьте в раздел public переменные:
OldPenMode:TPenMode;
StartX, StartY, OldX, OldY:Integer;
Переменные StartX, StartYбудут использоваться для запоминания координат начала линии, а переменные OldX, OldYнужны для хранения конечных координат линии. В переменной OldPenMode будет сохраняться текущее значение режима рисования.
Примечание: У пера (свойство Pen холста) есть очень много режимов рисования. Режимы рисования устанавливаются в свойстве Mode пера. Это свойство имеет тип TPenModeи может принимать следующие значения: pmBlack, pmWhite, pmNop, pmNot,pmCopy, pmNotXorи так далее.
- В операторе выбора case обработчика события MouseDown добавьте очередной вариант
3: begin
OldPenMode:=Canvas.Pen.Mode;
Pen.Mode:=pmNotXor;
StartX:=X; StartY:=Y; OldX:=X; OldY:=Y;
end;
Сначала мы сохраняем текущий режим рисования в переменной OldPenMode. В следующей строке меняем режим на pmNotXor. В таком режиме, когда мы рисуем первый раз какую-то фигуру, то она выводиться в нормальном виде. Если нарисовать ее второй раз, то она просто стирается и старое изображение восстанавливается на экране. Далее мы просто запоминаем координаты StartX, StartY, OldX и OldY.
- В обработчик события OnMouseMove добавьте вариант
3: begin
MoveTo(StartX, StartY); LineTo(OldX,OldY);
MoveTo(StartX, StartY); LineTo(X,Y);
OldX:=X; OldY:=Y;
end;
Сначала мы рисуем линию из начальной позиции до старой, где она была нарисована на прошлом шаге. Так как используется режим pmNotXor, то повторное рисования линии в старой позиции просто восстанавливает старое значение. После этого мы рисуем фигуру в новой позиции и сохраняем текущую позицию Х и Y в переменных OldXи OldY.
- В процедуру MouseUp добавьте вариант
3: begin
Pen.Mode:=OldPenMode;
MoveTo(StartX,StartY); LineTo(X,Y);
end;
Здесь сначала восстанавливается старое значение режима рисования, а затем рисуется уже окончательный вариант линии.
Прямоугольник, эллипс
Для рисования прямоугольника используется метод Rectangle (x1, y1, x2, y2), где x1, y1 и х2, у2 – координаты левого верхнего и правого нижнего углов прямоугольника. А для рисования эллипса – Ellipse (x1, y1, х2, у2), где x1, y1, х2, у2 – координаты прямоугольника, внутри которого вычерчивается эллипс.
Рисование прямоугольника и эллипса происходит аналогично рисованию линии:
- при нажатии кнопки мыши мы запоминаем текущие координаты точки;
- при движении мыши фигура перерисовывается от стартовой позиции до текущей;
- при отпускании мыши рисование заканчивается и холсте остается только последняя фигура.
- Поскольку при событии OnMouseDown выполняются те же действия, что и для линии (т. е. при z=3,4,5 действия одинаковые), нужно только дописать варианты 4 и 5 к варианту 3:
3,4,5: begin …
- В событии OnMouseMove добавьте два новых варианта
4: begin
Rectangle(StartX, StartY, OldX, OldY);
Rectangle(StartX, StartY, X, Y);
OldX:=X; OldY:=Y;
end;
5: begin
Ellipse(StartX, StartY, OldX, OldY);
Ellipse(StartX, StartY, X, Y);
OldX:=X; OldY:=Y;
end;
- В событии OnMouseUp добавьте
4: begin Pen.Mode:=OldPenMode; Rectangle(StartX,StartY,X,Y); end;
5: begin Pen.Mode:=OldPenMode; Ellipse(StartX,StartY,X,Y); end;
Заливка
Для инструмента Заливка используем метод
FloodFill (X, Y: double; Color: TColor; FillStyle: TFillStyle);
Этот метод заполняет холст, используя текущую кисть. FloodFill начинается в точке (X, Y) и заполняет область, ограниченную указанной цветом Color. Параметр FillStyle определяет способ заполнения используемый (fsBorder заполняет до тех пор, пока не встретит указанный цвет, и fsSurface заполняет, пока встречается указанный цвет).
Поскольку заливка происходит просто при щелчке мыши, нам понадобится только событие OnMouseDown. Добавьте в него вариант
6: FloodFill(X, Y, Pixels[X,Y], fsSurface);
Свойство Pixels [X,Y] определяет цвет точки с координатами [X,Y]. Таким образом, наш инструмент Заливка определяет цвет точки, в которой был произведен щелчок мышью, и заливает окрашенную этим цветом область цветом кисти холста.
Надпись
Работа инструмента Надпись заключается в том, чтобы по щелку мыши выводить на рисунке набранный пользователем текст.
Для вывода текста на холст используется процедура TextOut (x, у, Текст), где х, у – координаты точки графической поверхности, на которой выполняется вывод текста, а Текст – переменная или константа символьного типа, значение которой задает выводимый текст.
Фактически, инструмент Надпись должен выполнять следующие действия:
- по щелчку мыши запоминать текущие координаты;
- открывать окно для ввода текста пользователем;
- выводить этот текст в заданной точке.
Примечание: Область вывода текста закрашивается текущим цветом кисти. Поэтому перед выводом текста свойству Brush.Style нужно присвоить значение bsClear или задать цвет кисти, совпадающий с цветом поверхности, на которую выводится текст.
- В разделе public модуля опишите переменную BufStyle типа TBrushStyle, в ней будет содержаться текущий стиль кисти.
- В обработчик события OnMouseDown рисунка Image1 добавьте еще один вариант
7: begin
BufStyle:=Brush.Style; Brush.Style:=bsClear;
s:=InputBox('Ввод текста', 'Введите текст:','');
TextOut(X,Y,s);
Brush.Style:=BufStyle;
end;
А в разделе var это процедуры опишите переменную s типа string.
Данная процедура очищает стиль кисти, вызывает стандартное диалоговое окно InputBox для ввода текста, выводит на рисунок текст, а затем восстанавливается стиль кисти.
Создание палитры цветов
- С помощью Инспектора Объектов выделите форму MainForm. Перейдите на страницу Win32 Палитры компонентов и дважды щелкните мышью по компоненту ToolBar. В результате на форме появится еще одна панель инструментов. На нее мы и поместим компоненты палитры.
- Выделите панель Toolbar2, задайте для нее выравнивание (Align) по нижнему краю (alBottom), в свойстве AutoSize выберите True (это свойство разрешает компоненту автоматически изменять свои размеры в зависимости от размеров содержащихся в нем компонентов).
Рис. 4. Промежуточный вид формы MainForm.
- На эту панель инструментов поместите панель Panel со страницы Standard шириной (Width) 50 и высотой (Height) 50, удалите ее заголовок (Caption). Поэкспериментируйте со свойствами панели BevelInner, BevelOuter, определяющими тип внутренней и внешней кромки панели. В это панели будет содержаться информация об основном цвете и цвете фона.
- Внутри этой панели Panel разместите еще одну панель размером 20 на 20, удалите ее заголовок Caption и задайте тип границы.
- Скопируйте эту панель и вставьте новую рядом с ней (см. рис. 4). Первая панель предназначена для отображения основного цвета, а вторая – для цвета фона. Измените имена этих панелей (Name) на pnMain и pnBgr соответственно.
- Изначально основной цвет рисования черный, а цвет фона – белый, поэтому в процедуре Start добавьте код:
pnMain.Color:=clBlack; pnBgr.Color:=clWhite;
- Поместите на панель инструментов ToolBar2 еще одну панель Panel, которая будет содержать стандартный набор цветов. Удалите ее заголовок (Caption) и задайте вид границ. Поместите на нее компонент ColorCrid со страницы Samples.
Примечание: таблица цветов ColorGrid предназначена для выбора основного и фонового цвета из 16-цветной палитры. Основной цвет выбирается щелчком левой кнопки мыши, отображается символами FG и содержится в свойстве ForegroundColor, а фоновый цвет выбирается правой кнопкой, отображается символами BG и содержится в свойстве BackgroundColor (если оба цвета совпадают, соответствующая клетка таблицы помечается символами FB).
- Измените свойство GridOrdering компонента ColorCrid1 на go8x2, ширину (Width) задайте равной 168, а высоту (Height) – 40. В процедуру Start добавьте строчки
ColorGrid1.ForegroundIndex:=0;
ColorGrid1.BackgroundIndex:=15;
- Создайте для ColorCrid1 процедуру
procedure TMainForm.ColorGrid1Change(Sender: TObject);
begin
with Image1.Canvas do begin
Pen.Color:=ColorGrid1.ForegroundColor;
pnMain.Color:=Pen.Color;
Brush.Color:=ColorGrid1.BackgroundColor;
pnBgr.Color:=Brush.Color;
Font.Color:=Pen.Color;
end;
end;
Эта процедура изменяет цвет пера на основной цвет, а цвет кисти на цвет фона и выводит эти цвета на соответствующие панели.
- Теперь создадим возможность выбирать не стандартные, а произвольные цвета. Для этого понадобится диалоговое окно ColorDialog со страницы Dialogs. Поместите его на форму.
- На панели для выбора цветов поместите две кнопки SpeedButton (см. рис. 4). Задайте для них размеры 20 на 20 и с помощью свойства Glyph поместите на них изображения pen.bmp и fill.bmp из папки Buttons.
- Задайте для них значение свойства Flat равным True. В свойстве Hint наберите «Основной цвет|Выбор основного цвета рисования» и «Цвет фона|Выбор цвета фона» соответственно, а затем измените свойство ShowHint на True.
- Для первой кнопки в обработчик события OnClick добавьте код
ColorDialog1.Color:=Image1.Canvas.Pen.Color;
if ColorDialog1.Execute then begin
Image1.Canvas.Pen.Color:=ColorDialog1.Color;
pnMain.Color:=ColorDialog1.Color;
end;
- Для второй кнопки создайте процедуру
procedure TMainForm.SpeedButton2Click(Sender: TObject);
begin
ColorDialog1.Color:=Image1.Canvas.Brush.Color;
if ColorDialog1.Execute then begin
Image1.Canvas.Brush.Color:=ColorDialog1.Color;
pnBgr.Color:=ColorDialog1.Color;
end;
end;
- Теперь можно запустить проект и проверить его работу. На данном этапе графический редактор может использовать все свои инструменты и менять основной и фоновый цвет.