1 Основные компоненты для работы с графикой

advertisement
Тема: Реализация простой графической программы средствами Delphi
Основывается на лекции номер 3.




Цели работы:
Изучить объекты "Delphi", связанные с выводом графической информации;
Изучить методы создания графических изображений в системах использующих
событийную модель;
Познакомиться с принципами формирования динамического изображения;
Познакомиться с основными компонентами графической системы.
Программа семинара
1 Основные компоненты для работы с графикой;
2 Свойства класса ТCanvas;
3 Методы и события класса ТCanvas;
4. Разработка простой программы;
5. Создание «резиновой нити»;
6. Реализация преобразования координатных систем;
7. Добавление функции масштабирования изображения;
8. Дополнительное задание;
9. Заключение;
7 Контрольные вопросы;
Во все современные инструментальные среды разработки приложений встроены
средства работы с графикой. Не является исключением и среда Delphi, имеющая набор
визуальных компонент и специализированных объектов, обладающих широкими
возможностями работы с графической информацией. В ходе этого занятия мы познакомимся
с этими компонентами и объектами, а также с некоторыми методами создания графических
изображений. Полный текст программы, разрабатываемой в ходе семинара, можно найти на
прилагаемом диске.
1 Основные компоненты для работы с графикой
В Delphi существует три визуальных компонента, предназначенных для создания
пользователем геометрических примитивов:

Элемент управления изображением (компонент TImage). Используется для
импорта в приложение растровых изображений, пиктограмм и метафайлов. Рисунок
хранится в свойстве Picture.

Фигура (компонент TShape). Используется для создания стандартных
геометрических фигур: окружностей, эллипсов, прямоугольников и квадратов как
заполненных, так и нет. Свойство Shape определяет тип фигуры, а Pen и Brush характеристики границ и заполнения, соответственно.

