Программирование с C++ Builder

         

Builder позволяет программисту разрабатывать программы,



C++ Builder позволяет программисту разрабатывать программы, которые работают с графикой. В этой главе рассказывается, что надо сделать, чтобы на поверхности формы появилась картинка, сформированная из графических примитивов, или иллюстрация, созданная в графическом редакторе или полученная в результате сканирования фотографии.
Содержание

Холст



Программа может вывести графику на поверхность формы (или компонента image), которой соответствует свойство canvas (Canvas — холст для рисования). Для того чтобы на поверхности формы или компонента image появилась линия, окружность, прямоугольник или другой графический элемент (примитив), необходимо к свойству Canvas применить соответствующий метод (табл. 3.1).

Например, оператор Forml->Canvas->Rectangle(10,10,50, 50); рисует на поверхности формы прямоугольник.

Таблица 3.1. Методы вычерчивания графических примитивов

Метод
Действие
LineTo(x,y)
Рисует линию из текущей точки в точку с указанными координатами
Rectangle (x1,y1,x2, y2)
Рисует прямоугольник, x1, y1 и х2, у2 — координаты левого верхнего и правого нижнего углов прямоугольника. Цвет границы и внутренней области прямоугольника могут быть разными
FillRect (x1,y1,x2,y2)
Рисует закрашенный прямоугольник, x1, y1, х2, у2 — определяют координаты диагональных углов
FrameRect(x1,y1,x2,y2)
Рисует контур прямоугольника, x1, y1, х2, у2 — определяют координаты диагональных углов
RounRect (x1,y1,x2,y2,x3,y3)
Рисует прямоугольник со скругленными углами
Ellipse (x1,y1,x2,y2)
Рисует эллипс или окружность (круг), x1, y1, х2, у2 — координаты прямоугольника, внутри которого вычерчивается эллипс или, если прямоугольник является квадратом, окружность
Polyline (points, n)
Рисует ломаную линию, points— массив типа TPoint. Каждый элемент массива представляет собой запись, поля х и у которой содержат координаты точки перегиба ломаной; л — количество звеньев ломаной. Метод Polyline вычерчивает ломаную линию, последовательно соединяя прямыми отрезками точки, координаты которых находятся в массиве: первую со второй, вторую с третьей, третью с четвертой и т. д.


Методы вывода графических примитивов рассматривают свойство canvas как некоторый абстрактный холст, на котором они могут рисовать (Canvas переводится как "поверхность", "холст для рисования"). Холст состоит из отдельных точек — пикселов. Положение пиксела на поверхности холста характеризуется горизонтальной (X) и вертикальной (Y) координатами. Координаты возрастают сверху вниз и слева направо (рис. 3.1). Левый верхний пиксел поверхности формы (клиентской области) имеет координаты (0, 0), правый нижний — (ciientwidth, clientHeight). Доступ к отдельному пикселу осуществляется через свойство Pixels, представляющее собой двумерный массив, элементы которого содержат информацию о цвете точек холста.

Следует обратить внимание на важный момент. Изображение, сформированное на поверхности формы, может быть испорчено, например, в результате полного или частичного перекрытия окна программы другим окном. Поэтому программист должен позаботиться о том, чтобы в момент появления окна программа перерисовала испорченное изображение. К счастью, операционная система Windows информирует программу о необходимости перерисовки окна, посылая ей соответствующее сообщение, в результате чего возникает событие OnPaint. Событие OnPaint возникает и в момент запуска программы, когда окно появляется на экране в первый раз. Таким образом, инструкции, обеспечивающие вывод графики на поверхность формы, надо поместить в функцию обработки события onPaint.



Рис. 3.1. Координаты точек поверхности формы (холста)

Карандаш и кисть



Методы вычерчивания графических примитивов обеспечивают только вычерчивание. Вид графического элемента определяют свойства Реn(карандаш) и Brush (кисть) той поверхности (Canvas), на которой рисует метод.

Карандаш и кисть, являясь свойствами объекта Canvas, в свою очередь представляют собой объекты Реn и Brush. Свойства объекта Реп (табл. 3.2) задают цвет, толщину и тип линии или границы геометрической фигуры. Свойства объекта Brush (табл. 3.3) задают цвет и способ закраски области внутри прямоугольника, круга, сектора или замкнутого контура.

Таблица 3.2. Свойства объекта Реn (карандаш)

