Общий обзор программирования графики в Kylix
Обновление экрана
Типы графических объектов
Работа с объектом Canvas
Свойства и методы объекта Canvas
Использование пера
Цвет пера
Ширина пера
Стиль пера
Режим пера
Установка и определение позиции пера
Использование кисти
Цвет кисти
Стиль кисти
Установка значения свойства Bitmap
Использование методов объекта Canvas
Рисование линий и ломаных
Рисование геометрических фигур
Создание приложения наподобие графического редактора
Другие методы работы с графикой в Kylix
Работа с компонентом Image
Загрузка и сохранение графических файлов
Загрузка графического образа из файла
Сохранение графического образа в файл
Работа с буфером обмена
Копирование графики в буфер обмена
Вырезание графики в буфер обмена
Вставка графики из буфера обмена.
Работа с мышью
Обработка события OnMouseDown
Обработка события OnMouseUp
Обработка события OnMouseMove
Создание простой игровой программы
Из этой главы вы узнаете, как с помощью Kylix можно создавать приложения, использующие
графику. Вы научитесь работать с объектом канвы или холста (Canvas), рисовать
различные фигуры, строить графики и диаграммы. В конце этой главы мы создадим
простую игровую графическую программу.
Kylix предоставляет программисту несколько способов работы с графикой. Для добавления
графического элемента в ваше приложение вы можете вставить предварительно созданную
картинку во время разработки приложения, создать картинку во время разработки
приложения средствами Kylix или нарисовать ее во время работы приложения.
Общий обзор программирования графики в Kylix
Графические компоненты CLX инкапсулируют возможности Qt, которые позволяют достаточно
легко добавлять графику в Linux-приложения.
Для рисования в Kylix (так же, как и в Delphi) используется канва объекта, на
котором будет производиться рисование.
Канва (холст) - это свойство, имеющееся у некоторых объектов, входящих в CLX
Kylix, которое позволяет рисовать на поверхности объекта, как на холсте.
Примечание
Далее по тексту мы будем использовать слово канва вместо слова холст, т. к.
это слово более полно описывает поверхность для рисования.
Главное преимущество канвы объекта в том, что она наиболее эффективно использует
ресурсы, и вы можете применять одни и те же методы для вывода графики на экран,
принтер или графический образ. Канва объекта доступна программисту только во
время работы приложения, таким образом, для обращения к канве нужно использовать
команды языка Object Pascal.
Способ отображения графики в вашем приложении зависит от типа объекта CLX, канва
которого используется для рисования. Если вы напрямую выводите рисунок на канву
объекта управления, изображение будет выведено немедленно.
В то же время, если вы рисуете на канве объекта, находящегося вне экрана, Например
на канве объекта графического образа TBitmap, изображение не будет отображаться,
пока не будет выполнено копирование из графического раза на канву элемента управления.
Примечание
Использование объекта TBitmap в консольных приложениях приведет к исключительной
ситуации с выдачей сообщения "Имя проекта: невозможно соединиться с Х-сервером".
Применяя графику в своих приложениях, вы будете довольно часто использовать
два основных понятия: черчение и рисование.
Черчение - это создание с помощью команд языка Object Pascal особых одиночных
графических элементов, например линий и геометрических фигур.
Рисование - это создание готового (полного) графического образа на канве объекта.
Таким образом, рисование включает в себя черчение. В качестве примера южно рассмотреть
прорисовку окна редактирования TEdit, который рисует сам себя, начертив сначала
прямоугольник, а затем - текст внутри прямоугольника.
Обновление экрана
Во время работы приложения многие объекты на экране изменяют свое состояние.
Может измениться текст или графика, содержащаяся внутри объекта. Для того чтобы
эти изменения отображались на экране, необходимо обновление объектов.
Обновление (refresh) объектов - это процесс, выполняемый операционной системой
для перерисовки окон и компонентов, расположенных внутри окон.
Для самостоятельного вызова метода обновления компонента вы можете использовать
метод Refresh, который имеется у всех компонентов CLX, поддерживающих обновление.
При обновлении объекта генерируется событие OnPaint. Вы можете написать собственный
обработчик события OnPaint. Приведем пример перехвата события обновления формы.
Будем выводить окно с текстовым сообщением всякий раз, г когда произойдет обновление
формы. Создадим новое приложение - File/New Application. Теперь разместим на
форме Form1 кнопку Button1(рис. 13.1).
Рис. 13.1. Форма приложения
Напишем в обработчике события OnPaint формы Form1 следующий код (листинг 13.1):
Листинг 13.1. Код обработки события OnPaint
procedure TForm1.FormPaint(Sender: TObject);
begin
messagedlg('Произошло обновление формы',mtInformation,[mbOK],0);
end;
Теперь напишем код обработки события OnClick.
Листинг 13.2. Код обработки события OnClick
procedure TForm1.ButtonlClick(Sender: TObject);
begin
Form1.Refresh; // Вызываем метод обновления формы
end;
Запустим приложение на выполнение. Сразу после запуска произойдет событие первоначальной
прорисовки формы. В результате появится окно сообщения об обновлении формы (рис
13.2).
Попробуйте изменить размеры формы в сторону увеличения или нажмите на кнопку
Button1. В результате вы увидите то же самое информационное окно.
Рис. 13.2. Информационное окно, извещающее об обновлении формы
Если вы используете компонент TImage для отображения графики на форме, не нужно
будет заботиться об обновлении графического изображения, держащегося в этом
компоненте. Обновление будет произведено автоматически. Свойство picture компонента
TImage определяет текущий графический образ, рисунок или другую графику, которую
отображает компонент.
Типы графических объектов
Kylix предоставляет программисту несколько графических объектов, которые имеют
собственные методы для рисования на канве, а также для загрузки и сохранения
изображений в графические файлы. В табл. 13.1 приведены основные типы графических
объектов CLX.
Таблица 13.1. Типы графических объектов Kylix
Объект | Описание |
Picture | Используется как контейнер для содержания произвольного
графического образа. Для того чтобы объект Picture мог содержать файлы дополнительных
графических форматов, используйте метод Register |
Bitmap | Мощный графический объект, который используется для создания, манипулирования (масштабирование, скроллинг, вращение, закраска) и хранения картинок как файлов на диске |
Clipboard | Представляет собой контейнер, хранящий текст или графические образы, которые могут быть скопированы, вырезаны из приложения или вставлены в него |
Icon | Представляет собой картинку, загруженную из файла пиктограммы |
Drawing | Содержит файл, в котором записаны операции,
требующиеся для создания изображения. Не содержит самого изображения. Использование этого объекта позволяет свободно масштабировать изображение без потери деталей и обычно требует меньше памяти, чем хранение графического образа. В то же время, отображает рисунок значительно медленнее, чем другие объекты |
Работа с объектом Canvas
С помощью объекта canvas вы можете установить толщину рисуемых линий, тип кисти
для закрашивания областей, шрифт для вывода текста, а также массив пикселов
для представления графического образа. Все это устанавливается с помощью свойств
и методов объекта Canvas.
Свойства и методы объекта Canvas
В табл. 13.2 приводятся наиболее часто используемые свойства объекта Canvas
и их описания.
Таблица 13.2. Свойства объекта Canvas
Свойство | Описание |
Font | Определяет шрифт, который будет использоваться для вывода текста на картинке |
Brush | Определяет цвет и образец кисти, которыми будут заполняться графические объекты и фон канвы |
Реn | Определяет тип пера канвы, которым будут чертиться линии и геометрические фигуры |
PenPos | Определяет текущую позицию пера |
В табл. 13.3 перечислены методы, которые часто используются при рисовании на канве.
Таблица 13.3. Методы объекта canvas
Метод | Описание |
Arc | Предназначен для черчения дуги эллипса или окружности. В качестве параметров метода передаются координаты четырех точек. Первые две точки (x1, y1) и (х2, у2) определяют диагональ прямоугольника, в который вписан эллипс. Третья точка (хЗ, уЗ) задает начальную точку дуги. Точка (х4, у4) задает конечную точку дуги. Третья и четвертая точки принадлежат прямоугольнику, описывающему эллипс. Точки дуги получаются в результате пересечения прямой, проходящей через центр эллипса и точки (хЗ, уЗ) и (х4, у4}. Дуга рисуется против часовой стрелки от начальной до конечной точки |
Chord | Чертит замкнутую фигуру, границами которой являются дуга окружности или эллипса и хорда. Параметры, передаваемые в данный метод, аналогичны параметрам метода Arc |
CopyRect | Копирует прямоугольную часть изображения с одной канвы на другую. Копирование осуществляется в том режиме, который определен свойством CopyMode |
Draw | Рисует изображение, хранящееся в объекте, который
определен параметром Graphic, на канву в координаты, задаваемые параметрами
х и у. Например, Image1.Canvas.Draw (5, 24, Image2.Picture.Bitmap); Копирует в координаты (5, 24) рисунок, находящийся на канве компонента Image2, в канву компонента Image1 |
DrawFocusRect | Рисует изображение пунктирного прямоугольника с автоматической установкой режима пера (свойство Mode) в pmXor. Данный метод имеет место лишь в том случае, когда подсвойство DefaultStyle свойства Style приложения установлено в dsWindows |
DrawPoint | Отображает одиночную точку на канве с использованием текущих установок пера |
DrawPoints | Рисует несколько точек с использованием текущих установок пера |
Ellipse | Чертит на канве эллипс или окружность. Параметрами являются две точки (x1, y1) и (х2, у2), которые определяют диагональ прямоугольника, описывающего эллипс |
FillRect | Заполняет указанную прямоугольную область канвы
цветом, определенным текущим значением свойства кисти (Brush). Например, Image1.Canvas.FillRect(0, 0, 100, 100); Заполняет квадрат с главной диагональю, имеющей координаты (0, 0) и (100, 100), цветом, определенным в свойстве color кисти |
GetClipRegion | Возвращает указатель на текущую вырезаемую область канвы |
LineTo | Чертит на канве прямую линию, начало которой
совпадает с текущим значением координат пера (значение свойства PenPos),
а конец задается параметром (х, у). Конечная точка не принадлежит линии
и не отображается. После чего текущими координатами пера станет точка (х, у). Например, Image1.Canvas.LineTo(100, 130); Чертит линию от текущей позиции пера до точки с координатами (100, 130), не включая саму точку (100, 130), после чего значением PenPos будет точка (100, 130) |
MoveTo | Изменяет текущую позицию пера (значение свойства PenPos) на значение, заданное параметром (х, у). При перемещении пера на канве ничего не чертится. Метод аналогичен прямой установке значения свойства PenPos |
Pie | Чертит замкнутый сегмент эллипса или окружности. Параметры метода аналогичны параметрам метода Arc |
PolyBezier | Чертит на канве цветом пера Реn сглаженную
кривую по заданному множеству точек, определенных в массиве Points. Начинает
рисование с точки, определенной параметром startindex, используя следующие
две точки как направляющие для изгибов кривой. Кривая заканчивается четвертой
точкой массива. Например, Image1.Canvas.PolyBezier([Point(0, 0), Point (100,10) , Point (20,30) , Point (230, 100)], 0); Последний параметр, равный нулю,- это параметр Startindex |
PolyBezierTo | То же самое, что и PolyBezier, только после черчения линии данный метод устанавливает значение свойства PenPos в последнюю точку массива Points |
Polygon | Чертит на канве многоугольник по заданному
множеству точек, определенных в массиве Points, причем первая точка массива
соединяется с последней, после чего многоугольник закрашивается цветом,
определенным свойством кисти Brush. Например, Imagel.Canvas.Polygon([Point (0, 0), Point(10,10), Point(20,30), Point (230, 100)]); |
Polyline | Чертит на канве незамкнутый многоугольник. Аналогичен методу Polygon, только не соединяет первую и последнюю точки массива Points |
Rectangle | Чертит на канве текущим пером Реп прямоугольник, закрашенный цветом, определенным в свойстве кисти Brush. В качестве параметров передаются координаты двух точек: левого верхнего и правого нижнего углов прямоугольника, т. е. его главная диагональ |
RoundRect | Чертит на канве закрашенный цветом, определенным в свойстве кисти Brush, прямоугольник со скругленными углами. Два параметра (x1, y1) и (х2, у2) задают координаты углов прямоугольника (как в методе Rectangle). Два следующих параметра хЗ и уЗ задают эллипс с шириной хЗ и высотой уЗ точек. Углы прямоугольника скругляются по шаблону данного эллипса |
StretchDraw | Рисует графическое изображение, которое содержится
в компоненте, указанном в параметре Graphic, в прямоугольную область канвы,
указанную параметром Rect. Причем изображение растягивается или сжимается
под размер данной области. Например, Image1.Canvas.StretchDraw(Rect(0, 0, 29, 29), Image2.Picture.Bitmap); Уменьшает изображение, имеющее размер больше, чем 30x30 и хранящееся в компоненте Image2, и помещает его на канву компонента Image1 |
TextHeight | Возвращает значение, равное высоте текста, который предполагается вывести на канву с использованием текущего шрифта |
TextOut | Выводит строку текста, задаваемую параметром
Text, на канву в позицию с координатами (х, у). Например, Image1.Canvas.TextOut(10, 10, 'Kylix - лучшая среда разработки под Linux') ; |
TextRect | Похож по действию на метод TextOut, только текст, выходящий за пределы определенной прямоугольной области, не выводится |
TextWidth | Возвращает значение в пикселах, равное длине текста Text, который предполагается вывести на канву компонента текущим шрифтом |
TiledDraw | Рисует размноженное изображение внутри указанного прямоугольника |
Использование пера
Свойство Реn позволяет устанавливать атрибуты пера, которым производится рисование
линий и точек, а также других геометрических фигур.
Пepo имеет четыре собственных свойства, которые вы можете изменять:
Color - цвет пера;
Width - ширина пера; s
Style - стиль пера;
Mode - режим пера.
Значения данных свойств определяют способ, которым будут отображаться линий.
По умолчанию установлен черный цвет пера и его ширина равна одному пикселу,
стиль - сплошной, режим рисования поверх текущего изображения канвы. Рассмотрим
последовательно использование этих четырех свойств.
Цвет пера
Вы можете устанавливать цвет пера по своему усмотрению с помощью свойства color
во время исполнения приложения. Для этого нужно лишь присвоить соответствующее
значение цвета свойству Color пера Реп.
В листинге 13.3 мы устанавливаем красный цвет пера (значение ciRed) по нажатии
кнопки Button 1
Листинг 13.3. Установка значения цвета пера
procedure TForm1.ButtonlClick(Sender: TObject);
begin
Canvas.Pen.Color := PenColor.ForegroundColor;
end;
Ширина пера
Ширина пера определяет толщину линий, которыми будут начерчены геометрические
фигуры.
Примечание
Если вы создаете кросс-платформенное приложение, которое может функционировать
как под Linux, так и под Windows 9х, и ширина пера более одного пиксела, то
имейте в виду, что Windows будет всегда рисовать сплошные линии, независимо
от значения свойства style пера.
Для смены ширины пера достаточно присвоить необходимое числовое значение свойству width пера (листинг 13.4).
Листинг 13.4. Установка ширины пера
procedure TForml.ButtonlClick(Sender: TObject);
begin
Canvas.Pen.Width := 5;
end;
Стиль пера
Свойство style позволяет вам устанавливать различные стили начертания линий.
Это могут быть сплошные линии, пунктирные, точечные и др.
В листинге 13.5 стиль пера меняет последовательно все возможные значения.
Листинг 13.5. Смена стилей пера
procedure TForm1.ButtonlClick (Sender: TObject) ;
begin
with Canvas. Pen do
begin
Style: = psSolid
Style: = psDash
Style: = psDot
Style: = psDashDot
Style: = psDashDotDot
Style: = psClear;
end;
end;
Режим пера
Свойство пера Mode позволяет вам устанавливать различные режимы комбинирования
цвета пера с цветом, расположенным на канве. Например, режим постоянного цвета
пера, режим инверсии цвета пера или фона канвы и пр.
Установка и определение позиции пера
Текущая позиция рисования, с которой начинается рисование линий, называется
позицией пера. Как вы уже знаете, объект канвы хранит текущую позицию пера в
свойстве PenPos. Позиция пера нужна только для рисования . Для рисования геометрических
фигур и вывода текста на канву вы вызываете необходимые координаты при вызове
соответствующих методов. установки нужной позиции пера вызывайте метод MoveTo:
Imagel .Canvas .MoveTo (0, 0);
Данный код установит перо в левый верхний угол канвы.
Примечание
Черчение линий с помощью метода LineTo также устанавливает текущую позицию пера,
равную конечной точке линии.
Использование кисти
Свойство Brush канвы позволяет вам указывать, каким образом будет производиться
заполнение областей и геометрических фигур.
Кисть имеет три свойства:
Color - цвет кисти;
Style - стиль кисти;
Bitmap - графический образ, который будет применяться для заполнения.
Значения этих свойств определяют способ, которым будут заполняться геометрические
фигуры и области канвы. По умолчанию значения установлены следующим образом:
цвет кисти - белый, стиль - сплошной, без графического образа для заполнения.
Рассмотрим эти свойства более подробно.
Цвет кисти
Цвет кисти определяет, какой цвет будет использоваться для заполнения внутренних
областей геометрических фигур и областей канвы. Для смены цвета кисти достаточно
присвоить необходимое значение свойству color кисти.
Цвет кисти используется как фоновый цвет текста и линий. В листинге 13.6 мы
устанавливаем синий цвет кисти.
Листинг 13.6. Установка цвета кисти
procedure TForml.ButtonlClick(Sender: TObject);
begin
Canvas.Brush.Color := clBlue;
end;
Стиль кисти
Стиль кисти определяет, каким образом будет заполняться область на канве или
геометрическая фигура. Это позволяет программисту комбинировать цвет кисти с
уже имеющимися цветами канвы.
Для смены стиля кисти достаточно напрямую установить свойство style в одно из
следующих значений:
bsSolid, bsClear, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal. bsCross,
bsDiagCross, bsDensel, bsDense2, bsDenseS, bsDense4, bsDensc5. bsDense6 ИЛИ
bsDense7.
Пример, приведенный в листинге 13.7, показывает, как можно установить стиль
кисти. Здесь происходит последовательная установка нескольких значений стиля
кисти.
Листинг 13.7. Установка стиля кисти
procedure TForml.ButtonlClick(Sender: TObject);
begin
with Canvas.Brush do
begin
Style:= bsSolid
Style:= bsClear
Style:= bsHorizontal
Style:= bsVertical
Style:= bsFDiagonal
Style:= bsBDiagonal
Style:= bsCross
Style:= bsDiagCross;
end;
Установка значения свойства Bitmap
Свойство Bitmap кисти позволяет указать графический образ, который будет пользоваться
для заполнения областей и геометрических фигур, расположенных на канве.
Нижеприведенный пример (листинг 13.8) показывает, как можно загрузить графический
образ из файла и присвоить его свойству Bitmap кисти канвы формы Form1.
Листинг 13.8. Загрузка графического образа из файла
var
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
Bitmap.LoadFromFile('MyBitmap.bmp');
Forml.Canvas.Brush.Bitmap := Bitmap;
Forml.Canvas.FillRect(Rect(0,0,100,100));
finally
Forml .Canvas. Brush. Bitmap := nil;
Bitmap. Free;
end;
end;
Примечание
Кисть не является владельцем графического образа, который присвоен свойству
Bitmap кисти. Вы должны самостоятельно уничтожать объект графического образа
после использования.
Использование методов объекта Canvas
В этой части главы мы рассмотрим методы объекта canvas, которые позволяют рисовать
простые графические объекты.
Рисование линий и ломаных
Объект канвы позволяет чертить прямые линии и ломаные линии.
Прямая линия - это точки отрезка прямой, проходящей через две заданные точки.
Ломаная линия - это несколько прямых линий, которые соединены между собой конечными
точками.
Для рисования прямой линии на канве вы можете использовать метод LineTo. Данный
метод чертит линию из текущей позиции пера в точку, указанную вами, и делает
конечную точку линии текущей позицией пера.
Приведенный ниже пример (листинг 13.9) чертит диагональные линии формы каждый
раз, когда форма перерисовывается (обновляется). Для этого мы записываем код
в обработчик события формы OnPaint.
Листинг 13.9. Пример рисования прямых линий
procedure TForml . FormPaint (Sender : TObject) ;
begin
with Canvas do
begin
MoveTo ( 0 , 0 ) ;
LineTo (ClientWidth, ClientHeight) ;
MoveTo (0, ClientHeight);
LineTo (ClientWidth,
end;
end;
Результат выполнения примера изображен на рис. 13.3.
Рис. 13.3. Форма с диагональными линиями
Для рисования ломаных линий можно воспользоваться специальным методом Polyline.
Параметрами данного метода являются элементы массива Points. Приведем пример рисования ломаной линии:
Forml.Canvas.Polyline([Point(0, 0), Point(12,14), Point(50,30),
Point (130, 120), Point(210,132)]);
Данный пример чертит ломаную линию, состоящую из прямых линий рис. 13.4).
Рис. 13.4. Ломаная линия
Рисование линий с помощью метода Polyline аналогично рисованию нескольких линий с помощью методов MoveTo и ЫпеТо. Ниже приведен пример (листинг 13.10), который строит такую же ломаную, как и предыдущий пример.
Листинг 13.10. Построение ломаной линии
with Canvas do begin
MoveTo (О, О);
LineTo(12, 14);
LineTo(50, 30);
LineTo(130, 120);
LineTo(210,132);
end;
Примечание
Если вы рисуете ломаные линии, то используйте метод Polyline, т. к. он выполняется
значительно быстрее, чем вызов нескольких методов LineTo.
Рисование геометрических фигур
Для рисования эллипсов, окружностей или прямоугольников вы можете использовать
Методы Ellipse ИЛИ Rectangle соответственно.
Приведем пример (листинг 13.11), в котором рисуется прямоугольник, занимающий
левую верхнюю четвертую часть формы, а затем в этот прямоугольник вписывается
эллипс (рис. 13.5).
Листинг 13.11. Прямоугольник со вписанным эллипсом
procedure TForml.FormPaint(Sender: TObject);
begin
Canvas.Rectangle(0, 0, ClientWidth div 2, ClientHeight div 2);
Canvas.Ellipse(0, 0, ClientWidth div 2, ClientHeight div 2);
end;
Для того чтобы нарисовать на канве прямоугольник со скругленными углами, вы
можете воспользоваться методом RoundRect.
Первые четыре параметра определяют координаты главной диагонали прямоугольника,
остальные два показывают, как скругляются его углы.
Рис. 13.5. Эллипс, вписанный в прямоугольник
Нижеприведенный пример (листинг 13.12) рисует прямоугольник со скругленными углами, которые скруглены по шаблону окружности, с диаметром 10 точек (рис. 13.6).
Листинг 13.12. Прямоугольник со скругленными углами
rocedure TForml.FormPaint (Sender: TObject);
begin
Canvas.RoundRect(0, 0, ClientWidth div 2, ClientHeight div 2, 10, 10);
end;
Рис. 13.6. Прямоугольник со скругленными углами
Для рисования многоугольников с любым количеством углов и сторон вы можете использовать
метод Polygon. Метод Polygon содержит в качестве параметров массив точек Points,
которые определяют координаты вершин многоугольника. После рисования текущим
пером линий многоугольника метод Polygon закрашивает текущим цветом кисти область
внутри многоугольника.
Примечание
Данный метод аналогичен методу Polyline, только первая и последняя точки ломаной
линии соединяются.
Создание приложения наподобие графического
редактора
В графическом редакторе обычно присутствует панель инструментов, на которой
располагаются кнопки. Каждая из кнопок позволяет рисовать различные фигуры (линии,
точки, геометрические фигуры и многое другое). Такие кнопки удобнее всего создавать
с помощью компонента CLX TSpeedButton.
Приложение должно узнавать, какую кнопку нажал пользователь, и переходить в
режим рисования данного объекта. Для этого вы можете сопоставить с каждым типом
фигуры целое число, но в этом случае вам придется помнить, что обозначает каждое
число. Если вы позволите пользователю создавать множество фигур, то это будет
довольно трудно.
Однако все это можно значительно упростить, если вы сопоставите имена-константы
каждому числу. Кроме того, вы можете прибегнуть к применению перечисляемого
типа.
Для объявления перечисляемого типа используйте слово Туре. Например, нижеприведенный
код объявляет перечисляемый тип, содержащий все типы фигур, которые приложение
позволяет рисовать пользователю:
type
TDrawingTool = (dtLine, dtRectangle, dtEllipse, dtRoundRect) ;
По соглашению, идентификатор типа (в нашем случае - это TDrawingTool) начинается
с буквы т, а группа перечисляемых констант начинается с двухбуквенного префикса
(в нашем случае - букв dt).
Это объявление эквивалентно объявлению группы констант:
const
dtLine = 0;
dtRectangle = 1;
dtEllipse = 2;
dtRoundRect = 3;
Главное отличие объявления группы констант и перечисляемого типа заключается
в том, что в случае объявления типа вы присваиваете константам не только значение,
но и новый тип, который позволяет языку Object Pascal проверять соответствие
типов и предотвращать возможные ошибки. Переменная, тип TDrawingToo1, может
иметь значение только из перечисленных (dtLine ... dtRoundRect). Любая попытка
присвоения переменной других чисел (не входящих в диапазон от 0 до 3) вызовет
ошибку компиляции.
Код, приведенный в листинге 13.13, объявляет все необходимые константы будущего приложения, позволяющего пользователю выбирать инструмент для рисования.
Листинг 13.13. Объявление типа и переменных
type
TDrawingTool = (dtLine, dtRectangle, dtEllipse, dtRoundRect);
TForml = class(TForm)
… { объявление методов }
public
Drawing: Boolean;
Origin, MovePt: TPoint;
DrawingTool: TDrawingTool; { переменная, которая будет содержать текущий
инструмент }
end;
Расположим на панели инструментов четыре кнопки speedButton, каждая из которых будет означать линию, прямоугольник, эллипс или прямоугольник со скругленными углами. Теперь нужно для каждой кнопки написать обработчик события onclick, в котором необходимо присвоить соответствующее значение переменной DrawingTool (листинг 13.14).
Листинг 13.14. Обработчики нажатия кнопок
procedure TForm1.LineButtonClick(Sender: TObject); { Кнопка линии }
begin
DrawingTool := dtLine;
end;
procedure TForml.RectangleButtonClick(Sender: TObject); { Кнопка
прямоугольника }
begin
DrawingTool := dtRectangle;
end;
procedure TForml.EllipseButtonClick(Sender: TObject); { Кнопка эллипса }
begin
DrawingTool := dtEllipse;
end;
procedure TForml.RoundedRectButtonClick(Sender: TObject); { Кнопка
прямоугольника со скругленными углами }
begin
DrawingTool := dtRoundRect;
end;
Теперь нам осталось написать лишь обработчики событий движения мыши (onMouseMove) и отпускания левой кнопки мыши (onMouseup). Эти обработчики представлены в листингах 13.15 и 13.16.
Листинг 13.15. Обработчик события OnMouseup
procedure TForml.FormMouseUp(Sender: TObject; Button TMouseButton; Shift:
TShiftState;
X,Y: Integer);
begin
case DrawingTool of
dtLine:
begin
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y)
end;
dtRectangle: Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
dtEllipse: Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
dtRoundRect: Canvas.RoundRect(Origin.X, Origin.Y, X, Y, (Origin.X - X) div 2,
(Origin.Y - Y) div 2) ;
end;
Drawing := False;
end;
Листинг 13.16. Обработчик события OnMouseMove
procedure TForml.ForniMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
begin
Canvas.Pen.Mode := pmNotXor;
case DrawingTool of
dtLine:
begin
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(MovePt.X, MovePt.Y);
Canvas.MoveTo(Origin.X, Origin.Y);
Canvas.LineTo(X, Y);
end;
dtRectangle:
begin
Canvas.Rectangle(Origin.X, Origin.Y, MovePt.X, MovePt.Y);
Canvas.Rectangle(Origin.X, Origin.Y, X, Y);
end;
dtEllipse:
begin
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
Canvas.Ellipse(Origin.X, Origin.Y, X, Y);
end;
dtRoundRect:
begin
Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
(Origin.X - X) div 2, (Origin.Y - Y) div 2);
Canvas.RoundRect(Origin.X, Origin.Y, X, Y,
(Origin.X - X) div 2, (Origin.Y - Y) div 2);
end;
end;
MovePt := Point(X, Y);
end;
Canvas.Pen.Mode := pmCopy;
end;
Другие методы работы c графикой в Kylix
Вообще, вам не требуется наличие специальных компонентов для работы с графическими
возможностями Kylix. Вы можете создавать, рисовать, сохранять и уничтожать графические
объекты без отображения графики на экране. В качестве графического объекта могут
выступать bmp-файлы, рисунки, пиктограммы и другие объекты, включая сжатые jpeg-файлы.
В большинстве случаев приложение редко рисует напрямую на форме. Обычно сначала
создается графический образ, а затем он отображается с помощью компонента CLX
image.
Как только вы разместили рисунок в компонент image, вы можете достаточно легко
его сохранять, загружать и копировать в буфер обмена.
Примечание
Если вы рисуете не на экране, а, например, на канве объекта TBitmap, изображение
не будет отображаться на экране до тех пор, пока не будет произведено копирование
рисунка из канвы объекта TBitmap в канву визуального объекта. Более того, необходимо
сделать перерисовку визуального объекта после копирования, например с помощью
вызова метода Refresh для данного визуального объекта. Если вы рисуете напрямую
в канве визуального объекта, таких проблем не возникает.
Иногда картинка превышает размер формы. Для просмотра таких больших изображений можно разместить на форме компонент TScroiiBox и помещать изображение внутрь этого компонента.
Работа с компонентом Image
Компонент image представляет собой контейнер, который может содержать и отображать
графический объект.
Вы можете расположить данный компонент в любом месте формы, после чего с помощью
инспектора объектов в свойстве Picture указать графический объект, который будет
содержаться в компоненте image. Кроме того, данное свойство можно изменять и
в процессе выполнения приложения, изменяя свойство Picture.
Если вы хотите, чтобы приложение сразу после запуска создавало чистую заготовку
для изображения, вам необходимо выполнить следующие шаги:
1. Создать заготовку обработчика события oncreate для формы, содержащей компонент
Image.
2. Создать объект Bitmap и присвоить его свойству Picture.Graphic компонента
Image.
В нижеприведенном примере (листинг 13.17) главная форма приложения
Form1 содержит компонент типа TImage, который имеет имя (свойство Name) Image.
Код размещен в обработчике события OnCreate формы Form1.
Листинг 13.17. Создание объекта Bitmap
procedure TForml.FormCreate(Sender: TObject);
var
Bitmap: TBitmap; (временная переменная для хранения графического образа;
begin
Bitmap := TBitmap.Create,( создаем графический объект }
Bitmap.Width := 200; { устанавливаем начальную ширину }
Bitmap.Height := 200; { и начальную высоту объекта Bitmap }
Image.Picture.Graphic := Bitmap; { присваиваем созданный графический
объект компоненту Image }
Bitmap.Free; { Нам больше не нужен графический объект, поэтому
уничтожаем его }
end;
Если вы записали вышеприведенный код в обработчике события OnCreate формы Form1
и запустили приложение, то вы сможете увидеть в клиентской части формы белый
квадрат, представляющий собой как бы заготовку для изображения. Если вы уменьшите
окно таким образом, чтобы изображение (помещалось в нем, автоматически появятся
полосы прокрутки.
данной заготовке можно осуществлять любые графические операции. Для этого следует
воспользоваться канвой компонента image.
Для работы с линиями объекта Bitmap имеется свойство ScanLine, которое позволяет
получать информацию о цветах пикселов одной линии в виде массива RGB.
Пример, приведенный в листинге 13.18, показывает, как можно использовать свойство
ScanLine для одновременного получения пикселов одной линии.
Листинг 13.18. Прямая работа с Bitmap
procedure TForml.ButtonlClick(Sender: TObject);
// Данный пример показывает, как можно рисовать напрямую в Bitmap
var
х,у : integer;
Bitmap : TBitmap;
Р : PByteArray;
begin
Bitmap := TBitmap.create;
try
if OpenDialogl.Execute then
begin
Bitmap.LoadFromFile(OpenDialogl.FileName);
for у := 0 to Bitmap.height -1 do
begin
P := Bitmap.ScanLine[y] ;
for x := 0 to Bitmap.width -1 do
Р[х] := у;
end;
end;
canvas.draw(0,0,Bitmap);
finally
Bitmap.free;
end;
end;
Загрузка и сохранение графических файлов
Графические образы, которые используются в приложении, иногда требуется сохранить
для дальнейшего использования. Компонент Image позволяет достаточно просто и
эффективно загружать графику из файла и сохранять в файл.
Компоненты CLX, которые можно использовать для загрузки, сохранения и других
действий с графикой, поддерживают несколько графических форматов: bmp, png,
xpms, ico и др.
Загрузка графического образа из файла
Если ваше приложение позволяет изменять готовые изображения или создавать новые,
необходимо обеспечить возможность загрузки графики из файла. Для этого можно
воспользоваться специальным методом LoadFromFile, который имеется у всех компонентов
CLX, способных работать с графикой.
Нижеприведенный пример (листинг 13.19) вызывает диалоговое окно открытия файла
и получает из него имя файла, содержащего графический образ. Затем происходит
загрузка этого образа в компонент Image1.
Листинг 13.19. Загрузка графики из файла
procedure TForml.OpenlClick(Sender: TObject);
var
CurrentFile: String;
begin
if OpenDialogl.Execute then
begin
CurrentFile := OpenDialogl.FileName;
Imagei.Picture.LoadFromFile(CurrentFile);
end;
end;
Для успешной работы данного примера вам необходимо разместить на форме Form1
компонент openDialog1, который вы найдете на вкладке Dialogs цитры компонентов
Kylix, а также меню Menu1 с пунктом Open, и записать, в обработчике события
onclick для данного пункта меню этот код.
Сохранение графического образа в файл
Для сохранения графического образа в файл вызовите метод SaveToFiie. Данный
метод требует, чтобы вы передали в качестве параметра имя файла, в который будет
произведено сохранение графического образа.
Нижеприведенный пример (листинг 13.20) содержит две процедуры для двух пунктов
меню Save и SaveAs. Если вызывается пункт меню Save, то пронзятся проверка,
был ли уже создан файл для данного графического образа, если он был создан,
то образ сохраняется. Если такой файл не был создан, вызывается метод SaveAs,
который открывает окно SaveDialogl и запрашивает имя файла для данного графического
образа, после чего управление передается методу Save.
Таким образом, для успешной работы данного примера вам необходимо положить на
форме Forml меню с двумя пунктами Save и SaveAs и компонент SaveDiaiog с вкладки
Dialogs палитры компонентов Kylix. Кроме того, разместите на форме компонент
Image1 для хранения графического образа, после чего запишите в обработчик событий
нажатия пунктов меню код, приведенный в листинге 13.20.
Листинг 13.20. Сохранение графики в файл
var
Forml: TForml;
CurrentFile:String;
plementation
{$R *.XFM}
rocedure TForml.SavelClick(Sender: TObject);
begin Ef CurrentFile <> '' then
Imagel.Picture.SaveToFiie(CurrentFile) { файл уже существует }
else SaveAslClick(Sender);{ иначе нужно ввести имя файла }
end;
procedure TForml.SaveAslClick(Sender: TObject);
begin
if SaveDialogl.Execute then ( Получить имя файла }
begin
CurrentFile := SaveDialogl.FileName; { сохранить файл с именем,
заданным пользователем }
SavelClick(Sender); { вызов метода сохранения файла }
end;
end;
Работа с буфером обмена
Вы можете использовать системный буфер обмена для копирования и вставки графики
внутрь вашего приложения, а также для переноса графики из вашего приложения
в другие и из других приложений в ваше. Для этого используется специальный объект
Kylix clipboard. Этот объект позволяет оперировать различным типом информации,
включая графику и текст.
Прежде чем вы сможете воспользоваться данным объектом, необходимо добавить в
блок uses модуля, в котором будет использоваться буфер обмена.
имя модуля OClipbrd:
uses
SysUtils, Types, Classes, Variants, QGraphics, QControls, QForms, QDia-logs,
QStdCtrls, OClipbrd;
Данный модуль позволит обращаться к объекту clipboard.
Копирование графики в буфер обмена
Для копирования графической информации в буфер обмена нужно ассоциировать графический
объект с объектом clipboard. Это можно сделать с помощью метода Assign.
Код, приведенный в листинге 13.21, показывает, как можно скопировать графический
образ, содержащийся в компоненте типа Timage, имеющем имя image, в буфер обмена,
выбрав пункт меню Edit/Copy формы Form1.
Листинг 13.21. Копирование графики в буфер обмена
procedure TForml.CopylClick(Sender: TObject);
begin
Clipboard.Assign(Image.Picture)
end.
Вырезание графики в буфер обмена
Вырезание графики в буфер обмена похоже на копирование. Отличие заключается
в том, что после копирования картинка, содержащаяся в источнике, уничтожается.
Для реализации данной операции нужно выполнить два последовательных шага:
Скопировать данные в буфер обмена.
Уничтожить оригинальные данные.
В листинге 13.22 показано, как можно осуществить операцию вырезания картинки
в буфер обмена. Сначала изображение копируется в буфер обмена, затем место,
откуда взято изображение, закрашивается белым цветом с помощью установки режима
копирования cmWhiteness.
Листинг 13.22. Вырезание графики в буфер обмена
rocedure TForml.CutlClick(Sender: TObject);
var
ARect: TRect;
begin
CopylClick(Sender); { копирование картинки в буфер обмена }
with Image.Canvas do
begin
CopyMode := cmWhiteness;{установить режим копирования в белый цвет)
ARect := Rect(0, 0, Image.Width, Image.Height); (получение квадрата
копирования}
CopyRect(ARect, Image.Canvas, ARect); { наложение белого
прямоугольника }
CopyMode := cmSrcCopy; { восстановление нормального режима
копирования }
end;
end;
Вставка графики из буфера обмена
Если в буфере обмена содержится какая-либо графическая информация, вы можете
вставить ее в любой графический компонент Kylix, включая канву формы.
Для вставки графики из буфера обмена нужно выполнить следующие шаги:
Вызвать метод provides объекта clipboard для того, чтобы убедиться, что буфер
обмена содержит графическую информацию. Метод Provides представляет собой функцию,
которая возвращает булевы значения. Если возвращаемое значение True, то буфер
обмена содержит данные именно такого типа, которые указаны в параметре метода
Provides.
Указать объект, в который будет произведено копирование с помощью метода Assign.
Нижеприведенный код (листинг 13.23) показывает, как можно копировать картинку
из буфера обмена в компонент Image с помощью пункта меню Edit/Paste.
Листинг 13.23. Копирование графики из буфера обмена
procedure TForml.PasteButtonClick(Sender: TObject);
var
Bitmap: TBitmap;
begin
if Clipboard.Provides(SDelphiBitmap) then { в буфере обмена
изображение? )
begin
Imagel.Picture.Bitmap.Assign(Clipboard);
end;
end;
Изображение, находящееся в буфере обмена, может быть скопировано из любого приложения.
Работа с мышью
Ваше приложение может реагировать на действия пользователя, которые он выполняет
с помощью мыши. В этой части главы мы расскажем, как можно обрабатывать события
мыши.
Событие мыши происходит в тот момент, когда пользователь двигает мышью или нажимает
кнопки мыши. CLX поддерживает три события мыши, которые перечислены в табл.
13.4.
Таблица 13.4. События мыши
Событие мыши | Описание |
OnMouseDown | Происходит, когда пользователь нажимает кнопку мыши в тот момент, когда указатель мыши расположен над компонентом |
OnMouseMove | Происходит, когда пользователь двигает мышью в тот момент, когда указатель мыши расположен над компонентом |
OnMouseUp | Происходит, когда пользователь отпускает кнопку мыши в тот момент, когда указатель мыши расположен над компонентом |
Когда приложение фиксирует, что произошло событие мыши, оно вызывает обработчик
данного события, если он был вами написан. В обработчик события передается четыре
параметра, которые перечислены в табл. 13.5.
Таблица 13.5. Параметры событий мыши
Параметр | Значение |
Sender | Имя объекта, над которым произошло событие мыши |
Button | Указывает, какая из трех кнопок мыши нажата. Может принимать значения: mbLef t - левая; mbMiddle - средняя и mbRight - правая |
Shif t | Показывает состояние кнопок <Alt>, <Ctrl> и <Shift> во время наступления события мыши |
X, Y | Координаты клиентской части компонента, над которым произошло событие мыши |
Обработка события OnMouseDown
Всякий раз, когда пользователь нажимает любую кнопку мыши, происходит событие
OnMouseDown. Для использования этого события вам нужно написать обработчик события
у желаемого компонента. Например, если вы хотите обработать событие OnMouseDown,
когда пользователь нажмет кнопку мыши над формой Form1, нужно в окне инспектора
объектов на вкладке Events найги событие OnMouseDown для формы Form1 и дважды
щелкнуть на нем.
В результате Kylix создаст заготовку обработчика события нажатия кнопки мыши
для формы (листинг 13.24).
Листинг 13.24. Заготовка обработчика события OnMouseDown
procedure TForml.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
end;
Приведем пример обработки данного события (листинг 13.25). Запустите названную
программу. При каждом щелчке в области формы вы увидите надпись "Здесь!"
на месте, где вы щелкнули мышью (рис. 13.7).
Листинг 13.25. Пример обработки события onMouseDown
procedure TForml.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.TextOut(X, Y, 'Здесь!'); ( печатает текст на канве }
end;
Рис. 13.7. Обработка события OnMouseDown
Еще один пример (листинг 13.26) устанавливает текущую позицию пера в координаты, в которых пользователь щелкнул мышью.
Листинг 13.26. Установка позиции пера в координатах, указанных пользователем
procedure TForml.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.MoveTo(X, Y); { установка позиции пера )
end;
Обработка события OnMouseUp
Событие OnMouseUp происходит всякий раз, когда пользователь отпускает нажатую
кнопку мыши. Комбинация данного события с событием OnMouseDown позволит вам,
например, рисовать линии. Когда пользователь нажал кнопку мыши, установить начальную
точку линии, а когда отпустил - конечную.
Для обработки события OnMouseup нужно, как и для обработки OnMouseDown, создать
программу-обработчик.
Приведем пример (листинг 13.27), который рисует линию из точки, в которой произошло
нажатие кнопки мыши, в точку, в которой пользователь отпустил кнопку мыши (рис.
13.8).
Листинг 13.27. Пример рисования линии
procedure TForml.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.MoveTo(X, Y); { установка позиции пера }
end;
procedure TForml.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); begin
Canvas.LineTo(X, Y); { рисуем линию из координат PenPos в (X, Y) }
end;
Пользователь не будет видеть линию, пока не отпустит кнопку мыши.
Рис. 13.8. Пример рисования линий
Обработка события OnMouseMove
Данное событие происходит периодически во время перемещения мыши. Для обработки
этого события нужно написать программу-обработчик.
Нижеприведенный пример (листинг 13.28) показывает, как можно использовать событие
onMouseMove для немедленного рисования линий (рис. 13.9).
Листинг 13.28. Пример обработки события OnMouseMove
procedure TForml.FormMouseMove(Sender: TObject;Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Canvas.LineTo(X, Y); ( рисует линию в текущую позицию }
end;
Рис. 13.9. Обработка события OnMouseMove
Создание простой игровой программы
Теперь вы можете создавать графические приложения практически любой сложности.
Рассмотрим пример создания игры "Крестики-нолики" на поле 10x10 клеток.
Мы не будем касаться вопросов создания искусственного интеллекта, предоставив
это читателю. Рассмотрим лишь вопрос создания графической оболочки игры.
Итак, пусть программа работает в качестве игрового поля, на котором игроки смогут
последовательно ставить крестики и нолики. Создадим форму-заготовку (рис. 13.10),
на которую поместим две кнопки Button 1 и Button2. Первая будет готовить игровое
поле, а вторая позволит выйти из программы.
Рис. 13.10 Форма-заготовка для игровой программы
Теперь напишем код для этих двух кнопок. Ниже приведен полный код модуля unit1
с соответствующими пояснениями и комментариями (листинг 13.29). Думаем, что
читатель во всем разберется без особых проблем.
Листинг 13.29. Листинг игровой программы "Крестики-нолики"
unit Unitl;
interface
uses
SysUtils, Types, Classes, Variants, QGraphics, QControls, QForms, QDialogs,
QStdCtrls;
type
Forml = class(TForm)
Buttonl: TButton;
Button2: TButton;
procedure ButtonlClick(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Forml: TForml;
f:boolean; // Флаг, указывающий, что ставится: крестик
// или нолик
implementation
{$R *.xfm}
procedure TForml.ButtonlClick(Sender: TObject);
var
i:integer;
begin
// Рисуем прямоугольную область, закрашенную белым цветом Canvas.FillRectfrect(10,10,210,210))
;
i:=10;
//Рисуем горизонтальные линии клеточек сетки 10x10
while i<=210 do
begin
Canvas.MoveTo (10,i);
Canvas.LineTo (210,i);
i:=i+20;
end;
i:=10;
// Рисуем вертикальные линии клеточек сетки 10x10
while i<=210 do
begin
Canvas.MoveTo(i,10);
Canvas.LineTo(1,210);
i:=i+20;
end;
end;
procedure TForml.Button2Click(Sender: TObject);
begin
Forml.Close; // Закрытие приложения
end;
procedure TForml.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
x1,yl:integer;
begin
// Проверяем, в какой области формы щелкнул мышкой пользователь
//если в области сетки, то
if(х>10) and (x<210) and (y>10) and (y<210) then
begin
//Вычисляем координаты левого верхнего угла клеточки,
//внутри которой щелкнул пользователь
xl:=trunc((х-10)/20)*20+10;
yl:=trunc((у-10)/20)*20+10;
//Проверяем, что ставить: крестик или нолик
f:=not(f) ;
if f=true then
begin
//Если нолик, то canvas.Pen.Color:=clRed;
canvas.Pen.Width:=2 ;
canvas.Ellipse(xl,yl,xl+20,yl+20);
end else
begin
//Иначе - крестик
canvas.Pen.Color:=clBlue;
canvas.Pen.Width:=2 ;
canvas.MoveTo(xl,yl);
canvas.LineTo(xl+20,yl+20);
canvas. MoveTo (xl+20, yl) ;
canvas.LineTo(xl, yl+20) ;
end;
end;
end;
end.
Теперь запустим программу. Нажмите кнопку Начать игру, и программа нарисует белый прямоугольник и сетку 10x10 (рис. 13.11).
Рис. 13.11. Поле для игры
Теперь два игрока могут последовательно щелкать левой кнопкой мыши в области
сетки, в результате чего будут по очереди появляться красные нолики и синие
крестики (рис. 13.12).
Рис. 13.12. Программа в процессе работы
Итак, мы изучили основные графические возможности, которые предоставляет среда
Kylix. Теперь вы можете создавать любые программы, использующие графику.