Элемент управления окном рисования (компонент TPaintBox). Используется
для придания графических возможностей объектам, не имеющих свойства Сanvas, например,
компоненту Panel.
Во всех других объектах графические операции выполняются с использованием
свойства Canvas. Это свойство представлено объектом класса TСanvas, Оно поддерживается
многими компонентами. Например, оно есть у TForm, TBitMap, TComboBox и TPaintBox.
Свойство Сanvas предоставляет доступ к интерфейсу графических устройств Windows
(Graphic Device Interface - GDI) и обеспечивает независимую от устройства область
рисования графических объектов в окнах. Другими словами, методы объектов класса
TСanvas вызывают функции Windows GDI.
2 Свойства класса ТCanvas
Объект Canvas поддерживает восемь свойств. Значения этим свойствам
присваиваются только во время работы программы, обычно в обработчике событий формы
OnCreate или OnPaint.
Brush. Определяет цвет (Color) и шаблон (Style) заливки окружности, прямоугольника
и многоугольника, а также основной цвет текста.
ClipRect. Отсекает графику за пределами прямоугольника, размер которого обычно
совпадает с размером клиентской области окна. Для того, чтобы изменить размеры
графического объекта, его подсвойствам Left, Top, Right и Bottom присваиваются новые
значения.
CopyMode. Определяет, как обрабатывается изображение при вызове метода CopyRect
объекта Canvas. (см. ниже). Например, CopyMode равный cmNotSourceCopy, инвертирует
изображение попиксельно перед копированием.
Font. Подсвойства этого комплексного свойства используются для выбора стилей
шрифтов, применяемых при выводе текста с помощью методов TextOut или TextRect объекта
Canvas. Данный объект не имеет никакого отношения к свойству формы Font. Перед
выводом текста не забудьте установить свойства Canvas.Font.
Handle. Используется в качестве параметра дескриптора контекста устройства при
вызове методов GDI. Таким образом реализована возможность вызова отсутствующих в
объекте Canvas функций GDI.
Pen. Воздействует на линии и контуры. Определяет цвет, стиль, ширину и режим
выводимых линий соответствующими подсвойствами Color, Style, Width, Mode.
PenPos. Представляет относительные координаты объекта Pen (PenPos.X, PenPos.Y),
которые определяют, где появится следующий графический объект. Несмотря на то, что
Delphi разрешает присваивание свойству PenPos новых значений, для изменения
местоположения объекта Pen следует вызывать метод MoveTо объекта Canvas.
Pixels. Двухмерный массив для обеспечения доступа к отдельным пикселям объекта
Canvas. Каждый элемент массива является значением типа TColor. Например, выражение
Pixels[0,0] возвращает цвет пикселя, имеющего координаты (0,0).
Свойство Pixels является псевдомассивом. Класс TCanvas преобразует ссылки на
элементы Pixels[X, Y] в вызовы функций GetPixel и SetPixel. Поэтому применение Pixels
считается одним из самых неэффективных методов, используемых при создании
графических образов.
3 Методы и события класса ТCanvas
Объекты класса TCanvas имеют много методов, которые удовлетворяют потребности,
возникающие при создании большинства прикладных программ. Такие методы построения
фигур, как ArcEllipse, FloodFill, Polygon, Rectangle, RoundRect и др., непосредственно
обращаются к функциям GDI, которые имеют те же самые имена. Их перечень можно
получить в справке Delphi.
He забывайте перед каждым использованием объекта Canvas присваивать значения
его свойствам в обработчике события OnPaint. Например, чтобы нарисовать синюю линию,
подсвойству Pen.Color свойства Canvas присвойте значение clBlue, а затем вызовите методы
MoveTo и LineTo. Свойства Canvas нельзя предварительно сконфигурировать в обработчике
события формы OnCreate, поскольку событие OnPaint получает дескриптор контекста
устройства от Windows, а сам контекст устройства обеспечивается вашей программой через
2
Canvas. Таким образом, Canvas в OnPaint не содержит ни одного значения свойства, которое
вы присваиваете вне обработчика этого события. Ниже приведен список методов Canvas,
назначение которых не столь очевидно.
CopyRect. Копирует все или часть содержимого одного объекта Canvas в другой.
Установите свойство CopyMode, чтобы задать способ объединения пикселей. Применяемые
значения свойства CopyMode вы можете узнать из интерактивной справки Delphi.
Draw. Рисует объект класса TGraphic, который является прямым предком классов
TIcon, TBitmap и TMetafile. В метод Draw вы можете передавать любую пиктограмму,
растровое изображение или метафайл.
DrawFocusRect. Рисует прямоугольник, используя логическую операцию
исключающего ИЛИ (XOR). При повторном вызове этого метода с идентичными
аргументами удаляется нарисованный прямоугольник и восстанавливается предыдущее
изображение.
FrameRect. Рисует незаполненный прямоугольник, используя текущее значение
свойства Pen, но игнорируя Brush. Если вы, не используя свойства Brush, хотите получить
простой контур, вместо Rectangle примените метод FrameRect.
StretchDraw. Работает аналогично методу Draw, но растягивает или уменьшает
пиктограмму, растровое изображение или метафайл, чтобы они поместились в заданном
прямоугольнике.
Кроме того, объект Canvas распознает два события, которые при особых
обстоятельствах могут быть весьма полезны. Во многих приложениях вам не понадобится
обеспечивать их обработку, но вы, по крайней мере, должны знать об их существовании.
 OnChange. Вызывается после изменения значения свойства Canvas.
 OnChanging. Вызывается непосредственно перед изменением свойства Canvas.