Свойство
Определяет
Color
Цвет линии
Width
Толщину линии (задается в пикселах)
Style
Вид линии (psSolid— сплошная; psDash— пунктирная, длинные штрихи; psDot — пунктирная, короткие штрихи; psDashDot — пунктирная, чередование длинного и короткого штрихов; psDashDotDot — пунктирная, чередование одного длинного и двух коротких штрихов; psClear — линия не отображается (используется, если не надо изображать границу области — например, прямоугольника)


Таблица 3.3. Свойства объекта Brush (кисть)

Свойство
Определяет
Color
Цвет закрашивания замкнутой области
Style
Стиль заполнения области (bsSolid — сплошная заливка. Штриховка: bsHorizontal — горизонтальная; bsVertical — вертикальная; bsFDiagonal — диагональная с наклоном линий вперед; bsBDiagonal — диагональная с наклоном линий назад; bsCross — в клетку; bsDiagCross — диагональная клетка


Ниже приведена функция обработки события onPain, которая рисует на поверхности формы олимпийский флаг.

void__fastcall TForml::FormPaint(TObject *Sender)
{
// полотнище флага
Canvas->Pen->Width = 1;
Canvas->Pen->Color = clBlack;
Canvas->Brush->Color = clCream;
Canvas->Rectangle(30,30,150,150);
Canvas->Pen->Width =2; // ширина колец
Canvas->Brush->Style = bsClear; // чтобы круг, нарисованный
// методом Ellipse, не был закрашен
// рисуем кольца
Canvas->Pen->Color = clBlue; Canvas->Ellipse(40,40,80,80) ;
Canvas->Pen->Color = clBlack; Canvas->Ellipse(70,40,110,80);
Canvas->Pen->Color = clRed; Canvas->Ellipse(100,40,140,80);
Canvas->Pen->Color = clYellow; Canvas->Ellipse(55,65,95,105);
Canvas->Pen->Color = clGreen; Canvas->Ellipse(85,65,125,105);
}

Графические примитивы



Любая картинка, чертеж или схема могут рассматриваться как совокупность графических примитивов: точек, линий, окружностей, дуг и др. Таким образом, для того чтобы на экране появилась нужная картинка, программа должна обеспечить вычерчивание (вывод) графических элементов — примитивов, составляющих эту картинку.

Вычерчивание графических примитивов на поверхности (формы или компонента image — области вывода иллюстрации) осуществляется применением соответствующих методов к свойству canvas этой поверхности.


Линия



Вычерчивание прямой линии выполняет метод LineTo. Метод рисует линию из той точки, в которой в данный момент находится карандаш (эта точка называется текущей позицией карандаша или просто "текущей"), в точку, координаты которой указаны в инструкции вызова метода. Например, оператор

Canvas->LineTo(100,200)

рисует линию в точку с координатами (100, 200), после чего текущей становится точка с координатами (100, 200).

Начальную точку линии можно задать, переместив карандаш в нужную точку графической поверхности. Сделать это можно при помощи метода MoveTo, указав в качестве параметров координаты точки начала линии. Например, операторы
Canvas->MoveTo(10,10); // установить карандаш в точку (10,10)
Canvas->LineTo(50,10); // линия из точки (10,10)в точку (50,10)

рисуют горизонтальную линию из точки (10, 10) в точку (50, 10).

Используя свойство текущей точки, можно нарисовать ломаную линию. Например, операторы
Canvas->MoveTo(10,10) ;
Canvas->LineTo(50,10) ;
Canvas->LineTo(10,20) ;
Canvas->LineTo(50,20) ;

рисуют линию, похожую на букву Z.


Ломаная линия



Метод Polyline вычерчивает ломаную линию. В качестве параметров методу передается массив типа TPoint, содержащий координаты узловых точек линии, и количество звеньев линии. Метод Polyline вычерчивает ломаную линию, последовательно соединяя точки, координаты которых находятся в массиве: первую со второй, вторую с третьей, третью с четвертой и т. д.

Например, приведенный ниже фрагмент кода рисует ломаную линию, состоящую из трех звеньев.

TPoint p[4]; // координаты начала, конца и точек перегиба
# задать координаты точек ломаной
р[0].х = 100; р[0].у = 100; // начало
р[1].х = 100; р[1].у = 150; // точка перегиба
р[2].х = 150; р[2].у = 150; // точка перегиба
р[3].х = 150; р[3].у = 100; // конец
Canvas->Polyline(p,3}; // ломаная из трех звеньев

Метод Polyline можно использовать для вычерчивания замкнутых контуров. Для этого надо, чтобы первый и последний элементы массива содержали координаты одной и той же точки.


Прямоугольник



Метод Rectangle вычерчивает прямоугольник. В инструкции вызова метода надо указать координаты двух точек — углов прямоугольника. Например, оператор

Canvas->Rectangle(10,10,50,50)

рисует квадрат, левый верхний угол которого находится в точке (10, 10), а правый нижний в точке (50, 50).

Цвет, вид и ширину линии контура прямоугольника определяют значения свойства Реn, а цвет и стиль запивки области внутри прямоугольника — значения свойства Brush той поверхности, на которой метод рисует прямоугольник. Например, следующие операторы рисуют флаг Российской Федерации.
Canvas->Brush->Color = clWhite; // цвет кисти — белый
Canvas->Rectangle(10,10,90,30);
Canvas->Brush->Color = clBlue; // цвет кисти — синий
Canvas->Rectangle(10,30,90,50);
Canvas->Brush->Color = clRed; // цвет кисти — красный
Canvas->Rectangle(10,50,90,70);

Вместо четырех параметров — координат двух диагональных углов прямоугольника — методу Rectangle можно передать один параметр — структуру типа TRect, поля которой определяют положение диагональных углов прямоугольной области. Следующий фрагмент кода демонстрирует использование структуры TRect В качестве параметра метода Rectangle.
TRect ret; // прямоугольная область
ret.Top = 10;
ret.Left = 10;
ret.Bottom = 50;
ret.Right = 50;
Canvas->Rectangle(ret); // нарисовать прямоугольник

Есть еще два метода, которые вычерчивают прямоугольник. Метод FillRect вычерчивает закрашенный прямоугольник, используя в качестве инструмента только кисть (Brush), а метод FrameRect — только контур и использует только карандаш (Реп). У этих методов только один параметр — структура типа TRect. Поля структуры TRect содержат координаты прямоугольной области. Значения полей структуры TRect можно задать при помощи функции Rect.

Например:
TRect ret; // область, которую надо закрасить
ret = Rect(10,10,30,50); // координаты области
Canvas->Brush->Color = clRed; // цвет закраски
Canvas->FillRect(ret) ;

Метод RoundRec вычерчивает прямоугольник со скругленными углами. Инструкция вызова метода RoundRec в общем виде выглядит так:
Canvas->RoundRec(xl,yl,x2,у2,хЗ,уЗ)

Параметры x1, y1, x2, y2 определяют положение углов прямоугольника, а параметры х3 и у3 — размер эллипса, одна четверть которого используется для вычерчивания скругленного угла (рис. 3.2).



Рис. 3.2. Метод RoundRec вычерчивает прямоугольник со скругленными углами


Многоугольник



Метод Polygon вычерчивает многоугольник. Инструкция вызова метода в общем виде выглядит так:

Canvas->Polygon(p,n)

где р — массив записей типа TPoint, который содержит координаты вершин многоугольника; n — количество вершин.

Метод Polygon чертит многоугольник, соединяя прямыми линиями точки, координаты которых находятся в массиве: первую со второй, вторую с третьей, третью с четвертой и т. д. Вид границы многоугольника определяют значения свойства Реп, а вид заливки области, ограниченной линией границы, — значения свойства Brush той поверхности, на которой метод рисует.

Ниже приведен фрагмент кода, который, используя метод Polygon, рисует ромб.
TPoint p[4]; // четыре вершины
// координаты вершин
р[0].х = 50; р[0].у = 100;
р[1].х = 150; р[1].у = 75;
р[2].х = 250; р[2].у = 100;
р[3].х = 150; р[3].у = 125;
Canvas->Brush->Color = clRed;
Canvas->Polygon(p,3);


Окружность и эллипс



Нарисовать эллипс или окружность (частный случай эллипса) можно при помощи метода Ellipse. Инструкция вызова метода в общем виде выглядит следующим образом:

Canvas->Ellipse(xl,yl,x2,у2)

Параметры x1, y1, x2, y2 определяют координаты прямоугольника, внутри которого вычерчивается эллипс или, если прямоугольник является квадратом, — окружность (рис. 3.3).



Рис. 3.3. Значения параметров метода Ellipse определяют вид геометрической фигуры


Вместо четырех параметров — координат диагональных углов прямоугольника — методу Ellipse можно передать один — объект типа TRect. Следующий фрагмент кода демонстрирует использование объекта TRect в качестве параметра метода Ellipse.

TRect rec = Rect(10,10,50,50);
Canvas->Ellipse(rec);

Как и в случае вычерчивания других примитивов, вид контура эллипса (цвет, толщину и стиль линии) определяют значения свойства Реn, а цвет и стиль заливки области внутри эллипса — значения свойства Brush той поверхности (canvas), на которой метод чертит.


Дуга



Метод Arc рисует дугу — часть эллипса (окружности). Инструкция вызова метода в общем виде выглядит так:

Canvas->Arc(xl,yl,х2,у 2,х3,у3, х4,у4)

Параметры x1, y1, х2, у2 определяют эллипс (окружность), частью которого является дуга. Параметры х3 и у3 задают начальную, а х4 и у4 — конечную точку дуги. Начальная (конечная) точка дуги — это точка пересечения границы эллипса и прямой, проведенной из центра эллипса в точку с координатами х3 и у3(х4, у4). Метод Arc вычерчивает дугу против часовой стрелки от начальной точки к конечной (рис. 3.4).

Цвет, толщина и стиль линии, которой вычерчивается дуга, определяются значениями свойства Реn поверхности (canvas), на которую выполняется вывод.



Рис. 3.4. Значения параметров метода Arc определяют дугу как часть эллипса (окружности)


Сектор



Метод pie вычерчивает сектор эллипса или круга. Инструкция вызова метода в общем виде выглядит следующим образом:

Canvas->Pie(x1,y1,х2,у2,х3,у3,х4,у4)

Параметры x1, y1, x2, y2 определяют эллипс (круг), частью которого является сектор; х3, у3, х4 и у4 — прямые — границы сектора. Начальная точка границ совпадает с центром эллипса. Сектор вырезается против часовой стрелки от прямой, заданной точкой с координатами (х3, у3), к прямой, заданной точкой с координатами (х4, у4) (рис. 3.5).



Рис. 3.5. Значения параметров метода Pie определяют сектор как часть эллипса (окружности)


Текст



Вывод текста (строк типа Ansistring) на поверхность графического объекта обеспечивает метод TextOutA. Инструкция вызова метода TextoutA в общем виде выглядит следующим образом:

Canvas->TextOutA(x,y,TeKCT)

Параметр текст задает выводимый текст. Параметры х и у определяют координаты точки графической поверхности, от которой выполняется вывод текста (рис. 3.6).



Рис. 3.6. Координаты области вывода текста


Шрифт, который используется для вывода текста, определяется значением свойства Font соответствующего объекта canvas. Свойство Font представляет собой объект типа TFont. В табл. 3.4 перечислены свойства объекта TFont, определяющие характеристики шрифта, используемого методом TextoutA для вывода текста.

Таблица 3.4. Свойства объекта TFont

Свойство
Определяет
Name
Используемый шрифт. В качестве значения следует использовать название шрифта (например, Arial)
Size
Размер шрифта в пунктах (points). Пункт— это единица измерения размера шрифта, используемая в полиграфии. Один пункт равен 1/72 дюйма
Style
Стиль начертания символов. Может быть: нормальным, полужирным, курсивным, подчеркнутым, перечеркнутым. Стиль задается при помощи следующих констант: fsBold (полужирный), fsltalic (курсив), fsUnderline (подчеркнутый), fsStrikeOut (перечеркнутый)

Свойство style является множеством, что позволяет комбинировать необходимые стили. Например, инструкция, которая устанавливает стиль "полужирный курсив", выглядит так:

Canvas->Font->Style = TFontStyles ( ) <<fsBold<<f sUnderline
Color
Цвет символов. В качестве значения можно использовать константу типа TColor


При выводе текста весьма полезны методы Textwidth и TextHeight, значениями которых являются соответственно ширина и высота области вывода текста, которые, очевидно, зависят от характеристик используемого шрифта. Обоим этим методам в качестве параметра передается строка, которую предполагается вывести на поверхность методом TextoutA.

Следующий фрагмент кода демонстрирует использование методов, обеспечивающих вывод текста на поверхность формы. Приведенная функция обработки события OnPaint закрашивает верхнюю половину окна белым, нижнюю — голубым цветом, затем в центре окна, по границе закрашенных областей, выводит текст (рис. 3.7).

void _fastcall TForml::FormPaint(TObject *Sender)
{
AnsiString ms = "Borland C++Builder";
TRect aRect;
int x,y; // точка, от которой будет выведен текст
// верхнюю половину окна красим белым
aRect = Rect(0,0,ClientWidth,ClientHeight/2);
Canvas->Brush->Color = clWhite;
Canvas->FillRect(aRect);
// нижнюю половину окна красим голубым
aRect = Rect(0,ClientHeight/2,ClientWidth,ClientHeight);
Canvas->Brush->Color = clSkyBlue;
Canvas->FillRect(aRect);
Canvas->Font->Name = "Times New Roman";
Canvas->Font->Size = 24;
// Canvas->Font->Style = TFontStyles ()« fsBold « fsItalic;
// текст разместим в центре окна
х = (ClientWidth - Canvas-XTextWidth(ms)) /2;
у = ClientHeight/2 - Canvas-XTextHeight(ms) /2;
Canvas->Brush->Style = bsClear; // область вывода текста
// не закрашивать
Canvas->Font->Color = clBlack; Canvas->TextOutA(x,y,ms);
// вывести текст
}



Рис. 3.7. Вывод текста


Иногда требуется вывести какой-либо текст после сообщения, длина которого во время разработки программы неизвестна. В этом случае необходимо знать координаты правой границы области выведенного текста. Координаты правой границы текста, выведенного методом TextOutA, можно получить, обратившись к свойству penPos.

Следующий фрагмент кода демонстрирует возможность вывода строки текста при помощи двух инструкций TextOutA:

Canvas->TextOutA(10,10,"Borland ");
Canvas->TextOutA(Canvas->PenPos.x, Canvas->PenPos.y, "C++Builder");

Точка



Поверхности, на которую программа может осуществлять вывод графики, соответствует объект canvas. Свойство Pixels, представляющее собой двумерный массив типа TColor, содержит информацию о цвете каждой точки графической поверхности. Используя свойство pixels, можно задать цвет любой точки графической поверхности, т. е. "нарисовать" точку. Например, инструкция

Canvas->Pixels[10][10] = clRed

окрашивает точку поверхности формы в красный цвет.

Размерность массива pixels определяется реальным размером графической поверхности. Размер графической поверхности формы (рабочей области, которую также называют клиентской) определяют свойства clientwidth и clientHeight, а размер графической поверхности компонента image — свойства width и Height. Левой верхней точке рабочей области формы соответствует элемент pixels [0] [0], а правой нижней —
Pixels[Ciientwidth - 1][CliientHeight -1].

Следующая программа (листинг 3.1), используя свойство Pixels, строит график функции у = 2 sin(x) e*/5. Границы диапазона изменения аргумента функции являются исходными данными. Диапазон изменения значения функции вычисляется во время работы программы. На основании этих данных программа вычисляет масштаб, позволяющий построить график таким образом, чтобы он занимал всю область формы, предназначенную для вывода графика. Для построения графика используется вся доступная область формы, причем если во время работы программы пользователь изменит размер окна, то график будет выведен заново с учетом реальных размеров окна.

Листинг 3.1. График функции
// обработка события OnPaint
void__fastoall TForml::FormPaint(TObject *Sender)
{
Grafik();
}
// обработка события OnResize
void __fastcall TForml::FormResize(TObject *Sender)
{
TRect ret = Rect(0,0,Ciientwidth,CiientHeight);
Canvas->FillRect(ret); // стереть Grafik();
}
#include "math.h" // для доступа к sin и exp
// функция, график которой надо построить
float f(float х)
{
return 2*sin(x)*exp(x/5); }
void TForml::Grafik()
{
float xl, x2; // границы изменения аргумента функции
float yl, y2; // границы изменения значения функции float x;
// аргумент функции
float у; // значение функции в точке х
float dx; // приращение аргумента
int 1, Ь; // левый нижний угол области вывода графика
int w, h; // ширина и высота области вывода графика
float mx, my; // масштаб по осям X и Y
int xO, уО; // начало координат
// область вывода графика
1-10; // X - координата левого верхнего угла
b = Forml->ClientHeight-20; // Y — координата левого нижнего угла
h = Forml->ClientHeight-40; // высота
w = Forml->Wldth - 20; // ширина
xl = 0; // нижняя граница диапазона аргумента
х2 = 25; // верхняя граница диапазона аргумента dx = 0.01;
 //шаг аргумента
// найдем максимальное и минимальное значение
// функции на отрезке [xl,x2]
x = xl;
yl = f(х); // минимум
у2 = f(x); // максимум
do
{
у = f(х);
if ( у < yl) yl = у;
if ( у > у2) у2 = у;
х += dx; } while (x <= х2);
// вычислим масштаб
my = (float)h/abs(y2-yl); // масштаб по оси Y
mx = w/abs(x2-xl); // масштаб по оси X
// оси
хО = 1+abs(xl*mx);
уО = b-abs(yl*my);
Canvas->MoveTo(xO,b);Canvas->LineTo(xO,b-h);
Canvas->MoveTo(l,yO);Canvas->LineTo(1+w,yO);
Canvas->TextOutA(xO+5,b-h,FloatToStrF(y2,ffGeneral,6,3));
Canvas->TextOutA(xO+5,b,FloatToStrF(yl,ffGeneral, 6,3));
// построение графика x = xl; do {
У = f (x);
Canvas->Pixels[xO+x*mx][yO-y*my] = clRed;
x += dx;
}
while (x <= x2); }

Основную работу выполняет функция Grafik (ее объявление надо поместить в раздел private объявления формы в заголовочном файле программы). Функция Grafik сначала вычисляет максимальное (у2) и минимальное (yi) значение функции на отрезке [x1, x2]. Затем, используя информацию о ширине и высоте области вывода графика, она вычисляет коэффициенты масштабирования по осям X и Y. После этого вычисляет координату Y горизонтальной оси, координату X вертикальной оси и вычерчивает координатные оси. Затем выполняется непосредственное построение графика (рис. 3.8).



Рис. 3.8. График, построенный по точкам


Вызов функции Grafik выполняют функции Обработки событий OnPaint и OnResize. Функция TForm1:: Formpaint обеспечивает вычерчивание графика после появления формы на экране в результате запуска программы, а также после появления формы во время работы программы — например, в результате удаления или перемещения других окон, полностью или частично перекрывающих окно программы. Функция TForm1: :FormResize обеспечивает вычерчивание графика после изменения размера формы.

Приведенная программа универсальна. Заменив инструкции в теле функции f (х), можно получить график другой функции. Причем независимо от вида функции ее график будет занимать всю область, предназначенную для вывода. Следует обратить внимание на то, что приведенная программа работает корректно, если функция, график которой надо построить, принимает как положительные, так и отрицательные значения. Если функция во всем диапазоне только положительная или только отрицательная, то в программу необходимо внести изменения. Какие — пусть это будет упражнением для читателя.


Иллюстрации



Наиболее просто вывести иллюстрацию, которая находится в файле с расширением bmp, jpg или ico, можно при помощи компонента image, значок которого находится на вкладке Additional палитры компонентов (рис. 3.9). Основные свойства компонента приведены в табл. 3.5.



Рис. 3.9. Значок компонента Image


Таблица 3.5. Свойства компонента image

Свойство
Описание
Picture
Иллюстрация, которая отображается в поле компонента
Width, Height
Размер компонента. Если размер компонента меньше размера иллюстрации и значение свойств AutoSize, Strech и Proportional равно false, то отображается часть иллюстрации
Proportional
Признак автоматического масштабирования картинки без искажения. Чтобы масштабирование было выполнено, значение свойства AutoSize должно быть false
Strech
Признак автоматического масштабирования (сжатия или растяжения) иллюстрации в соответствии с реальным размером компонента. Если размер компонента не пропорционален размеру иллюстрации, то иллюстрация будет искажена
AutoSize
Признак автоматического изменения размера компонента в соответствии с реальным размером иллюстрации
Center
Признак определяет расположение картинки в поле компонента по горизонтали, если ширина картинки меньше ширины поля компонента. Если значение свойства равно false, то картинка прижата к правой границе компонента, если true — то картинка располагается по центру
Visible
Признак указывает, отображается ли компонент и, соответственно, иллюстрация на поверхности формы
Canvas
Поверхность, на которую можно вывести графику


Иллюстрацию, которая будет выведена в поле компонента image, можно задать как во время разработки формы приложения, так и во время работы программы.

Во время разработки формы иллюстрация задается установкой значения свойства Picture путем выбора файла иллюстрации в стандартном диалоговом окне, которое становится доступным в результате щелчка на командной кнопке Load окна Picture Editor, которое, в свою очередь, появляется в результате щелчка на кнопке с тремя точками в строке свойства picture (рис. 3.10).

Если размер иллюстрации больше размера компонента, то свойству Proportional нужно присвоить значение true. Тогда будет выполнено масштабирование иллюстрации в соответствии с реальными размерами компонента.

Чтобы вывести иллюстрацию в поле компонента image во время работы программы, нужно применить метод LoadFromFile к свойству Picture, указав в качестве параметра метода файл иллюстрации. Например, инструкция

Imagel->Picture->LoadFromFile("e:\\temp\\bart.bmp")

загружает иллюстрацию из файла bart.bmp и выводит ее в поле компонента вывода иллюстрации (Image 1).

По умолчанию компонент image можно использовать для отображения иллюстраций форматов BMP, ICO и WMF. Чтобы использовать компонент для отображения иллюстраций в формате JPEG (файлы с расширением jpg), надо подключить соответствующую библиотеку (поместить в текст программы директиву #include <jpeg.hpp>). Обратите внимание, что если указанной директивы в тексте программы не будет, то компилятор не выведет сообщения об ошибке. Но во время работы программы при попытке загрузить jpg-файл при помощи метода LoadFromFile возникнет ошибка — исключение EInvalidGraphic.



Рис. 3.10. Чтобы выбрать иллюстрацию, щелкните в строке Picture на кнопке стремя точками, затем в окне Picture Editor — на кнопке Load



Рис. 3.11. Диалоговое окно программы Просмотр иллюстраций


Следующая программа (вид ее окна приведен на рис. 3.11, а текст — в листинге 3.2) использует компонент image для отображения JPG-иллюстраций.

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

Листинг 3.2. Просмотр иллюстраций

#include <jpeg.hpp> // обеспечивает работу с JPEG-иллюстрациями
linclude <FileCtrl.hpp> // для доступа к функции SelectDirectory
AnsiString aPath; // каталог, в котором находится иллюстрация
TSearchRec aSearchRec; // результат поиска файла
void __fastcall TForml::FormCreate(TObject *Sender)
{
aPath = ""; // текущий каталог — каталог, из которого
// запущена программа
Imagel->AutoSize = false;
Imagel->Proportional = true;
Button2->Enabled = false;
FirstPicture(); // показать картинку, которая
// есть в каталоге программы
}
// щелчок на кнопке Каталог
void __fastcall TForml::ButtonlClick(TObject *Sender)
{
if (SelectDirectory(
"Выберите каталог, в котором находятся иллюстрации", "",aPath) != 0)
 {
// пользователь выбрал каталог и щелкнул на кнопке ОК
aPath = aPath + "\\";
FirstPicture(}; // вывести иллюстрацию
}
}
// найти и вывести первую картинку
void TForml::FirstPicture()
{
Imagel->Visible = false; // скрыть компонент Imagel
Button2->Enabled = false; // кнопка Дальше недоступна
Labell->Caption = "";
if ( FindFirst(aPath+ "*.jpg", faAnyFile, aSearchRec) == 0)
{
Imagel->Picture->LoadFromFile(aPath+aSearchRec.Name);
Imagel->Visible = true;
Labell->Caption = aSearchRec.Name;
if ( FindNext(aSearchRec) == 0) // найти след, иллюстрацию
{
// иллюстрация есть
Button2->Enabled = true; // теперь кнопка Дальше доступна
} }
}
// щелчок на кнопке Дальше
void __fastcall TForml::Button2Click(TObject *Sender)
{
Imagel->Picture->LoadFromFile(aPath+aSearchRec.Name);
Labell->Caption = aSearchRec.Name;
if ( FindNext(aSearchRec) != 0) // найти след, иллюстрацию
{
// иллюстраций больше нет
Button2->Enabled = false; // теперь кнопка Дальше недоступна
}
 }

Загрузку и вывод первой и остальных иллюстраций выполняют соответственно функции FirstPicture и NextPicture. функция FirstPicture вызывает функцию FindFirst для того, чтобы получить имя файла первой иллюстрации. В качестве параметров функции FindFirst передаются:

 имя каталога, в котором должны находиться иллюстрации;  структура aSearchRec, поле Name которой, в случае успеха, будет содержать имя файла, удовлетворяющего критерию поиска;  маска файла иллюстрации.


Если в указанном при вызове функции FindFirst каталоге есть хотя бы один файл с указанным расширением, то значение функции будет равно нулю. В этом случае метод LoadFromFiie загружает файл иллюстрации. После загрузки первой иллюстрации функция FirstPicture вызывает функцию FindNext для поиска следующего файла иллюстрации. Если файл будет найден, то кнопка Дальше будет сделана доступной.

Функция обработки события Onclick на кнопке Дальше загружает следующую иллюстрацию, имя файла которой было найдено функцией FindNext в процессе обработки предыдущего щелчка на кнопке Дальше, и снова вызывает функцию FindNext для поиска следующей иллюстрации. Если файл иллюстрации не будет найден, то кнопка Дальше станет недоступной. Необходимо обратить внимание на следующее. Для того чтобы иллюстрации отображались без искажения, свойству Autosize компонента image1 надо присвоить значение false, а свойству Proportional — значение true. Сделать это можно во время создания формы в среде разработки (установить значения свойств в окне Object Inspector) или возложить задачу настройки компонента на саму программу. В последнем случае в функцию обработки события OnCreate для формы (TForm1: : FormCreate) надо добавить следующие инструкции:

Image1->AutoSize = false; Image1->Proportional = true;

Кроме того, во время создания формы свойству Enabled кнопки Дальше (Button2) надо присвоить значение false. Это обеспечит корректную работу программы в том случае, если в каталоге, из которого запускается программа, нет иллюстраций. Настройку кнопки Buttona можно возложить на функцию TForml: : FormCreate. Для этого в функцию надо добавить оператор
Button2->Enabled = false

Битовые образы



Для формирования сложных изображений используют битовые образы. Битовый образ — это, как правило, небольшая картинка, которая находится в памяти компьютера.

Сформировать битовый образ можно путем загрузки из bmp-файла или из ресурса, а также путем копирования фрагмента из другого битового образа, в том числе и с поверхности формы.

Картинку битового образа (иногда говорят просто "битовый образ") можно подготовить при помощи графического редактора или, если предполагается, что битовый образ будет загружен из ресурса программы, — при помощи редактора ресурсов (например, Borland Resource Workshop). В последнем случае надо создать файл ресурсов и поместить в него битовый образ. Файл ресурсов можно создать и при помощи утилиты Image Editor.

В программе битовый образ — это объект типа TBitmap. Некоторые свойства объекта TBitmap приведены в табл. 3.6.

Загрузку картинки из файла обеспечивает метод LoadFromFile, которому в качестве параметра передается имя bmp-файла. Например, следующий фрагмент кода обеспечивает создание и загрузку битового образа из файла.

Graphics: :TBitmap *Plane = new Graphics: :TBititiap() ;
Plane->LoadFromFile("plane.bmp");

В результате выполнения приведенного выше фрагмента, битовый образ Plane представляет собой изображение самолета (предполагается, что в файле plane.bmp находится изображение самолета).

Таблица 3.6. Свойства объекта TBitmap

Свойство
Описание
Height, Width
Размер (ширина, высота) битового образа. Значения свойств соответствуют размеру загруженной из файла (метод LoadFromFile) или ресурса (метод LoadFromResourcelD или LoadFromResourceName) картинки
Empty
Признак того, что картинка в битовый образ не загружена (true)
Transparent
Устанавливает (true) режим использования "прозрачного" цвета. При выводе битового образа методом Draw элементы картинки, цвет которых совпадает с цветом TransparentColor, не выводятся. По умолчанию значение TransparentColor определяет цвет левого нижнего пиксела
TransparentColor
Задает прозрачный цвет. Элементы картинки, окрашенные этим цветом, методом Draw не выводятся
Canvas
Поверхность битового образа, на которой можно рисовать точно так же, как на поверхности формы или компонента image


После того как битовый образ сформирован (загружен из файла или из ресурса), его можно вывести, например, на поверхность формы или компонента image. Сделать это можно, применив метод Draw к свойству Canvas. В качестве параметров методу Draw надо передать координаты точки, от которой будет выведен битовый образ. Например, оператор

Canvas->Draw(10,20,Plane);

выводит на поверхность формы битовый образ plane — изображение самолета.

Если перед применением метода Draw свойству Transparent битового образа присвоить значение true, то фрагменты рисунка, цвет которых совпадает с цветом левой нижней точки рисунка, не будут выведены. Такой прием используется для создания эффекта прозрачного фона. "Прозрачный" цвет можно задать и принудительно, присвоив соответствующее значение свойству TransparentColor.

Следующая программа демонстрирует работу с битовыми образами. После запуска программы в ее окне появляется изображение неба и двух самолетов (рис. 3.12). И небо, и самолеты — это битовые образы, загруженные из файлов во время работы программы. Загрузку и вывод битовых образов на поверхность формы выполняет функция обработки события onPaint, текст которой приведен в листинге 3.3. Белое поле вокруг левого самолета показывает истинный размер битового образа Plane. Белого поля вокруг правого самолета нет, т. к. перед тем как вывести битовый образ второй раз, свойству Transparent было присвоено значение true.



Рис. 3.12. Присвоив свойству Transparent значение true, можно скрыть фон


Листинг 3.3. Загрузка и вывод битовых образов на поверхность формы 

void __fastcall TForml::FormPaint(TObject *Sender)
{
// битовые образы: небо и самолет
Graphics::TBitmap *sky = new Graphics::TBitmap();
Graphics::TBitmap *plane = new Graphics::TBitmap();
sky->LoadFromFile("sky.bmp");
plane->LoadFromFile("plane.bmp");
Canvas->Draw(0,0,sky); // фон - небо
Canvas->Draw(20,20,plane); // левый самолет
plane-XTransparent = true;
/* теперь элементы рисунка, цвет которых совпадает
с цветом левой нижней точки битового образа,
не отображаются */
Canvas->Draw(120,20,plane); // правый самолет
// уничтожить объекты
sky->Graphics::-TBitmap();
plane->Graphics::-TBitmap();
}


Небольшие по размеру битовые образы часто используют при формировании фоновых рисунков по принципу кафельной плитки (рис. 3.13).



Рис. 3.13. Фоновый рисунок и битовый образ-плитка, из которого он составлен


Следующая программа показывает, как можно получить фоновый рисунок путем многократного вывода битового образа на поверхность формы. Формирование фонового рисунка, многократный вывод битового образа на поверхность формы выполняет функция Background. Ее объявление (прототип), а также объявление битового образа (объекта типа TBitmap) надо поместить в секцию private объявления класса формы (листинг 3.4), которая находится в заголовочном файле. Создание битового образа и загрузку картинки из файла выполняет функция обработки события onCreate. Функция обработки события OnPaint путем вызова функции Background обеспечивает вывод фонового рисунка на поверхность формы (листинг 3.5).

Листинг 3.4. Объявление битового образа и функции Background 

class TForml : public TForm
{
_published:
void__fasteal1 FormCreate(TObject *Sender);
void__fastcall FormPaint(TObject *Sender);
void__fastcall FormResize(TObject *Sender);
private:
Graphics::TBitmap *back; // элемент фонового рисунка
void __fastcall Background(); // формирует фоновый рисунок на
// поверхности формы public:
_fastcall TForml(TComponent* Owner);
};

Листинг 3.5. Функции, обеспечивающие формирование и вывод фонового рисунка
// обработка события OnCreate
void __fastcall TForml::FormCreate(TObject *Sender)
{
back = new Graphics::TBitmap(); // создать объект — битовый образ
// загрузить картинку
try // в процессе загрузки картинки возможны ошибки
{
Forml->back->LoadFromFile("Legal.bmp");
}
catch (EFOpenError &e)
{
return;
}
 }
// формирует фоновый рисунок
void __fastcall TForml::Background()
{
int x=0,y=0; // координаты левого верхнего угла битового образа
if ( back->Empty) // битовый образ не был загружен
return;
do
{
do
 {
Canvas->Draw(x,y,back); x += back->Width;
}
while (x < ClientWidth); x = 0;
у4= back->Height;
}
while (y < ClientHeight);
}
// обработка события OnPaint
void __fastcall TForml::FormPaint(TObject *Sender)
{
Background(); // обновить фоновый рисунок
}

Мультипликация



Под мультипликацией обычно понимается движущийся и меняющийся рисунок. В простейшем случае рисунок может только двигаться или только меняться.

Обеспечить перемещение рисунка довольно просто: надо сначала вывести рисунок на экран, затем через некоторое время стереть его и снова вывести этот же рисунок, но уже на некотором расстоянии от его первоначального положения. Подбором времени между выводом и удалением рисунка, а также расстояния между старым и новым положением рисунка (шага перемещения), можно добиться того, что у наблюдателя будет складываться впечатление, что рисунок равномерно движется по экрану.


Метод базовой точки



Следующая простая программа показывает, как можно заставить двигаться изображение, сформированное из графических примитивов. Окно и форма программы приведены на рис. 3.14.



Рис. 3.14. Окно и форма программы


На поверхности формы находится один-единственный компонент Timer, который используется для генерации последовательности событий, функция обработки которых обеспечивает вывод и удаление рисунка. Значок компонента Timer находится на вкладке System (рис. 3.15). Следует обратить внимание, что компонент Timer является невизуальным. Это значит, что во время работы программы компонент в диалоговом окне не отображается. Поэтому компонент Timer можно поместить в любую точку формы. Свойства компонента Timer приведены в табл. 3.7.



Рис. 3.15. Значок компонента Timer


Таблица 3.7. Свойства компонента Timer

Свойство
Определяет
Name
Имя компонента. Используется для доступа к свойствам компонента
Interval
Период возникновения события OnTimer, Задается в миллисекундах
Enabled
Разрешение работы. Разрешает (значение true) или запрещает (значение false) возникновение события OnTimer


Компонент Timer генерирует событие OnTimer. Период возникновения события onTimer измеряется в миллисекундах и определяется значением свойства interval. Следует обратить внимание на свойство Enabled. Оно дает возможность программе "запустить" или "остановить" таймер. Если значение свойства Enabled равно false, то событие onTimer не возникает.

В рассматриваемой программе вывод изображения выполняет функция ship, которая рисует на поверхности формы кораблик. В качестве параметров функция ship получает координаты базовой точки. Базовая точка (X0, Y0) определяет положение графического объекта в целом; от нее отсчитываются координаты графических примитивов, образующих объект (рис. 3.16). Координаты графических примитивов можно отсчитывать от базовой точки не в пикселах, а в относительных единицах. Такой подход позволяет легко выполнить масштабирование изображения.



Рис. 3.16. Базовая точка (х0, у0) определяет положение объекта


Перед тем как нарисовать кораблик на новом месте, функция обработки события от таймера стирает кораблик, нарисованный в процессе обработки предыдущего события onTimer. Изображение кораблика стирается путем вывода прямоугольника, перекрывающего его.

Функции обработки события OnTimer, функция Ship и функция FormCreate, обеспечивающая настройку таймера, приведены в листинге 3.6

 Листинг 3.6. Простая мультипликация

int х = -68, у = 50; // начальное положение базовой точки
// рисует на поверхности формы кораблик
void __fastcall TForml::Ship(int x, int y)
 {
int dx=4,dy=4; // шаг сетки
// корпус и надстройку будем рисовать
// при помощи метода Polygon
TPoint pi[7]; // координаты точек корпуса
TPoint p2[8]; // координаты точек надстройки
TColor pc,bc; // текущий цвет карандаша и кисти
// сохраним текущий цвет карандаша и кисти
рс = Canvas->Pen->Color;
be = Canvas->Brush->Color;
// установим нужный цвет карандаша и кисти
Canvas->Pen->Color = clBlack;
Canvas->Brush->Color = clWhite;
// рисуем ... 11 корпус
pl[0].x = x; pl[0].y = y;
pl[l].x=x; pl[l].y = y-2*dy;
pl[2].x = x+10*dx; pi[2].у = y-2*dy;
pl[3].x = x+ll*dx; pl[3].y = y-3*dy;
pl[4]-x = x+17*dx; pi[4].у =y-3*dy;
pl[5].x = x+14*dx; pi[5].у =y;
pl[6].x = x; pl[6].y =y;
Canvas->Polygon(pl,6);
// надстройка
p2[0].x = x+3*dx; p2[0].y = y-2*dy;
p2[l].x = x+4*dx; p2[l].y = y-3*dy;
р2[2].х = x+4*dx; p2[2].y = y-4*dy;
р2[3].х = x+13*dx; p2[3].y = y-4*dy;
р2[4].х = x+13*dx; p2[4].y = y-3*dy;
р2[5].х = x+ll*dx; p2[5].y = y-3*dy;
р2[6].х = x+10*dx; p2[6].y = y-2*dy;
р2[7].х = x+3*dx; p2[7].y = y-2*dy;
Canvas->Polygon(p2,7);
Canvas->MoveTo(x+5*dx,y-3*dy);
Canvas->LineTo(x+9*dx,y-3*dy);
// капитанский мостик
Canvas->Rectangle(x+8*dx,y-4*dy,x+ll*dx,y-5*dy);
// труба
Canvas->Rectangle(x+7*dx,y-4*dy,x+8*dx,y-7*dy);
// иллюминаторы
Canvas->Ellipse(x+ll*dx,y-2*dy,x+12*dx,y-l*dy);
Canvas->Ellipse(x+13*dx,y-2*dy,x+14*dx,y-l*dy);
// мачта
Canvas->MoveTo(x+10*dx,y-5*dy);
Canvas->LineTo(x+10*dx,y-10*dy);
// оснастка
Canvas->Pen->Color = clWhite;
Canvas->MoveTo(x+17*dx,y-3*dy);
Canvas->LineTo(x+10*dx, y-10*dy);
Canvas->LineTo(x,y-2*dy);
// восстановим цвет карандаша и кисти
Canvas->Pen->Color = рс;
Canvas->Brush->Color = be; }
// обработка события OnTimer
void__fastcall TForml::TimerlTimer(TObject *Sender)
{
// стереть кораблик — закрасить цветом, совпадающим
// с цветом фона (формы)
Canvas->Brush->Color = Forml->Color;
Canvas->FillRect(Rect(x-1,y+l,x+68,y-40));
// вычислить координаты базовой точки х+=3;
if (x > ClientWidth)
{
// кораблик "уплыл" за правую границу формы
х= -70; // чтобы кораблик "выплывал" из-за левой границы формы
y=random(Forml->ClientHeight); }
// нарисовать кораблик на новом месте Ship(х, у) ; )
// обработка события OnCreate для формы
void__fastcall TForml::FormCreate(TObject *Sender)
{
/* Таймер можно настроить во время разработки программы
(в процессе создания формы) или во время работы программы. */
// настройка и запуск таймера
Timerl->Interval = 100; // период события OnTimer —0.1 сек.
Timerl->Enabled = true; // пуск таймера
}

Использование битовых образов



В последнем примере изображение формировалось из графических примитивов. Теперь рассмотрим, как можно реализовать перемещение заранее подготовленного при помощи графического редактора изображения.

Как и в предшествующей программе, эффект перемещения объекта (картинки) достигается за счет периодической перерисовки картинки с некоторым смещением относительно ее прежнего положения. Перед выводом картинки в новой точке предыдущее изображение должно быть удалено, а фоновый рисунок, который был перекрыт — восстановлен. Удалить (стереть) картинку и одновременно восстановить фон можно путем перерисовки всей фоновой картинки или только той ее части, которая была перекрыта объектом. В рассматриваемой программе используется второй подход. Изображение объекта выводится применением метода Draw к свойству canvas формы, а стирается путем копирования (метод CopyRect) нужной части фона из буфера в битовый образ, соответствующий поверхности формы.

Форма программы приведена на рис. 3.17, а текст — в листинге 3.6. Компонент Timer используется для организации цикла удаления и вывода изображения самолета.



Рис. 3.17. Форма программы "Полет над городом"


Листинг 3.7. Полет над городом

void _fastcall TForml::FormCreate(TObject *Sender)
{
// загрузить фоновый рисунок из bmp-файла
back = new Graphics::TBitmap();
back->LoadFromFile("factory.bmp");
// установить размер клиентской (рабочей) области формы
// в соответствии с размером фонового рисунка
GlientWidth = back->Width;
ClientHeight = back->Height;
// загрузить картинку
sprite = new Graphics::TBitmap();
sprite->LoadFromFile("aplane.bmp");
sprite->Transparent = true;
// исходное положение самолета
x=-20; // чтобы самолет "вылетал" из-за левой границы окна У=20;
}
void _fastcall TForml::FormPaint(TObject *Sender)
{
Canvas->Draw(0,0,back); //фон
Canvas->Draw(x,у,sprite); // рисунок }
void__fastoall TForml::TimerlTimer(TObject *Sender)
{
TRect badRect; // положение и размер области фона,
// которую надо восстановить
badRect = Rect(x,y,x+sprite->Width,y+sprite->Height);
// стереть самолет (восстановить "испорченный" фон)
Canvas->CopyRect(badRect,back->Canvas,badRect);
// вычислим новые координаты спрайта (картинки)
х +=2;
if (х > ClientWidth)
{
// самолет улетел за правую границу формы
// изменим высоту и скорость полета
х = -20;
у = random(ClientHeight —30); // высота полета"
// скорость полета определяется периодом возникновения
// события On Timer, который, в свою очередь, зависит
// от значения свойства Interval
Timerl->Interval = random(20) + 10;
// скорость "полета" меняется
// от 10 до 29 }
Canvas->Draw(х,у,sprite);
}

Для хранения битовых образов (картинок) фона и самолета используются два объекта типа TBitmap, которые создает функция TFormi:: Formcreate (объявления этих объектов надо поместить в заголовочный файл проекта). Эта же функция загружает из файлов картинки фона (factory.bmp) и самолета (aplane.bmp).

Восстановление фона выполняется при помощи метода copyRect, который позволяет выполнить копирование прямоугольного фрагмента одного битового образа в другой. Объект, к которому применяется метод copyRect, является приемником копии битового образа. В качестве параметров методу передаются: координаты и размер области, куда должно быть выполнено копирование; поверхность, с которой должно быть выполнено копирование; положение и размер копируемой области. Информация о положении и размере восстанавливаемой (копируемой на поверхность формы) области фона находится в структуре badRect типа TRect.

Следует обратить внимание на то, что начальное значение переменной х, которая определяет положение левой верхней точки битового образа (движущейся картинки) — отрицательное число, равное ширине битового образа картинки. Поэтому в начале работы программы самолет не виден и картинка отрисовывается за границей видимой области. С каждым событием OnTimer значение координаты х увеличивается и на экране появляется та часть битового образа, координаты которой больше нуля. Таким образом, у наблюдателя создается впечатление, что самолет вылетает из-за левой границы окна.


Загрузка битового образа из ресурса программы



В программе "Полет над городом" (листинг 3.7) картинки (битовые образы) фона и объекта (самолета) загружаются из файлов. Такой подход не всегда удобен. C++ Builder позволяет поместить нужные битовые образы в исполняемый файл программы и по мере необходимости загружать их непосредственно оттуда.

Битовый образ, находящийся в выполняемом файле программы, называется ресурсом, а операция загрузки битового образа из выполняемого файла — загрузкой битового образа из ресурса.

Для того чтобы воспользоваться возможностью загрузки картинки из ресурса, сначала надо создать файл ресурсов и поместить в него нужные картинки.


Создание файла ресурсов



Файл ресурсов можно создать при помощи утилиты Image Editor, которая поставляется вместе с C++ Builder. Запустить Image Editor можно из C++ Builder, выбрав в меню Tools команду Image Editor, или из Windows, выбрав команду Пуск | Программы | Borland C++Builder | Image Editor.

Для того чтобы создать файл ресурсов, надо в меню File выбрать команду New, а затем в появившемся подменю — команду Resource File (рис. 3.18). В результате выполнения команды будет создан файл ресурсов Untitledl.res (рис. 3.19), в который надо поместить необходимые ресурсы.



Рис. 3.18. Чтобы создать файл ресурсов, выберите команду File | New | Resource File



Рис. 3.19. Файл ресурсов создан. Теперь в него надо поместить необходимые ресурсы


Для того чтобы в файл ресурсов добавить новый ресурс, надо в меню Resource выбрать команду New | Bitmap (Новый битовый образ). В результате выполнения этой команды открывается диалоговое окно Bitmap Properties (Характеристики битового образа), в котором нужно установить размер (в пикселах) битового образа и выбрать палитру (рис. 3.20). В результате нажатия кнопки ОК в списке Contents появится новый элемент Bitmap1, соответствующий новому ресурсу, добавленному в файл ресурсов (рис. 3.21).



Рис. 3.20. В диалоговом окне Bitmap Properties надо задать характеристики создаваемого битового образа



Рис. 3.21. Окно файла ресурсов после добавления ресурса Bitmap


Bitmap 1 — это автоматически созданное имя ресурса, которое можно изменить, выбрав команду Resource | Rename. После этого можно приступить к редактированию (созданию) битового образа. Для этого надо в меню Resource выбрать команду Edit. В результате этих действий будет активизирован режим редактирования битового образа.

Графический редактор Image Editor предоставляет программисту стандартный для подобных редакторов набор инструментов, используя которые можно нарисовать нужную картинку. Если во время работы надо изменить масштаб отображения картинки, то для увеличения масштаба следует выбрать команду View | Zoom In, а для уменьшения — команду View | Zoom Out. Увидеть картинку в реальном масштабе можно, выбрав команду View | Actual Size.

В качестве примера на рис. 3.22 приведен вид диалогового окна Image Editor, в котором находится файл ресурсов images.res для программы Flight. Файл содержит два битовых образа FACTORY и APLANE.



Рис. 3.22. Файл ресурсов images.res содержит два битовых образа


Если нужная картинка уже существует в виде отдельного файла, то ее можно через буфер обмена (Clipboard) поместить в битовый образ файла ресурсов. Делается это следующим образом.

1. Сначала надо запустить графический редактор, например Microsoft Paint, загрузить в него файл картинки и выделить всю картинку или ее часть. В процессе выделения следует обратить внимание на информацию о размере (в пикселах) выделенной области (Paint выводит размер выделяемой области в строке состояния). Затем, выбрав команду Копировать меню Правка, необходимо поместить копию выделенного фрагмента в буфер.

2. Далее нужно переключиться в Image Editor, выбрать ресурс, в который надо поместить находящуюся в буфере картинку, и установить значения характеристик ресурса в соответствии с характеристиками картинки, находящейся в буфере. Значения характеристик ресурса вводятся в поля диалогового окна Bitmap Properties, которое открывается выбором команды Image Properties меню Bitmap. После установки характеристик ресурса можно вставить картинку в ресурс, выбрав команду Past меню Edit.

После добавления всех нужных ресурсов файл ресурса следует сохранить в том каталоге, где находится программа, для которой этот файл создается. Сохраняется файл ресурса обычным образом, т. е. выбором команды Save меню File. Image Editor присваивает файлу ресурсов расширение res.


Подключение файла ресурсов



Для того чтобы ресурсы, находящиеся в файле ресурсов, были доступны программе, в текст программы надо поместить инструкцию (директиву), которая сообщит компилятору, что в исполняемый файл следует добавить содержимое файла ресурсов.

В общем виде эта директива выглядит следующим образом:

#pragma resource ФайлРесурсов

где ФайлРесурсов — имя файла ресурсов.

Например, для программы flight_l директива, обеспечивающая включение содержимого файла ресурсов в выполняемый файл, выглядит так:
#pragma resource "images.res"

Загрузить битовый образ из ресурса можно при помощи метода LoadFromResourceName, который имеет два параметра: идентификатор программы и имя ресурса. В качестве идентификатора программы используется глобальная переменная Hinstance. Имя ресурса должно быть представлено в виде строковой константы.

Например, в программе flight_l инструкция загрузки фона из ресурса выглядит так:
back->LoadFromResourceName((int)Hinstance,"FACTORY");

В качестве примера в листинге 3.8 приведен фрагмент программы flight_l — функция TForm1:: FormCreate, которая обеспечивает загрузку битовых образов из ресурсов.

 Листинг 3.8. Загрузка битовых образов из ресурса 
// подключить файл ресурсов, в котором находятся
// необходимые программе битовые образы
#pragma resource "images.res"
void__fastcall TForml::FormCreate(TObject *Sender)
{
// загрузить фоновый рисунок из ресурса
back = new Graphics::TBitmap();
back->LoadFromResourceName((int)HInstance,"FACTORY");
// установить размер клиентской (рабочей) области формы
//в соответствии с размером фонового рисунка
ClientWidth = back->Width;
ClientHeight = back->Height;
// загрузить изображение объекта из ресурса
sprite = new Graphics::TBitmap();
sprite->LoadFromResourceName((int)HInstance,"APLANE");
sprite->Transparent = true;
// исходное положение самолета
x=-20; // чтобы самолет "вылетал" из-за левой границы окна
у=20;
}

Преимущества загрузки картинок из ресурса программы очевидны: при распространении программы не надо заботиться о том, чтобы во время работы программы были доступны файлы иллюстраций, т. к. все необходимые программе картинки находятся в исполняемом файле.

Теперь рассмотрим, как можно реализовать в диалоговом окне программы вывод баннера, представляющего собой последовательность сменяющих друг друга картинок (кадров). Кадры баннера обычно находятся в одном файле или в одном ресурсе. В начале работы программы они загружаются в буфер (объект типа TBitmap). Вывод кадров баннера обычно выполняет функция обработки сигнала от таймера (события onTimer), которая выделяет очередной кадр и выводит его на поверхность формы.

Вывести кадр баннера (фрагмент битового образа) на поверхность формы можно при помощи метода copyRect, который копирует прямоугольную область одной графической поверхности на другую.

Инструкция применения метода CopyRect в общем виде выглядит так:
Canvasl->CopyRect(Область1, Canvas2, Область2)

где:

 Canvas1 — поверхность, на которую выполняется копирование;  Canvas2 — поверхность, с которой выполняется копирование;  Область1 — структура типа TRect, которая задает положение и размер области, куда выполняется копирование (приемник);  Область2 — структура типа TRect, которая задает положение и размер области, откуда выполняется копирование (источник).


Определить прямоугольную область, заполнить поля структуры TRect можно при помощи функции Rect или Bounds. Функции Rect надо передать в качестве параметров координаты левого верхнего и правого нижнего углов области, функции Bounds — координаты левого верхнего угла и размер области. Например, если надо определить прямоугольную область, то это можно сделать так: ret = Rect(x1,y1,x2,y2) или так: ret = Bounds(x1,y1,w,h)

где x1, y1 — координаты левого верхнего угла области; х2, у2 — координаты правого нижнего угла области; w и h — ширина и высота области.

Следующая программа (ее текст приведен в листинге 3.9) выводит в диалоговое окно баннер — рекламное сообщение. На рис. 3.23 приведены кадры этого баннера (содержимое файла baner.bmp), а на рис. 3.24 — диалоговое окно. Форма программы содержит один-единственный компонент — таймер.



Рис. 3.23. Кадры баннера



Рис. 3.24. Воспроизведение баннера в окне программы


Листинг 3.9. Баннер (baner.h, baner_.cpp)

// baner.h
class TForml : public TForm
{ published:
TTimer *Timerl;
void__fastcall FormCreate(TObject *Sender);
void __fastcall TimerITimer(TObject *Sender);
private:
Graphics::TBitmap *baner; // баннер
TRect kadr; // кадр баннера
TRect scr; // область воспроизведения баннера
int w, h; // размер кадра
int с; // номер воспроизводимого кадра
public:
_fastcall TForml(TComponent* Owner);
};
// baner_.cpp
#define FBANER "borland.bmp" // баннер
#define NKADR 4 // количество кадров в баннере
void__fastcall TForml::FormCreate(TObject *Sender)
{
baner = new Graphics::TBitmap();
baner->LoadFromFile(FBANER); // загрузить баннер
h = baner->Height;
w = baner->Width / NKADR;
scr = Rect(10,10,10+w,10+h); // положение и размер области
// воспроизведения баннера kadr = Rect(0,0,w,h);
// положение и размер первого кадра
//в баннере
}
// обработка события OnTimer
void__fastcall TForml:rTimerlTimer(TObject *Sender)
{
// вывести кадр баннера
Canvas->CopyRect(scr,baner->Canvas,kadr);
// подготовиться к воспроизведению следующего кадра
if (с < NKADR)
{
// воспроизводимый в данный момент
// кадр — не последний
с++;
kadr.Left += w;
kadr.Right += w;
 }
else
{
с = 0;
kadr.Left = 0;
kadr.Right = w;
 }
 }

Программа состоит из двух функций. Функция TForm1:: Form-Create создает объект TBitmap и зафужает в него баннер — BMP-файл, в котором находятся кадры баннера. Затем, используя информацию о размере загруженного битового образа, функция устанавливает значения характеристик кадра: высоту и ширину.

Основную работу в программе выполняет функция обработки события onTimer, которая выделяет из битового образа Baner очередной кадр и выводит его на поверхность формы. Выделение кадра и его отрисовку путем копирования фрагмента картинки с одной поверхности на другую выполняет метод copyRect (рис. 3.25), которому в качестве параметров передаются координаты области, куда нужно копировать, поверхность и положение области, откуда нужно копировать. Положение фрагмента в фильме, т. е. координата х левого верхнего угла, определяется умножением ширины кадра на номер текущего кадра.



Рис. 3.25. Метод CopyRect копирует в область Rect1 поверхности Canvas1 область Rect2 с поверхности Canvas2