Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Прикладное программирование на CC++ с нуля до мультимедийных и сетевых приложений
.pdf
Графические возможности TURBO C++ 51
åé int fseek(FILE*,long, int). Первый аргумент указывает на файл, с которым
нужно работать. Третий аргумент обязан иметь значение системной константы
SEEK_SET для текстовых файлов (а другие мы не рассматриваем и рассматривать не будем). Именно эта конструкция должна стоять на месте последнего
параметра функции. Второй аргумент задает номер позиции, на которую
должно быть установлено файловое окно, то есть номер байта, отсчитанный от
начала файла. Функция long ftell(FILE*) возвращает номер текущей позиции в
файле. Функция void rewind(FILE*) устанавливает файловое окно в начало
файла, то есть делает то же, что и функция fseek(p,0L, SEEK_SET), åñëè ð —
указатель на файл. Числовая константа 0L есть «длинный ноль» — число 0
типа long.
Графические возможности TURBO C++
В текстовом режиме, с которым мы до сих пор работали, рабочий экран
представляет собой совокупность строк и столбцов. Обычно на экране размещено 25 строчек и 80 столбцов. В каждой позиции может быть отображен
только один из алфавитно-цифровых символов клавиатуры. Гораздо большие
возможности предоставляет графический режим.
Прежде чем подробно знакомиться с графикой, следует отметить, что графические средства не включаются в единый стандарт языка С. Это значит,
что в тех или иных системах программирования такие средства могут быть
реализованы по-разному или вообще отсутствовать. То, о чем будет идти речь
ниже, относится именно к системе TURBO C++ 1.0. В современных объектно-ориентированных системах типа Borland C++ графика организована вообще совершенно иначе.
Графические возможности системы определяются аппаратным и программным обеспечением компьютера. Аппаратные средства включают в себя
монитор и видеоадаптер. Основными характеристиками монитора являются
возможность графического отображения и цветность. Современные мониторы, как правило, предоставляют возможность работы с графикой. Вообще говоря, и многоцветный режим работы дисплея поддерживается большинством
мониторов, однако имеются и мониторы, работающие только в монохромном
режиме, обеспечивающие при этом высокое разрешение. Видеоадаптерами
называются электронные схемы, обеспечивающие работу монитора. Промежуточным звеном — интерфейсом между программой и видеоадаптером — является программа управления последним. Такая программа называется драйвером. Драйверы допускают работу в различных видеомодах. Видеомоды различаются разрешающей способностью (количеством точек на экране по
вертикали и горизонтали), количеством отображаемых цветов и количеством
видеостраниц. Что такое видеостраницы и как с ними работать, любознательный читатель может узнать самостоятельно, пользуясь литературой, например
книгой [3], и справочной системой.
Драйверы видеоадаптера могут быть самыми разнообразными, в зависи
мости от того, работу каких систем они поддерживают. В системе программи
-
-

52 Глава 1. Язык программирования С
рования TURBO Ñ существует достаточно большой набор таких драйверов,
находящихся в каталоге с именем BGI. Файлы, в которых записаны драйверы,
имеют расширение bgi от фирменного названия BORLAND GRAPHIC
INTERFACE. Мы будем ориентироваться на работу с драйвером egavga.bgi,
обеспечивающим работу монитора в режиме VGA. Кроме того, везде далее будем предполагать, что графические процедуры реализуются в графической
моде VGAHI (режим VGA с высоким разрешением). В этой моде экран представляет собой совокупность точек (пикселей) 640 × 480 по горизонтали и вертикали соответственно. В каждом пикселе возможно отображение одного из
16 цветов. Мода VGAHI может оперировать с двумя видеостраницами. Таким
образом, любой пиксель имеет свои координаты — целые числа, изменяющиеся по горизонтали от 0 до 639 включительно и по вертикали от 0 до 479.
Система координат несколько необычна. Начало ее — точка с координатами
0,0 находится в левом верхнем углу экрана так, что ось ОХ направлена сверху
вниз.
Для операций с графикой к программе следует подключить соответствующий заголовочный файл. Если вы собираетесь рисовать, не забудьте вставить
в программу препроцессорную инструкцию:
#include<graphics.h>
Что же можно делать в графическом режиме? Перечислим полный список
таких возможностей, и если в следующем материале этой книги вы не найдете
нужных вам сведений по какому-то из этих пунктов, обратитесь к справочной
системе TURBO Ñ или найдите книгу [3].
Итак, вам предоставляется возможность:
1. Закрашивать всю рабочую область экрана одним из доступных цве-
тов — устанавливать цвет фона.
2. Ставить и удалять пиксель с любыми допустимыми координатами и
любого допустимого цвета.
3. Соединять две любые точки экрана прямой линией заданного цвета.
Линии могут быть нескольких типов и нескольких толщин.
4. Рисовать прямоугольники, окружности, эллипсы и их дуги.
5. Закрашивать замкнутые области экрана. Закраска может быть несколь-
ких типов.
6. Хранить в памяти прямоугольные области экрана и выводить их в про-
извольном месте экрана.
7. Манипулировать несколькими страницами видеопамяти.
Кроме того, к графике отнесены операции вывода на экран текстов с использованием различных размеров и типов шрифтов и различной ориентации
(по горизонтали и по вертикали).
Перед первой графической операцией графика должна быть инициализирована — загружен необходимый драйвер и установлена необходимая мода.
Инициализация производится функцией:
void initgraph(int*, int*, char*)

Графические возможности TURBO C++ 53
Первый параметр является указателем на целую переменную, которая
предварительно должна получить значение номера графического драйвера. По
мнению автора, здесь допущена некоторая путаница. На самом деле речь идет
не о номере драйвера, а о номере режима, причем этот номер устанавливается,
как правило, не числом, а системной константой. Так, для подключения режима VGA следует сначала в программе выполнить присваивание gd=VGA и на
место первого аргумента функции initgraph поместить &gd. Второй параметр
является адресом переменной, которой присваивается значение номера графической моды. Здесь также удобнее обратиться не к числу, а к системной переменной. Для работы в моде высокого разрешения вы должны выполнить присваивание gm=VGAHI и на место второго аргумента поставить &gm. Третий аргумент является строкой, в которой указан полный путь к драйверу, например:
"C:\\LANGUAGE\\TC\\BGI"
В данном случае считается, что драйвер egavga.bgi находится в подкаталоге BGI подкаталога ТС каталога LANGUAGE диска С:. Дорогой читатель! Вот
вам вопрос на тестирование вашей внимательности и памяти: почему в указании пути мы разделяем имена каталогов двумя обратными чертами, а не одной? Впрочем, можно обойтись и без указания пути вообще. Для этого скопируйте файл egavga.bgi из того места, где он находится, в ваш рабочий каталог
и на месте третьего аргумента функции инициализации графики поставьте
пустую строку «».
В случае успешной инициализации графики произойдет переход из текстового режима в графический, полностью очистится экран, и вы можете
«брать в руки карандаши и ластик» и приступать к рисованию. Однако, прежде чем учиться рисовать, примите рекомендацию. Перед выходом из программы или в любом другом месте, закончив работу с графикой, вернитесь в текстовый режим. Закрытие графики выполняется очень просто. Напишите выражение closegraph();, и все. Но помните, что при этом графическое
изображение с экрана исчезнет.
Рассмотрим две первые графические операции установки цветов. Цвета
задаются номерами — значениями типа int или символическими константами:
0 BLACK 8 DARKGRAY
1 BLUE 9 LIGHTBLUE
2 GREEN 10 LIGHTGREEN
3 CYAN 11 LIGHTCYAN
4 RED 12 LIGHTRED
5 MAGENTA 13 LIGHTMAGENTA
6 BROWN 14 YELLOW
7 LIGHTGRAY 15 WHITE.
Установка цвета фона производится функцией void setbkcolor(int), где аргумент задает цвет (можно писать как номер, так и название цвета в соответствии с приведенной выше таблицей). Цвет рисуемых объектов — линий окружностей, прямоугольников и т. д. устанавливается функцией void setcolor(int).

54 Глава 1. Язык программирования С
Теперь рассмотрим построение так называемых графических примитивов.
Для того чтобы поставить точку с заданными координатами и заданного цвета, используйте функцию void putpixel(int, int. int). Два первых аргумента задают Õ è Y координаты точки, а третий — ее цвет. Вы можете определить цвет
точки экрана с помощью функции unsigned getpixel(int, int). Аргументами являются координаты точки. Функция возвращает номер цвета, который имеет
точка с этими координатами в текущий момент.
Для того чтобы поместить «перо» в точку с заданными координатами, вы
можете употребить функцию void moveto(int, int). Здесь аргументы — координаты, в которые нужно установить перо. Функция void line(int, int, int, int) рисует прямую линию из точки с координатами, заданными первой парой аргументов, в точку, заданную второй парой аргументов. Если же вы хотите провести прямую из текущей позиции в заданную, то это можно сделать
функцией void lineto(int, int). Наконец, может возникнуть задача проведения
прямой из текущей позиции в точку, смещенную на ΔX точек по горизонтали
и на ΔY точек по вертикали. Выполняйте эту операцию функцией void linerel
(int, int). Аргументы здесь задают смещения.
Как можно видеть, параметры, задающие координаты на экране, определяются целыми значениями типа int. В процессе построения графиков в результате различных математических вычислений координаты могут быть получены в виде вещественных чисел. Ничего страшного. Система сама позаботится о преобразовании типов. Нужно только помнить, что преобразование
будет сделано путем округления. Кроме того, программисту следует позаботиться о том, чтобы рисуемое изображение не выходило за рамки рабочей области экрана. В ряде случаев выход за «разрешенные границы» может привести к непредсказуемым последствиям, хотя, как правило, следствием такой ситуации будет только то, что вы не увидите желанного изображения или его
части.
Чтобы нарисовать прямоугольник, нужно задать две пары чисел — координаты левой верхней и правой нижней вершин прямоугольника — и использовать их в качестве аргументов функции void rectangle(int, int, int, int) соответственно. Можно провести ломаную через заданные точки с помощью
функции void drowpoly(int, int*). Первый аргумент функции задает число точек, через которые нужно провести ломаную.
Второй аргумент может быть именем массива целого типа, в котором записаны попарно Õ è Y координаты точек. Теперь настала пора написать первую программу с графикой:
#include<graphics.h>
int grdr=VGA,grmd=VGAHI;
void main()
{int mas[] ={70,75,84,96,120,100,90,100};
initgraph(&grdr,&grmd,"");
setcolor(RED);
drowpoly(4,mas);
getch();
closegraph(); }