Поскольку свойство недоступно во время разработки, вы не сможете воспользоваться
услугами Object Inspector для создания обработчиков этих двух событий. Для того чтобы их
использовать необходимо создать их обработчики вручную.
4. Разработка простой программы
Решим простую задачу – вычерчивание на экране отрезков. Для этого разместите на
форме экземпляр объекта TРaintBox, обладающий доступным свойством Сanvas. В
обработчик события onMouseDown данного объекта поместите код, запоминающий
координаты курсора в момент нажатия кнопки мыши. Эти координаты будут определять
начальную точку отрезка. В обработчик события onMouseUp поместите код, производящий
построение отрезка, соединяющего запомненную точку с точкой, в которой произошло
отпускание кнопки мыши. Для этого можно использовать методы MoveTo и LineTo объекта
Сanvas. Поставленная задача решена, однако наша программа имеет ряд существенных
недостатков. Мы будем рассматривать и устранять их поочередно.
При сворачивании окна или изменении его размеров нарисованные отрезки будут
исчезать. Причина ясна. При наступлении этих событий (и ряда других) происходит
перерисовка окна, в процессе которой все его содержимое стирается. Преодолеть данное
затруднение можно, заменив визуальный компонент TPaintBox на компонент TImage. Этот
компонент хранит в себе образ создаваемого растрового изображения и, при необходимости,
обеспечивает его перерисовку. Однако такой подход не очень удачен, так как мы не сможем
редактировать созданное изображение (сможем, но только попиксельно). Более удачным
решением будет хранение координат конечных точек всех созданных отрезков и
перерисовывание созданного изображения или его фрагментов при необходимости.
Структуру, хранящую координаты точек, в грубом приближении, можно рассматривать как
модель.
3
В реальной системе выделение памяти под такую структуру должно быть
динамическим, так как объем хранимой информации заранее неизвестен. В нашем примере
для простоты мы воспользуемся массивом.
Создайте такой массив и измените написанный ранее код, так чтобы координаты
конечных точек отрезков заносились в массив (массив можно сделать двумерным, а его
базовым типом выбрать запись, хранящую координаты x и y).
Напишите процедуру, рисующую отрезки по координатам точек, хранящимся в
массиве. Разместите вызов этой процедуры в обработчике события onPaint компонента
TPaintBox. Таким образом мы обеспечиваем восстановление изображения.
Не размещайте вызов в обработчике события onPaint формы. Для формы это событие
порождается при изменении любого объекта формы. В результате возникает избыточное
перечерчивание.
5. Создание «резиновой нити»
Пользоваться созданной нами программой не удобно, так как мы видим положение
отрезка только после того как указали определяющие его точки. В такой ситуации сложно
создать даже произвольный горизонтальный отрезок. Однако, помочь пользователю
достаточно просто. После ввода первой точки отрезка можно показать позицию
создаваемого отрезка, соединив линией введенную точку и текущую позицию курсора
мыши. При перемещении мыши линия должна соответственно изменять свое положение. С
подобным приемом вы, наверное, сталкивались, работая с графическими программами.
Данный тип курсора (ответа системы на действия пользователя) носит название «резиновой
нити». Далее мы разберем принципы ее реализации.
Прежде чем переходить к изучению методов создания изменяющихся во времени
изображений, рассмотрим подробнее режимы вывода, задаваемые свойством Canvas.Pen.Мode. С полным списком разрешенных значений этого свойства можно
познакомится в справочной системе Delphi. Мы рассмотрим только наиболее важные для
нашей темы режимы:

pmCopy
Цвет линии определяется свойством Canvas.Pen.Color. При
выводе в этом режиме рисуемая линия уничтожает попавшие под нее пиксели фона и
заносит на их места пиксели своего цвета. Данный режим используется по умолчанию;

pmXor Цвет линии определяется результатом операции Xor (исключающее
ИЛИ) над цветом фона и цветом, заданным свойством Canvas.Pen.Color;

