Система Windows предоставляет средства рисования GDI (Graphics Device Interface) для построения графических изображений на графическом контексте независимо от типа устройства вывода. При прямом вызове функций GDI им необходимо передавать дескриптор контекста устройства (HDC – device context handle), который задает инструменты рисования. Графический контекст представляет собой модель графического устройства. После завершения работы c изображениями необходимо восстановить контекст устройства в исходное состояние и освободить его. C++Builder берет на себя работу GDI, связанную с поиском дескрипторов изображений и ресурсов памяти. Разрешается прямое обращение приложений к функциям Windows GDI. Рассмотрим пример:
MessageBox(Form1->Handle,"Вызов Windows API","",MB_OK);
}
C++Builder предоставляет простой интерфейс посредством свойства Canvas графических компонентов. Это свойство инициализирует и освобождает контекст устройства. Свойство Canvas представляет собой класс, инкапсулирующий свойства и методы для работы с графикой.
В среде C++Builder существует три способа для работы с графикой.
• Канва представляет собой битовую карту поверхности для рисования на форме, графическом компоненте или на другом битовом образе. Кроме формы, для рисования используются объекты классов TImage и TPaintBox. Canvas является свойством этих классов. Рассмотрим пример рисования на форме:
Метод FormPaint здесь вызывается событием OnPaint формы при ее рисовании. Отметим, что при рисовании непосредственно на форме возникает ряд проблем, связанных с ее перерисовкой. В следующем примере рассматриваются различные способы задания цвета формы и цвета линий для рисования на компоненте TImage.
При нажатии на первую кнопку выбирается цвет формы, при нажатии на вторую кнопку рисуются линии случайно выбранным цветом.
• Графика (TGraphic) представляет собой абстрактный базовый класс для работы с графикой. C++Builder определяет графические классы TBitmap, TClipBoard, TImage, TIcon и TMetafile, производные от базового класса TGraphic. Объекты этих классов используют как методы рисования на канве, так и собственные методы. Методы класса TGraphic: LoadFromClipboardFormat(), LoadFromFile(), LoadFromStream(), SaveToClipboardFormat(), SaveToFile(), SaveToStream().
• Рисунок (TPicture) представляет собой контейнер для графических объектов. Свойствами этого класса являются: Bitmap, Graphic, Icon, Metafile, PictureAdapter. Контейнерный класс TPicture может содержать битовый образ, пиктограмму, метафайл или некоторый другой графический тип, а приложение будет обращаться ко всем объектам контейнера посредством объекта класса TPicture. Если необходимо указать доступ к конкретному графическому объекту, задайте его в свойстве Graphic данного рисунка. Методы этого класса: LoadFromClipboardFormat(), LoadFromFile(), LoadFromStream(), SaveToClipboardFormat(), SaveToFile(), SaveToStream().
Класс Canvas инкапсулирует графические функции Windows на различных уровнях, начиная с функций высокого уровня для рисования линий, фигур и текста. Далее следуют свойства и методы среднего уровня для манипуляций с канвой. В табл. 7 приводятся характеристики основных методов и свойств канвы.
Объекты класса Canvas являются свойствами формы и всех графических объектов, например TForm, TImage, TBitmap. Рассмотрим пример:
{ case 0: Canvas->Pen->Style = psSolid; break; // стиль линии
case 1: Canvas->Pen->Style = psDash; break;
case 2: Canvas->Pen->Style = psDot; break;
case 3: Canvas->Pen->Style = psDashDot; break;
case 4: Canvas->Pen->Style = psDashDotDot; break;
}
Canvas->Rectangle(x, y, x + random(400), y + random(400)); }
Таблица 7
Уровень
Действие
Методы
Свойства
Высокий
Определяет текущую позицию пера
MoveTo
PenPos
Рисует прямую до заданной точки
LineTo
PenPos
Рисует прямоугольник заданного размера
Rectangle
Рисует эллипс заданного размера
Ellipse
Выводит текстовую строку
TextOut
Задает высоту текстовой строки
TextHeight
Задает ширину текстовой строки
TextWidth
Вывод текста внутри прямоугольника
TextRect
Заливка указанного прямоугольника цветом и текстурой текущей кисти
FillRect
Заливка области канвы (произвольной формы) заданным цветом
FloodFill
Средний
Используется для установки цвета, стиля, ширины и режима пера
Pen
Используется для установки цвета и текстуры при заливке графических фигур и фона канвы
Brush
Используется для установки шрифта заданного цвета, размера и стиля
Font
Используется для чтения и записи цвета заданного пикселя канвы
Pixels
Копирует прямоугольную область канвы в режиме CopyMode
CopyRect
CopyMode
Копирует прямоугольную область канвы с заменой цвета
BrushCopy
Рисует битовый образ, пиктограмму, метафайл в заданном месте канвы
Draw
Рисует битовый образ, пиктограмму или метафайл так, чтобы целиком заполнить заданный прямоугольник
StretchDraw
Используется как параметр при вызове функций Windows GDI
Handle
Здесь в методе FormActivate() формы задается интервал времени, через который происходит событие OnTimer компонента TTimer, осуществляющее перерисовку прямоугольника на форме.
В качестве примера рассмотрим рисование графика функции y = f(x). Пусть x принимает значения из промежутка [x1, x2], а y изменяется в промежутке [y1, y2]. График функции будем рисовать в прямоугольнике на экране с координатами верхнего левого угла (Х1, Y1) и нижнего правого угла – (X2, Y2). Таким образом, необходимо выполнить масштабирование: преобразование координат точек функции (x, f(x)) в соответствующие координаты точек (пикселей) заданного прямоугольника на экране. В процессе преобразования будем учитывать, что ось Oy на экране имеет направление сверху вниз. Поэтому изменим направления оси Oy в заданном прямоугольнике на экране на привычное для нас направление снизу вверх. Для преобразования координат точки функции (x, y) в координаты соответствующего пикселя (X, Y) на экране можно использовать следующие формулы:
X = X1 + [(X2 - X1) / (x2 - x1)](x - x1);
Y = Y2 - [(Y2 - Y1) / (y2 - y1)](y - y1).
Ниже приводится фрагмент программы для рисования графика функции y=cos x, где x изменяется в промежутке [0, 2π]. График будем рисовать на всей поверхности компонента Image1, т. е. x [0,Image1->Width], а y [0,Image1->Height]. Получим следующий код:
#define pi 3.14159
double X,Y; // координаты точек функции
int PX,PY; // координаты пикселей на экране
Y=cos(0);
PY=Image1->Height-Image1->Height/2*(Y+1);
Image1->Canvas->MoveTo(0,PY); // перемещаем перо в начальную
// точку рисования графика
for(X=0.05;X<=2*pi;X+=0.05){
Y=cos(X);
PX=Image1->Width/(2*pi)*X;
PY=Image1->Height-Image1->Height/2*(Y+1);
Image1->Canvas->LineTo(PX,PY);
}
Графические файлы. Приложения C++Builder поддерживают загрузку и сохранение рисунков и графиков в файлах изображений. Для загрузки изображения из файла можно использовать метод LoadFromFile(). Чтобы сохранить изображение в файле, используется метод SaveToFile(). Единственным параметром этих методов является имя файла. Рисунок распознает стандартное расширение файлов битовых образов .bmp и создает свою графику как объект класса TBitmap, а затем вызывает метод LoadFromFile загрузки изображения из файла с указанным именем.
Ниже приводится пример приложения, иллюстрирующего работу с графическим компонентом TImage. На рис. 18 приведена форма приложения в процессе проектирования.
Рис. 18. Форма приложения в процессе проектирования
Обслуживание палитр. Компонентам, содержащим графические изображения, может потребоваться взаимодействие с Windows и экранным драйвером, чтобы обеспечить надлежащее отображение данных компонентов. Реализация палитр призвана обеспечить, чтобы самое верхнее активное окно использовало полную цветовую палитру, в то время как фоновые окна максимально использовали оставшиеся цвета палитр.
C++Builder не содержит самостоятельных средств для создания и обслуживания иных палитр, кроме палитры битовых образов. Однако можно получить дескриптор некоторой палитры с помощью метода GetPalette(), а затем воспользоваться методом Windows API CreatePalette(). Компоненты C++Builder автоматически поддерживают механизм реализации палитр. Таким образом, если компонент имеет палитру, можно воспользоваться двумя методами GetPalette() и PaletteChanged(), наследованными от базового компонентного класса TControl, чтобы управлять тем, как Windows обращается с этой палитрой.
Когда компонент ассоциируется с некоторой палитрой посредством перегрузки метода GetPalette(), C++Builder автоматически берет на себя реакцию на сообщения Windows от палитр с помощью метода PaletteChanged().
Внеэкранные битовые образы. Методика программирования графических приложений заключается в создании внеэкранного битового образа, заполнении его конкретным изображением и копировании изображения из битового образа в экранное окно. Благодаря этому уменьшается заметное глазу мерцание экрана монитора, вызванное повторным рисованием непосредственно в экранном окне. C++Builder позволяет создавать объекты класса TBitmap для представления изображений файлов и других ресурсов, которые также способны работать как внеэкранные изображения.
C++Builder предусматривает четыре способа копирования изображений, которые приведены в табл. 8.
Таблица 8
Требуемый результат
Метод
Полное копирование графики
Draw
Копирование с масштабированием
StretchDraw
Копирование прямоугольного участка канвы
CopyRect
Копирование с растровыми операциями
BrushCopy
Далее приводится пример копирования изображения в обработчике события для кнопки:
{ShowMessage("Нельзя загрузить или отобразить изображение");
}
delete pBitmap;
}
Анимация.Для воспроизведения анимации, состоящей из последовательного отображения кадров из стандартных avi-файлов Windows, используется компонент Animate из страницы Win32 Палитры компонентов. Последовательность действий может быть следующей:
Animate1->FileName=”p.avi”;
Animate1->play(1, Animate1->FrameCount,1);
Animate1->stop();
Для обеспечения процесса мультимедиа и воспроизведения звука и анимации при отображении war-, rmi-, mid-файлов используется компонент MediaPlayer (страница System).
При анимации широко используется невидимый компонент Timer. При этом в одном из методов, например FormCreate() или Button1Click(), устанавливается частота прерывания: Timer1->Interval=time;
Компонент Timer генерирует событие OnTimer, в обработчике которого осуществляется перерисовка.
Вопросы
1. Как установить режимы рисования на канве? Какие режимы есть у пера?
2. Как очистить поверхность графического компонента Image?
3. Как установить цвет и ширину линии, которой рисуется график функции?
4. Назовите основные методы для рисования класса Canvas.
5. Назовите основные события графических компонентов Image и PaintBox.
6. Как вывести текст в графические компоненты?
7. Как вывести на графическом экране:
a) точку в позицию, указанную курсором мыши;
б) свою фотографию, загруженную из графического файла;
в) установить толщину линии, ее цвет и провести линию указанной длины и под заданным углом.
8. Как установить цвет рисунка при использовании графики и нарисовать указанным цветом две касающиеся внутренним образом окружности?
9. Опишите методику анимации изображения.
10. Какой режим пера Pen используется для удаления рисунка при повторном его рисовании?
11. Какие свойства имеет компонент Timer?
12. Назовите основные события мыши.
13. Как в программе распознать координаты курсора мыши?
14. Как распознать нажатую кнопку мыши?
15. Когда наступают события мыши OnStartDrag, OnDragOver, OnDragDrop, OnEndDrag? Что можно распознать при обработке этих событий?
16. С помощью какой клавиши клавиатуры можно перемещать фокус с элемента на элемент?
17. Какие способы вывода графической информации Вы знаете?
18. Какие проблемы могут возникнуть при рисовании непосредственно на форме? Как их преодолеть? Почему такие проблемы не возникают при использовании компонента Image?
19. С помощью какого метода класса Canvas можно вывести текст?
Упражнения
1. Нарисовать график функции y = sin x.
2. Нарисовать график функции y = -2x2 + 3x.
3. Вывести аналоговые часы (со стрелками). Предусмотреть кнопку для запуска и остановки часов. Использовать функцию Time() и класс TDataTime для получения текущего времени.
4. «Летающий шарик». По достижении границы компонента он отражается от границы по правилам отражения. Предусмотреть кнопку остановки и запуска шарика.
5. Точка равномерно движется по окружности. Предусмотреть возможность увеличения скорости движения.
6. Построить простейший графический редактор с возможностью выбора цвета рисования.
7. Равносторонний треугольник вращается вокруг своего центра. Предусмотреть возможность увеличения скорости вращения.
8. Изобразить прямоугольник (квадрат), вращающийся вокруг своего центра. Предусмотреть возможность увеличения скорости вращения.
9. Вращаются два отрезка, каждый вокруг своей концевой точки. Предусмотреть возможность изменения скорости вращения каждого отрезка отдельно.
10. «Ипподром». Играющий выбирает одну из трех лошадей, состязающихся на бегах, и выигрывает, если его лошадь приходит первой. Скорость передвижения лошадей на разных этапах выбирается программой с помощью датчика случайных чисел.
11. «Игра в слова». Программа выбирает слово и рисует на экране столько прочерков, сколько букв в слове. Отгадать, какое слово загадано программой. За один ход играющий указывает одну букву. Если буква не угадана, то играющий теряет одно очко. В начальный момент у играющего 15 очков.
12. Требуется ввести курсор в область экрана (небольшой круг), расположение которого неизвестно играющему. Если курсор приближается к области, то его цвет становится ярче, если удаляется, то тускнеет.