Графические возможности TURBO C++ 55
Массив mas содержит восемь чисел, которые представляют собой пары
координат четырех точек, через которые проводится ломаная. Цвет фона не
установлен, а следовательно, останется черным. Основной цвет определен как
RED. Стало быть, сама ломаная рисуется красным цветом. Наличие перед закрытием графики функции getch() обеспечивает сохранение рисунка на экране до тех пор, пока не будет нажата какая-либо клавиша.
Рассмотрим теперь изображение кривых второго порядка. Функция void
circle(int, int, int) рисует окружность. Два первых параметра задают координаты центра, последний — радиус окружности. Функция, рисующая дугу окружности, имеет пять аргументов типа int и может быть вызвана в виде
àrñ(õ,ó,startangle,endangle,radius). Здесьхиу—координаты центра, radius —
радиус окружности. Второй и третий аргументы задают начальный и конечный углы, в пределах которых рисуется дуга. Углы задаются в градусах и отсчитываются от положительного направления оси абсцисс против часовой
стрелки.
Для рисования дуги эллипса можно вызвать функцию:
ellipce(x,ó,startangle,endangle,radiusx,radiusy)
В отличие от функции arc здесь последними параметрами задаются горизонтальная и вертикальная полуоси.
Пожалуй, наиболее интересные возможности графики в TURBO C++ сосредоточены в функциях доступа к видеопамяти. Наверное, понятно, что информация о состоянии каждой точки графического экрана закодирована в
цифровом виде и хранится в памяти компьютера. Память, отведенная под
хранение состояния экрана, может быть названа видеопамятью. Любой прямоугольный фрагмент экрана может быть сохранен в памяти в виде массива
атрибутов пикселей, его составляющих. В этой связи такую «заплатку» на экране можно перенести в любое другое место рабочей области. Для этого необходимо выполнить следующие шаги:
1. Определить объем памяти, необходимый для запоминания «заплатки».
Используется функция unsigned imagesize(int left, int top, int right, int bottom).
Здесь left — Х-координата левой стороны прямоугольника, top — Y-координата верхней стороны прямоугольника, right — координата правой стороны,
bottom — координата нижней стороны. Функция возвращает занимаемый прямоугольником объем памяти, выраженный, разумеется, в байтах.
2. Выделить (зарезервировать) необходимую память. Здесь работает функция void* malloc(unsigned size). Функция резервирует size байтов памяти и возвращает адрес начала зарезервированной памяти. Обратите внимание на совсем экзотический тип функции. Дословно этот тип void* следовало бы назвать «указатель на никакой тип», однако более верно назвать его указателем
на что угодно. Функции резервирования памяти (это не только malloc,ине
только для графических работ) требуют подключения заголовочного файла
alloc.h. Обратим внимание на то, что после того как вы закончили работать с
выделенной памятью, желательно освободить память, вызвав функцию
free(point).

56 Глава 1. Язык программирования С
3. Записать в выделенную память информацию. Функция void getimage(int
left, int top, int right, int bottom, void* point) помещает информацию о «заплат-
ке» в память, начиная с адреса, заданного последним параметром. Первые аргументы те же, что и у функции imagesize.
4. Скопировать прямоугольник в новое место экрана можно с помощью
функции void putimage(int left, int top. void* point, int sort). Первый и второй параметры задают новые координаты левого верхнего угла копии «заплатки».
С третьим аргументом, наверное, все ясно — это все тот же адрес участка памяти, где сохранена «заплатка». Последний аргумент управляет режимом копирования. В частности, если он имеет значение 0 или символической константы COPY_PUT, то копия «заплатки» просто освобождает себе место, стерев занимаемую область. Если sort принимает значение 1 или XOR_PUT, то
двукратное применение putimage с этим значением восстанавливает прежние
пиксели. Последней возможностью следует пользоваться при отображении
движущихся объектов для восстановления предыдущего состояния фонового
рисунка экрана. Есть еще и некоторые другие режимы копирования.
Проиллюстрируем последний, довольно сложный материал программой:
#include<graphics.h>
#include<alloc.h>
int gd=VGA,gm=VGAHI;
void main()
{ void* point; unsigned size;
initgraph(&gd,&gm,"");
circle(70,70,10);
size=imagesize(60,60,80,80);
point=malloc(size);
getimage(60,60,80,80,point);
putimage(160,160,point,0);
getch(); free(point); closegraph(); }
В программе рисуется окружность с центром в точке с координатами
х=60, у=60. Затем, с использованием средств прямого доступа к видеопамяти,
воспроизводится копия окружности с центром в точке х=160, у=160.
Теперь рассмотрим возможности вывода текста на экран в графическом
режиме. Функция void outtext(char*) выводит текст на графический экран, начиная с текущей позиции, то есть с того места, где находился графический
курсор в момент выполнения функции. Аргументом функции является указатель на символ. Таким образом, этот параметр должен быть именем символьного массива, содержащего печатаемую строку, или непосредственно строкой
текста, взятой в кавычки. Функция void outtextxy(int, int, char*) отличается от
предыдущей тем, что выводит текст, начиная с графической позиции, координаты которой заданы двумя первыми параметрами.
В стандартном режиме текст выводится неким «обычным» шрифтом в горизонтальную строку. Можно, однако, и изменить шрифт и вывести текст в
виде вертикальной строки. Изменение шрифта, направления вывода и размера символов выполняет функция void settextstyle(int font, int dir, int size). Первый аргумент font задает шрифт печати и может принимать значения 0, 1, 2, 3