pmNotXor
Цвет линии определяется отрицанием результата, полученного по
схеме предыдущего режима.
В отличие от режима pmCopy, при выводе в режимах, определяющих
результирующий цвет на основе логической операции Xor, информация о фоне учитывается
при определении цвета, выводимого пикселя, и ее при необходимости можно восстановить.
Предположим, цвет пикселя фона задан битовой комбинацией 1111, а цвет линии0101, тогда цвет выводимого пикселя определиться как
1111
цвет _ пикселя _ фона
0101
цвет _ пикселя _ линии
xor
xor
1010
цвет _ выводимого _ пикселя
Восстановить цвет фона достаточно просто. Еще раз выполним логическую операцию
Xor между полученным цветом и цветом линии
1010
цвет _ выводимого _ пикселя
0101
цвет _ пикселя _ линии
xor
xor
1111
цвет _ пикселя _ фона
4
Как видим, битовый код цвета пикселя идентичен исходному цвету. Таким образом,
если в режиме Xor начертить линию любого цвета, а затем повторно прорисовать ее по тем
же координатам тем же цветом, то линия исчезнет с экрана, оставив фон не поврежденным.
Цвет выводимого пикселя сильно отличается от желаемого цвета линии (заданного
свойством Canvas.Pen.Color). Чтобы этого не происходило, вместо логической операции Xor
используют операцию NotXor. Результирующий цвет получается близким или совпадающим
с цветом линии. Рассмотрим тот же пример.
1111
0101
notxor
как видим, результирующий цвет совпадает с цветом линии
0101
0101
0101
notxor
так же как и в предыдущем случае получаем исходный цвет фона.
1111
На рассмотренной выше идее и основывается один из методов создания «резиновой
нити». При каждом движении мыши необходимо:
1. Стереть с экрана существующий на данный момент отрезок. Для этого необходимо
начертить еще раз этот отрезок в режиме NotXor.
2. Начертить в режиме NotXor отрезок, связанный с новым положением мыши.
Запомнить координаты концов отрезка для повторного вычерчивания,
обеспечивающего стирание отрезка (так как первая точка отрезка фиксирована,
можно запоминать только одну точку).
Реализуйте «резиновую нить». Для этого поместите в обработчик события onMouseMove требуемый код. Не забудьте вставить проверку на нажатие левой кнопки мыши, нить
должна появляться только при нажатой кнопке.
Созданная вами программа может оставлять на экране «мусор» в виде отдельных
точек. Это вызвано тем, что при первом перемещении курсора мыши образа нити на экране
не существует, и попытка стирания приводит к появлению «мусора». Чтобы этого не
происходило, нужно добавить в обработчик события onMouseDown функцию рисования
нити (создаваемый отрезок будет единичной длины).
6. Реализация преобразования координатных систем
Теперь попробуем преобразовать нашу систему из «рисовальной» в «чертежную».
Ключевое различие будет в используемых координатных системах. До этого момента мы
работали в координатной системе экрана. Ни один инженер не захочет, да и не сможет
работать в экранных координатах. Следовательно, мы должны определить координатную
систему, удобную пользователю и выполнять преобразования из данной системы в экранные
координаты и наоборот. Такая координатная система называется модельной. Подобные
преобразования выполняются с помощью двумерного видового конвейера, рассмотренного
нами на лекции 3. Полная реализация конвейера достаточно сложна, поэтому мы
существенно упростим задачу, оставив только одно преобразование. Вывод, по-прежнему,
будем осуществлять в экранных координатах, а для описания элементов модели используем
нормализованные координаты. В процессе нормализации приведем все координаты к
диапазону от 0 до 1.
Для формирования преобразования нам необходимо определить две компоненты:
окно, определяющее область видимости, и поле вывода, задающее место вывода
изображения на экране.
В нашем случае вывод осуществляется с помощью визуального объекта PaintBox.
Выбрав поле вывода, совпадающее по размерам с рабочей областью данного объекта и
зафиксировав его, мы существенно упростим решение задачи. Во-первых, для описания
преобразования достаточно будет знать только текущие координаты окна. Во-вторых, мы
5
уйдем от проблемы отсечения части изображения, оказавшейся вне области видимости.
Фрагменты модели, координаты которых попадают за пределы рабочей области объекта
TPaintBox, просто не будут выводиться на экран. Эту задачу будет решать за нас
операционная система. Такой подход, безусловно, не применим в реальной системе, так как
существенно снижает ее эффективность. Отсечение обычно выполняется относительно окна
до выполнения преобразований. Бессмысленно выполнять расчеты для объектов, которые в
конечном итоге не будут видны.
Теперь рассмотрим, как определить окно преобразования. Его размеры и позиция
определят видимую часть модели. Мы приводим модель к нормализованным координатам,
следовательно, координаты окна тоже не должны выходить за пределы диапазона от 0 до 1.
Положение и размер окна, как мы увидим позднее, будут меняться в ходе взаимодействия
пользователя с программой. В качестве начальных значений удобно взять вершины с
координатами (0,0) и (1,1). Это гарантирует нам то, что в момент запуска программы, модель
будет видна полностью, конечно, если она существует. Модель можно заполнить
значениями, сохраненными в файле после предыдущей сессии работы программы.
Не забудьте сделать поле вывода подобным окну (в нашем случае квадратным), иначе
коэффициенты масштабирования по осям будут различны, и возникнет искажение формы.
Используя формулы, рассмотренные в лекционном материале, напишите процедуру,
преобразующую координаты точки из нормализованных координат в экранные на основании
характеристик окна и поля вывода. Это будет процедура, выполняющая
прямое
преобразование. Она будет использована нами при отображении модели на экране (можно
написать отдельные функции для X и Y координат, так будет удобнее).
Напишите процедуру, выполняющую обратное преобразование – из экранных
координат в нормализованные. Данная процедура необходима при вводе координат
конечных точек создаваемых отрезков (так же можно выполнить в виде отдельных
функций).
Модифицируйте написанный ранее код так, чтобы координаты точек линий,
вводимые пользователем перед занесением в модель (в массив) подвергались обратному
преобразованию. Обратите внимание на то, что координаты модели становятся
вещественными (необходимо сделать соответствующие изменения в определении массива).
Внесите также изменения в процедуру, создающую образ модели на экране. Перед
построением каждого отрезка необходимо выполнить прямое преобразование его конечных
точек.
Если вы правильно выполнили задание, то внешне, работа нашей программы должна
остаться без изменений. Что дали нам внесенные изменения? Теперь наша модель описана в
координатах не зависящих от устройства. Преобразование из нормализованных координат в
экранные, и обратно, производится на основе масштабирования и переноса. Коэффициент
масштабирования определиться коэффициентом подобия окна и поля вывода. Так как в
исходном положении мы задали окно и поле вывода, начинающимися из инвариантной
точки (0,0), то сдвиг можно исключить из рассмотрения. Следовательно, можно рассчитать
масштабирующий коэффициент, связывающий размеры образов на экране с реальными
размерами объектов.
7. Добавление функции масштабирования изображения
Рассмотрим, как можно изменить этот коэффициент. Самый простой способ - это
явное задание масштаба. Многие хорошо вам знакомые прикладные программы
предоставляют пользователю возможность задать масштаб изображения в процентах.
Однако, для графических систем данный подход не удобен. При увеличении масштаба
пользователь не может указать какую именно часть изображения он хочет видеть на экране в
увеличенном виде. Система предлагает пользователю тот или иной фрагмент, и для поиска
нужной части изображения приходится пользоваться полосами прокрутки.
6
При другом подходе пользователь непосредственно указывает прямоугольную
область изображения, которую он хочет увидеть на экране увеличенной. Фрагменты,
попавшие в указанную область, появятся на экране, а не попавшие подвергнутся отсечению.
Такими свойствами обладает не что иное, как окно преобразования. Заданный пользователем
прямоугольник - это образ будущего окна преобразования. Определяя прямоугольник,
пользователь с помощью мыши задает пару точек в экранных координатах. Для того чтобы
получить из них координаты окна необходимо применить к данным точкам обратное
преобразование. Остается только перечертить изображение на экране с учетом
изменившихся характеристик преобразования устройства.
Реализуете такой подход в нашей программе. Для этого вам потребуется новый тип
курсора – «резиновый прямоугольник». Принципы его построения аналогичны принципам
создания «резиновой нити». Не забудьте учесть ограничение, наложенное на окно - оно
должно быть подобно полю вывода. Мы приняли отношение сторон равное единице, что
присуще квадрату. В принципе, отношение сторон прямоугольников, определяющих окно и
поле вывода, может быть любым – главное чтобы оно было одинаковым. Задается такое
ограничение достаточно просто. Первая точка, определяющая прямоугольник, безусловно,
принимается, а от второй точки берется одна из координат. Значение второй координаты
рассчитывается исходя из требований ограничения.
Кроме того, необходим механизм, отменяющий увеличение. Самый простой способ –
запомнить начальное преобразование и при необходимости восстановить его. Для
пользователя удобнее использовать пошаговый откат, позволяющий последовательно
отменять увеличения в порядке обратном их заданию. Для реализации пошагового отката
требуется стек, в котором будут храниться описания преобразований (история). Как мы уже
говорили, преобразование устройства полностью описывается характеристиками окна (в
силу того, что поле вывода, у нас зафиксировано). Следовательно, каждая ячейка стека
должна хранить координаты двух точек, определяющих окно. При каждом увеличении
необходимо занести в стек координаты текущего окна. При выходе из увеличения мы просто
восстанавливаем из стека предыдущие координаты окна.
В нашей программе появляется несколько функций, и необходимо разобраться, какую
из них в данный момент хочет выполнить пользователь. То есть необходимо организовать
поддержку диалога с пользователем. Задача сложная и выходящая за рамки нашего курса.
Мы просто определим некоторую переменную, которая будет определять состояние системы
на текущий момент времени. Разрешим ей принимать два значения – Lines (отрезки) и Zoom
(лупа). По умолчанию установим значение Lines.
Теперь модифицируйте код нашей программы.
Обработчик события onMouseDown можно оставить без изменений, нам безразлично,
вводит пользователь первую точку окна или отрезка.
В обработчике события onMouseMove требуется учитывать состояние системы. Если
система находится в состоянии Lines, то используем курсор – «резиновая нить», в противном
случае (состояние Zoom) - «резиновый прямоугольник».
Действия по отпусканию кнопки мыши также зависят от состояния системы. В
состоянии Lines необходимо вычертить отрезок. В другом случае набор действий более
широк:
 занести в стек характеристики текущего окна преобразования;
 применить к веденным пользователем точкам прямоугольника обратное
