C++ Builder - вопросы программирования

         

обработка события OnResize void __fastcall



Листинг 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.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
 




Листинг 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.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.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; // пуск таймера }
 




Листинг 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.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.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), которому в качестве параметров передаются координаты области, куда нужно копировать, поверхность и положение области, откуда нужно копировать. Положение фрагмента в фильме, т. е. координата х левого верхнего угла, определяется умножением ширины кадра на номер текущего кадра.

Содержание раздела