Графические возможности TURBO C++ 57
и 4. Этим номерам соответствуют пять возможных шрифтов, включая, например, готический. Для работы с различными шрифтами системе должны быть
доступны соответствующие драйверы, которые имеют расширение .chr и расположены там же, где и графические драйверы с расширением .bgi. По этой
причине, если вы отважились на красивое оформление вашей графики с помощью различных шрифтов, то в функции инициализации графики необходимо указать путь к каталогу BGI системы TURBO C++ или поместить соответствующий драйвер шрифта в рабочий каталог. Кстати, по названию
.chr-драйверов вы поймете, каким шрифтам они соответствуют. Второй параметр — dir может принимать значения 0 или 1. В первом случае текст выводится в горизонтальную строку, а во втором — по вертикали снизу вверх. Третий аргумент задает размер символов, изменяющийся от очень маленького —
0 до очень большого — 14.
Пример работы с различными шрифтами дает следующая программа:
#include <graphics.h>
void main()
{ int gd=VGA,gm=VGAHI,font,dir,size;
puts("FONT (0 —- 4)="); scant ("%d",&font) ;
puts("DIR (0,1)="); scanf('%d",&dir);
puts("SIZE (0 —- 14)="); scanf("%d",&size);
initgraph(&gd,&gm,"");
outtextxy(150,150."THIS is the font");
getch(); closegraph(); }
Реализовав эту программу, вы сможете опробовать различные варианты
шрифтов, направлений печати и размеров символов и получите при этом немалое эстетическое удовольствие, за что мы с вами должны поблагодарить
разработчиков графических средств системы TURBIC++.
На этом ваше краткое знакомство с программированием на языке С заканчивается. На очереди изучение современного инструмента разработки
программ на C/C++ — Borland C++ Builder.

Глава 2
ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ
ПРОГРАММИРОВАНИЕ И С++ BUILDER
Техника работы в С++ Builder
В настоящем разделе мы научимся («в нулевом приближении») работать с
интегрированной средой разработки приложений Borland C++ Builder. Пакет
является результатом развития системы программирования TURBO C++, ориентированной на WINDOWS. Весь материал относится к реализации системы
в пятой и шестой версии пакета. Изучение техники работы с пакетом начнем
с непосредственного создания простого приложения. В соответствии с традициями обучения работе с новыми для пользователя системами программирования поставим себе задачу разработать приложение, которое всего лишь выводит на экран приветствие при своем запуске.
Прежде всего, создадим с помощью проводника Windows или любого файлового менеджера специальную папку для хранения проекта приложения.
Пусть это будет каталог NewFold в корневой директории диска Ñ. То есть
DOS-овский путь к папке выглядит как C:\NewFold. Теперь запускаем Builder
и попадаем в его стартовое окно, изображенное на рис. 2.1.
По умолчанию программа открывается в состоянии, готовом к разработке
32-разрядного Windows-приложения, с чем мы и согласимся. Давайте для начала сохраним наш пока пустой проект в подготовленной папке. Для этого из
пункта меню File нужно вызвать подпункт Save all или воспользоваться комбинацией клавиш Ctrl+Shift+S. Откроется окно перемещений по файловой
системе, где вы должны войти в нашу папку NewFold и нажать кнопку Сохра-
íèòü. Тем самым будет создан и сохранен файл главного текстового модуля с
именем Unit1.cpp. Имя, конечно, можно и изменить, но мы оставим предлагаемое по умолчанию. Затем здесь же будет предложено создать и сохранить
файл проекта Project1.bpr. Давайте и с этим согласимся. Теперь, если вы заглянете в папку проекта, вы обнаружите там готовый, но пока пустой проект,
состоящий из нескольких файлов-заготовок. Самое главное то, что теперь
можно закрыть Builder и назавтра или через год снова начать работу с проектом. Давайте закроем и снова откроем программу. Вызвать проект можно через пункт меню File, подпункт Open Project (Ctrl+F11), перейдя далее в папку
проекта и открыв тот самый файл проекта Project1.bpr. Можно поступить и

Техника работы в С++ Builder 59
Ðèñ. 2.1
по-другому. Откройте пункт File, подпункт Reopen. Здесь вы увидите ссылку
на нужный файл и, возможно, на другие недавно используемые файлы.
Итак, проект загружен. Давайте посмотрим, что система успела сделать
автоматически без вашего участия. В папке проекта образовано несколько
файлов, среди которых для нас интересен главный текстовый модуль
Unit1.cpp. Для того, чтобы посмотреть содержимое этого файла, можно открыть его окно. Оно находится под окном формы Form1 на представленном
выше рисунке. Щелкните мышью по области, частично скрытой формой, то
есть в зоне, где написано Insert. Откроется листинг, представленный далее.
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//—————————————————————————————————————#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//—————————————————————————————————————__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}

60 Глава 2. Объектно-ориентированное программирование
Пока здесь практически ничего нет. Правда, мы уже понимаем, что к
основному модулю подключаются два заголовка vcl.h è Unit1.h. Строка
TForm1 *Form1; означает, что создается указатель Form1 на некий класс.
Это — класс так называемой формы. Подробно о классах мы поговорим
позднее, а сейчас просто примем к сведению это слово. Форма представляет
собой обычное окно Windows, которое будет открываться при запуске изготовленного приложения. В рабочем окне формы можно размещать различные управляющие элементы, выводить результаты расчетов, рисовать графики и делать многое другое. Пока же в нашей форме вообще ничего нет, и
соответствующее окно будет иметь только стандартный инструмент закрытия — крестик в правом верхнем углу.
Хотя мы называем проект пустым, из него можно изготовить приложение, которое можно запустить на исполнение и которое, естественно, ничего
делать не будет. Выберите пункт меню Run и подпункт с тем же названием
или просто нажмите функциональную клавишу F9 на клавиатуре. Система
выполнит компиляцию программы, редактирование связей (линковку) и запустит приложение. С открывшимся окном программы можно сделать только
одно действие — закрыть его. Ведь наша первая программа ничего делать не
умеет. Если вы заглянете в папку проекта, то обнаружите там новые файлы, в
частности, исполняемый файл программы Project1.exe. Это и есть наша программа, которую можно запускать уже и без Builder'а и даже на другом компьютере.
Теперь пойдем дальше и разместим на форме управляющую кнопку. Для
начала сделайте так, чтобы активным стало окно формы, например, свернув
окно текстового модуля. Нам понадобится обратиться к панели так называемых визуальных компонентов. Эта панель (см. рисунок выше) имеет множество вкладок, среди которых по умолчанию открыта вкладка Standard. Она-то
нам и нужна. Найдите на вкладке маленькую картинку, изображающую кнопку с названием ÎÊ, сделайте по ней щелчок левой кнопкой мыши, переведите
мышиный курсор в любое место рабочего поля формы и снова сделайте щелчок мышью. В результате на форме появится кнопка с именем Button1. Сделайте по ней двойной щелчок, и вы снова попадете в окно Unit1.cpp. Вы обнаружите, что к предыдущему тексту добавлена конструкция:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
}
Это — функция обработки события, которое заключается в нажатии
мышкой на управляющую кнопку (разумеется, если программа запущена).
На секунду прервем свою увлекательную работу по разработке приложения и примем некоторые меры безопасности — сохраним изменения, сделанные в проекте. Для этого снова нажмем одновременно три клавиши
Ctrl+Shift+S. Рекомендуется делать сохранения почаще во избежание неприятностей, которые могут возникнуть, например, при перебоях с электроэнер
гией. Вернемся в окно главного текстового модуля. Кстати, чтобы сразу по
-
-
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