преобразование устройства, получив координаты нового окна;
 заменить координаты текущего окна новыми значениями;
 перевести систему в состояние Lines;
 инициировать перерисовывание модели.
Нам потребуется создать две кнопки. Первая – “Увеличить”. При ее нажатии мы
переводим
систему в состояние “Zoom” (устанавливаем соответствующее значение
7
переменной за него отвечающей за состояние). Вторая кнопка - «Отменить». Ее нажатие
приводит к выполнению следующих действий:
 извлечению из стека (если он не пуст) сохраненных при последнем увеличении
координат окна преобразования;
 замены текущих значений окна извлеченными значениями;
 перечерчиванию модели.
Состояние системы при этом не изменяется (Lines).
8. Дополнительное задание
Создайте приложение, включающее в себя 4 окна (поля вывода). В первом окне
реализуйте возможность свободного рисования с помощью мыши. При нажатой кнопке за
курсором должен оставаться точечный след. Во втором окне должны вычерчиваться отрезки
с использованием курсора “резиновая нить”, показывающим положение создаваемого
отрезка. В третьем окне - прямоугольники, в качестве курсора необходимо использовать
“резиновый прямоугольник”. По нажатию правой кнопки мыши реализуйте режим
перетаскивания нарисованных ранее прямоугольников. В последнем окне аналогичным
образом должны вычерчиваться окружности.
9. Заключение.
В рамках данного занятия мы, с помощью графических средств среды Delphi, создали
прототип простейшей интерактивной программы. В ходе ее мы коснулись многих основных
компонент, которые включает в себя интерактивная графическая система. Еще раз
перечислим их.
Прикладная модель. Хранит в себе описание создаваемых пользователем объектов в
терминах геометрических примитивов, поддерживаемых данной системой, и отношений
между ними. В нашем примере модель была вырождена до простого массива.
Модуль визуализации. Компонента системы, обеспечивающая создание визуального
представления модели. Во многих системах реализуется на основе геометрического
конвейера. Прямое преобразование координат, производимое нами при выводе примитивов,
имеет непосредственное отношение к данному модулю.
Логические устройства ввода информации. Обеспечивают ввод графической
информации в координатной системе модели, поддерживают необходимые типы курсоров и
обеспечивают независимость от физических устройств.
Интерфейс пользователя – набор компонент, обеспечивающих взаимодействие
пользователя с системой. К интерфейсу можно отнести меню, кнопки и другие визуальные
объекты, созданные нами на экране. Обработчики событий и состояние системы,
представленное в нашей программе совокупностью значений переменных, обеспечивают
логику диалога с пользователем.
Реализовывать самостоятельно все компоненты графической системы сложно и
трудоемко. Удобнее воспользоваться готовыми средствами. Реализации таких стандартов
графического ядра как GKS или PHIGS предоставляют прикладному программисту наиболее
полный набор необходимых компонент. Они предлагают средства логического ввода/вывода,
структуры хранения данных для создания модели, видовой конвейер и другие компоненты.
Библиотеки класса OpenGL, DirectX предоставляют пользователю только средства
связанные с выводом изображения, возлагая на прикладного программиста реализацию
других компонент. Однако, на сегодняшний день они пользуются большой популярностью и
последующие занятия мы посвятим работе с OpenGL.
7 Контрольные вопросы
1.
линии?
Почему предпочтительнее использовать режим NotXor при имитации движения
8
2. В
обработчике,
какого
события
целесообразно
размещать
код,
восстанавливающий изображение?
3. Какие визуальные компоненты Delphi, предназначенные для вывода графического
изображения, не требуют его восстановления при перечерчивании формы?
4. Перечислите основные свойства объекта Canvas.
5. К чему приведет изменение положения поля вывода (без изменения размеров) при
неизменном окне преобразования?
6. Что произойдет с изображением, если увеличить окно преобразования?
9
Download