§ 17. Анімацыя

17.4. Фрагменты малюнкаў

Мігаценне, якое можна было назіраць у прыкладзе 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 так, каб жывёл можна было маляваць у абраным маштабе.

Этапы выканання задання

  1. Змясціць на форму два кампаненты Image, кампаненты LabeledEdit, Button і дыялог OpenPictureDialog.
  2. Змяніць уласцівасці Caption у кампанента Button1 на «Выбрать».
  3. Устанавіць у кампанента Image2 значэнне true для ўласцівасці AutoSize (малюнак будзе загружацца ў рэальным памеры).
  4. Змяніць у кампанента LabeledEdit1 уласцівасць Caption на «Коэффициент масштабирования», уласцівасць Text — на 1,3.
  5. Апісаць як глабальныя пераменныя два бітавых вобраза: Ris1 — для захоўвання зыходнага малюнка, Ris2 — для захоўвання малюнка з улікам маштабу;
  6. Напісаць апрацоўшчык падзеі OnCreate для формы, у якім загрузіць з файла малюнак лесу ў кампанент Image1.
  7. Напісаць апрацоўшчык падзеі OnClick для кампанента Button1.
    7.1. Загрузіць у бітавы вобраз Ris1 малюнак з абранага файла.
    7.2. Вывесці яго ў Image2 метадам Assign.
  8. Напісаць апрацоўшчык падзеі 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(00,
    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(00, w, h);

  Image1 -> Canvas -> Draw(250200, Pict1);

  //зверху-ўніз

  Pr2 = Pr1;

  Pr2.bottom = Pr1.top - 1;

  Pr2.top = Pr1.bottom;

  Pict2 -> Canvas -> CopyRect(Pr2,

      Pict1 -> Canvas, Pr1);

  Image1 -> Canvas -> Draw(50300, Pict2);

  //злева-направа

  Pr3 = Pr1;

  Pr3.left = Pr1.right;

  Pr3.right = Pr1.left;

  Pict2 -> Canvas -> CopyRect(Pr3, 

      Pict1 -> Canvas, Pr1);

  Image1 -> Canvas -> Draw(100200, 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(350300, Pict2);

}