§ 14. Интерактивная графика

14.2. Построение изображения в зависимости от размера и положения

Пример 14.2. Создать проект, в котором будет строиться изображение «сердечка». Пользователь задает высоту и ширину изображения. Местоположение рисунка будет определяться кликом мыши (в точке, где кликнули, должен располагаться центр изображения). Если изображение целиком не помещается в области рисования, то следует вывести соответствующее сообщение.

Этапы выполнения задания

  1. Разместить на форме компоненты: Image и два компонента LabeledEdit для ввода размеров изображения.
  2. Написать обработчик события OnMouseDown для компонента Image1.
    2.1. По клику мыши рисуем «сердечко».
    2.2. Для рисования одного изображения опишем функцию heart. Эта функция должна стать методом формы, поэтому ее объявление нужно добавить в заголовочный файл. Для того, чтобы функция была определена в области видимости класса формы перед ее заголовком необходимо прописать void __fastcall TForm1::.
    2.3. Изображение «сердечка» можно разбить на части: равнобедренный треугольник и два полукруга.
    2.3.1. Для построения треугольника будем использовать метод канвы Polygon. У этого метода два параметра — массив точек и номер точки в массиве, которую нужно соединить с нулевой. Массив из трех точек можно описать следующим образом:
    TPoint t[3] = {{x4,y4},{x6,y6},{x3,y3}};
    2.3.2. Для построения полукруга будем использовать метод канвы Pie.
    2.4.  Все координаты для рисования рассчитываются относительно центральной точки и размеров изображения, введенных пользователем.
    2.5. Изображение будем строить с красной границей и зальем его красным цветом.
  3. Проверить, поместится ли изображение в область рисования можно считая, что прямоугольник, определяемый диагональю (x1; y1) — (x2; y2) должен помещаться в компонент Image1.

Пример 14.3. Создать проект, в котором можно будет выбирать, как располагать «сердечки»:

а) одно «сердечко» в случайном месте Image;
б) «сердечки» расположены по одному в ряд вдоль левого края Image;
в) «сердечки» равномерно заполняют весь Image.

Выбор необходимо осуществлять с помощью соответствующих кнопок.

Этапы выполнения задания

  1. Разместить на форме: компонент Image и три кнопки.
  2. Будем использовать функцию рисования «сердечка» из примера 14.2.
  3. Написать обработчик события OnClick для компонента Button1. Рисуем одно «сердечко». Размер и местоположение определяем случайным образом.
  4. Написать обработчик события OnClick для компонента Button2. В цикле меняем вертикальную координату, определяющую местоположения «сердечка». Размер — 30 на 30 пикселей. Цикл выполняется, пока вертикальная координата меньше высоты Image1.
  5. Написать обработчик события OnClick для компонента Button3. Используем два вложенных цикла, в которых будут меняться горизонтальная и вертикальная координаты, определяющие местоположения сердечка. Размер — 30 на 30 пикселей. Циклы выполняются, пока координаты меньше размеров Image1.
  6. В начале каждого обработчика необходимо очищать Image1 от предыдущих изображений.

Пример 14.2. Добавление метода heart в заголовочный файл формы:

Расчет элементов изображения:

Значения  и  вводятся пользователем, значение d = w/2. Значения x0, y0 определяются кликом мыши, остальные координаты высчитываются по следующим формулам:

x1 = x0 – w/2; y1 = y0 – h/2;
x2 = x0 + w/2; y2 = y0 + h/2;
x3 = x1y3 = y1 + d/2;
x4 = x2y4 = y3;
x5 = x3 + dy5 = y3;
x6 = x5y6 = y2;

Обработчик события OnMouseDown и функция рисования:

void __fastcall TForm1::heart(int x0, int y0, 
                              int w, int h)

{

  Image1 -> Canvas -> Pen -> Color = clRed;

  Image1 -> Canvas -> Brush -> Color = clRed;

  int d = w / 2;

  int x1 = x0 - w/2, y1 = y0 - h/2;

  int x2 = x0 + w/2, y2 = y0 + h/2;

  int x3 = x1, y3 = y1 + d/2;

  int x4 = x2, y4 = y3;

  int x5 = x3 + d, y5 = y3;

  int x6 = x5, y6 = y2;

  Image1 -> Canvas -> Pie(x1, y1, x5, y5 + d / 2, x5, y5, x3, y3);

  Image1 ->Canvas -> Pie(x5, y5 - d / 2, x4, y4 + d / 2, x4, y4, x5, y5);

  TPoint t[3] = {{x4,y4},{x6,y6},{x3,y3}};

  Image1 ->Canvas ->Polygon(t, 2);

}

//---------------------------------

void __fastcall TForm1::Image1MouseDown
(TObject *Sender, TMouseButton Button, 
TShiftState Shift,   
int X, int Y)

{

  int width = StrToInt(LabeledEdit1 ->Text);

  int height = StrToInt(LabeledEdit2 ->Text);

  if (X - width / 2 < 0 || Y - height / 2 < 0 ||

     X + width / 2 > Image1 -> Width ||

     Y + height / 2 > Image1 -> Height)

    ShowMessage("Не поместится");

  else

    heart(X, Y, width, height);

}

Работающее приложение:

 Пример 14.3. Обработчики событий для кнопок:

void __fastcall TForm1::Button1Click
                (TObject *Sender)

{

  Image1 -> Canvas -> Pen -> Color = clWhite;

  Image1 -> Canvas -> Brush -> Color = clWhite;

  Image1 -> Canvas -> Rectangle(0, 0,

      Image1 -> Width, Image1 -> Height);

  int width = rand() % 300 + 30;

  int height = rand() % 300 + width;

  int x = rand() %(Image1 ->Width - 2 * width) + width / 2;

  int y = rand() %(Image1 ->Height - 2 * height) + height / 2;

  heart(x, y, width, height);

}

//---------------------------------

void __fastcall TForm1::Button2Click
               (TObject *Sender)

{

  Image1 -> Canvas -> Pen -> Color = clWhite;

  Image1 -> Canvas -> Brush -> Color = clWhite;

  Image1 -> Canvas -> Rectangle(0, 0,

      Image1 -> Width, Image1 -> Height);

  for (int y = 16; y < Image1 -> Height - 16; y += 45)

    heart(16, y, 3030);

}

//---------------------------------

void __fastcall TForm1::Button3Click
                (TObject *Sender)

{

  Image1 -> Canvas -> Pen -> Color = clWhite;

  Image1 -> Canvas -> Brush -> Color = clWhite;

  Image1 -> Canvas -> Rectangle(0, 0,

      Image1 -> Width, Image1 -> Height);

  for (int x = 16; x < Image1 -> Width - 16; x += 45)

    for (int y = 16; y < Image1 -> Height - 16; y += 45)

      heart(x, y, 3030);

}

Работающее приложение: