Мерцание, которое можно было наблюдать в примере 17.6 возникает вследствие того, что изображение приходится перерисовывать на форме при каждом срабатывании таймера. Чем больше будут размеры движущегося объекта, тем сильнее будет мерцание. Использование свойств формы AlphaBlend и DoubleBuffered не всегда дает результат.
Для организации анимации движения можно использовать битовые образы, которые были рассмотрены в §14. Для вывода битового образа на Image можно использовать разные методы (пример 17.7). Использование метода Draw было рассмотрено в §14. Для применения других методов необходимо выделять на рисунке прямоугольную область.
Переменные Pr1 и Pr2 из таблицы примера 17.7 описаны типом TRect. Тип TRect — это структура с 4 полями (Left, Top, Right, Bottom), которая используется для хранения верхней левой и нижней правой вершин прямоугольника. Задавать значения можно непосредственным присваиванием значений или с помощью функций Rect или Bounds (пример 17.8).
Пример 17.9. Изменить проект из примера 14.5 так, чтобы животных можно было рисовать в выбранном масштабе.
Этапы выполнения задания
- Поместить на форму два компонента Image, компоненты LabeledEdit, Button и диалог OpenPictureDialog.
- Изменить свойства Caption у компонента Button1 на «Выбрать».
- Установить у компонента Image2 значение true для свойства AutoSize (рисунок будет загружаться в реальном размере).
- Изменить у компонента LabeledEdit1 свойство Caption на «Коэффициент масштабирования», свойство Text — на 1,3.
- Описать как глобальные переменные два битовых образа: Ris1 — для хранения исходного изображения, Ris2 — для хранения изображения с учетом масштаба;
- Написать обработчик события OnCreate для формы, в котором загрузить из файла изображение леса в компонент Image1.
- Написать обработчик события OnClick для компонента Button1.
7.1. Загрузить в битовый образ Ris1 изображение из выбранного файла. 7.2. Вывести его в Image2 методом Assign.
- Написать обработчик события OnMouseDown для компонента Image1, в котором
8.1. Задать прямоугольник, длины сторон которого получаются как длины сторон исходного изображения, умноженные на коэффициент масштабирования. 8.2. Задать размеры Ris2 в соответствии с масштабом. 8.3. Скопировать изображение с Ris1 на Ris2, используя метод StretchDraw. 8.4. Методом Draw вывести изображение на Image1.
При использовании метода CopyRect можно копировать прямоугольную область, находящуюся на одной канве, в прямоугольную область, находящуюся на другой канве (пример 17.10).
Если размеры прямоугольников совпадают, то получаем точную копию. Если размер источника меньше или больше, то копия масштабируется так, чтобы вписаться в прямоугольник (пример 17.11). Прозрачность фона при этом не поддерживается.
При использовании метода CopyRect изображения можно выводить, отразив их слева-направо или сверху-вниз. Для этого нужно заменить значения полей в структуре, описывающей прямоугольник:
//сверху вниз Pr2 = Pr1; Pr2.bottom = Pr1.top;[1] Pr2.top = Pr1.bottom; //слева направо Pr3 = Pr1; Pr3.left = Pr1.right; Pr3.right = Pr1.left;
При необходимости можно изменить все четыре значения — в этом случае получим зеркальное отображение рисунка.
В примере 17.12. изображения копировались с битового образа Pict1 в битовый образ Pict2 для того, чтобы можно было затем вывести изображение с прозрачным фоном.
[1] Иногда необходимо отнять 1, поскольку точка, описывающая нижний правый угол, не принадлежи области копирования. Вследствие чего, при добавлении прозрачности, может оставаться белая полоса толщиной в 1 пиксель.
|
Пример 17.7. Методы вывода битового образа (Ris1):
Требуемый результат
|
Метод
|
Копирование графики
|
Draw(x, y, Ris1)
|
Копирование с масштабирова-нием
|
StretchDraw(Pr1, Ris1)
|
Копирование прямоугольного участка канвы
|
CopyRect(Pr1, Ris -> Canvas, Pr2)
|
Полное копирование всех свойств (в том числе и размеров)
|
Picture->Assign(Ris1)
|
Пример 17.8. Определение прямоугольной области:
TRect Pr1, Pr2, Pr3;
//Определение прямоугольной //области указанием значений //полей
Pr1.left = x1;
Pr1.top = y1;
Pr1.right = x2;
Pr1.bottom = y2;
//Определение прямоугольной //области по координатам
Pr2 = Rect(x1, y1, x2, y2);
//Определение прямоугольной //области путем задания
//верхнего левого угла и
//длины, ширины прямоугольника
Pr3 = Bounds(x1, y1, w, h);
|
Пример 17.9. Форма на этапе проектирования:
Обработчик события OnCreate для формы.
void __fastcall TForm1:: FormCreate(TObject *Sender)
{
Image1 ->Picture -> LoadFromFile("лес.bmp");
OpenPictureDialog1 -> InitialDir =
ExtractFilePath(ParamStr(0));
}
|
Обработчик события OnClick для компонента Button1.
void __fastcall TForm1:: Button1Click(TObject *Sender)
{
if (OpenPictureDialog1 ->Execute()){
Ris1 -> LoadFromFile (OpenPictureDialog1 ->FileName);
Image2 -> Picture -> Assign(Ris1);
w = Ris1 -> Width;
h = Ris1 -> Height;
}
}
|
Обработчик события OnMouseDown для компонента Image1.
void __fastcall TForm1:: Image1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { TRect Pr1; double k = StrToFloat (LabeledEdit1 -> Text); Pr1 = Bounds(0, 0, int(k * w), int(k * h)); Ris2 -> Width = int(k * w); Ris2 -> Height = int(k * h); Ris2 -> Canvas ->StretchDraw(Pr1, Ris1); Ris2 -> Transparent = true; Image1 -> Canvas -> Draw(X, Y, Ris2); }
|
Работающее приложение:
Пример 17.10. Формат команды CopyRect:
Пример 17.11. Использование метода CopyRect:
Пример 17.12. Копирование с отражением:
Обработчик события для кнопки:
void __fastcall TForm1:: Button1Click(TObject *Sender)
{
TRect Pr1, Pr2, Pr3, Pr4;
Pr1 = Bounds(0, 0, w, h);
Image1 -> Canvas -> Draw(250, 200, Pict1);
//сверху вниз
Pr2 = Pr1;
Pr2.bottom = Pr1.top - 1;
Pr2.top = Pr1.bottom;
Pict2 -> Canvas -> CopyRect(Pr2,
Pict1 -> Canvas, Pr1);
Image1 -> Canvas -> Draw(50, 300, Pict2);
//слева направо
Pr3 = Pr1;
Pr3.left = Pr1.right;
Pr3.right = Pr1.left;
Pict2 -> Canvas -> CopyRect(Pr3,
Pict1 -> Canvas, Pr1);
Image1 -> Canvas -> Draw(100, 200, Pict2);
//сверху-вниз, слева-направо
Pr4 = Pr1;
Pr4.left = Pr1.right;
Pr4.right = Pr1.left;
Pr4.top = Pr1.bottom;
Pr4.bottom = Pr1.top;
Pict2 -> Canvas -> CopyRect(Pr4,
Pict1 -> Canvas, Pr1);
Image1 -> Canvas -> Draw(350, 300, Pict2);
}
|
|