ТЕХНОЛОГИИ ПРОГРАММИРОВАНИЯ
ПРОГРАММИРОВАНИЕ В СРЕДЕ VISUAL C++ 6
Лабораторная работа №2
Тема: Мастера Классов ClassWizard.
Цель: Получить практические навыки создания простых Win32 API-приложений в среде Microsoft Visual C++ с использованием мастеров классов..
Основное содержание работы.
Создать с использованием мастера Class Wizard простое приложение Win32 API, в котором рисуются графические фигуры и выводится текст с помощью функций API.
Краткие теоретические сведения
-
Мастер ClassWizard
Высвечивает
список оста-льных дей-ствий, кото-рые
можно выполнить
Панель ClassWizard Bar выглядит так.
Позволяет
выбрать класс или глобальную функцию,
к редактированию которой вы хотите
преступить. Фильтр
того, что вы хотите редактировать в
этом классе , по умолчанию выводит все
функции класса для выбора Список
всех членов-функций для данного класса
или список всех глобальных функций,
выберите одну из них
Действие
по умолча-нию для этого органа управления.
Переход к текущей позиции редактирования,
к началу реализации функции класса или
глобальной функции.
Этот орган управления служит для облегчения навигации в тексте программы.
Можно выбрать класс, затем функцию класса, либо имя глобальной
функции, щелкните на кнопку “действие по умолчанию” и перейти в
редакторе к тому месту в программе, где находится начало
реализации выбранной функции. Вы можете изменить что-то в декларации функции или класса.
Дополнительно этот орган управления предоставляет возможности, список которых можно получить, нажав на стрелку вниз.
Переход
к реализации функции(definition) или
к декларации(описанию) данной
ффуфункции(Declarartion) Добавить
в выбранный класс новую функцию или удалить
выбранную с помощью WizardBar
функцию класса
Открыть
заголовочный файл выбранного класса
для редактирования
.
Добавить
новый класс Позволяет
переходить от текста реализации одной
функции класса к другой в алфавитном
порядке.
При удалении какой-либо функции класса с помощью средств Visual C++, сам код функции не удаляется, а только заключается в комментарии; окончательное решение на удаление остается за вами.
Е
Введите
здесь тип значения возвращаемого
функцией Введите
имя функции +параметры , если они есть
Тип
доступа к функции Если
необходимо, выберите тип функции-
статическая или виртуальная
Сгенерированная функция всегда появится в декларации класса. В конце того файла, где находится реализация функций данного класса, появится “заготовка” для данной функции- просто пустая функция. Практически аналогично добавление новой переменной в класс. Для этого надо в Workspace Viwer выбрать вкладку Class View и щелкнуть на имени класса правой кнопкой мыши. В появившемся всплывающем меню выбрать пункт Add Member Variable…
Для облегчения внесения в проект данных о новом классе можно воспользоваться средствами, которые предоставляет ClassWizard. Вызвав одну из возможностей с именем New Class, мы получим окно New Class.
В этом окне в поле Class type укажите тип мастера генерации класса. Для приложений типа Win32 Application – это Generic Class.
В группе Class information в поле Name укажите имя нового класса, а в поле File name- имя файла с реализацией данного класса.
В группе Base class в поле Derived From укажите имя базового класса (если новый класс наследуется , а в поле As – тип наследования.
При создании класса будет сгенерирован прототип класса, состоящий из определения класса и пустого конструктора и деструктора.
Затем в класс можно добавить члены-данные и члены-функции, как было показано выше.
-
Графический интерфейс устройства (gdi)
Графический интерфейс устройства (Graphics Device Interface-GDI) – это подсистема Windows, отвечающая за работу с графическими устройствами. На системном уровне GDI достаточно сложен и включает в себя более 200 функций. Для выполнения приложением практически любой графической операции необходимы вызовы функций GDI.
Функции GDI- это обычные API функции, однако VC++ предлагает и встроенную поддержку GDI в виде библиотеки классов MFC.
GDI – это графическая библиотека, предназначенная, прежде всего, для решения задач нижнего уровня. GDI находится в полном неведении о проблемах графики интерфейса пользователя, таких как ширина заголовка окна или цвет затененного края кнопки. На вопросы такого сорта отвечает ОС Windows, которая, в свою очередь, используя GDI, размещает графические элементы на экране компьютера. Связующим звеном между программным кодом и областью рисования (drawing area) является контекст устройства.
-
Контекст устройства (dc)
Контекст устройства можно представить как некоторую подсистему, которая принимает от программы инструкции по выводу графики и транслирует их в форму, понятную устройству вывода. Если программа говорит контексту устройства - нарисовать в определенном месте экрана красный квадрат, тот, в свою очередь, отдаст соответствующий запрос драйверу видеоадаптера, который произведет необходимые модификации в памяти видеоплаты. Таким образом, контекст устройства призван скрыть от приложения конкретные детали, связанные с аппаратной частью устройства. Контекст устройство позволяет сделать приложение действительно независимым от типа конкретного устройства вывода. Это означает, что процедуры, посылающие что-либо на принтер, часто могут быть теми же, что и процедуры вывода на экран.
Для того, чтобы что-то нарисовать(вывести) необходимо получить контекст устройства (DC). Во всех случаях, кроме обработки сообщения WM_PAINT, для этой цели используется функция GetDC().
HDC GetDC(HWND hWnd);
где hWnd - handle окна
Для получения контекста устройства для обработчика сообщения WM_PAINT используется функция BeginPaint()
HDC BeginPaint(
HWND hwnd, // handle окна
LPPAINTSTRUCT lpPaint // структура, содержащая информацию для рисования в кли-
// ентской области окна
);
За исключением самого первого сообщения WM_PAINT, посылаемого окну при вызове UpdateWindow(), эти сообщения будут посылаться в следующих случаях:
- при изменении размеров окна;
- если рабочая область была скрыта меню или окном диалога, которое в данный момент закрывается;
- при использовании функции ScrollWindow();
- при принудительной генерации сообщения WM_PAINT вызовом функций InvalidateRect() или InvalidateRgn().
-
Вывод текста
Для вывода текста в области окна можно использовать функции TextOut() и DrawText().
BOOL TextOut(
HDC hdc, // handle to DC
int nXStart, // x-coordinate of starting position
int nYStart, // y-coordinate of starting position
LPCTSTR lpString, // character string
int cbString // number of characters
);
int DrawText(
HDC hDC, // handle to DC
LPCTSTR lpString, // выводимый текст
int nCount, // длина выводимой строки, если передать -1,то длина вычисляется автоматически
LPRECT lpRect, // область, внутри которой будет выведена строка
UINT uFormat // флаги форматирования
);
Пример
RECT Rect;
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps);
GetClientRect(hwnd,&Rect);
DrawText(hdc,”Простое Win32 Application”, -1, &Rect, DT_SINGLELINE|DT_CENTER| DT_VCENTER);
Для того чтобы установить шрифт надо:
1)Создать структуру типа LOGFONT.
typedef struct tagLOGFONT {
LONG lfHeight; //высота шрифта
LONG lfWidth; //ширина
LONG lfEscapement;// угол, под которым выводится шрифт
LONG lfOrientation; //0
LONG lfWeight; //толщина(0-900)
BYTE lfItalic; //1-курсив
BYTE lfUnderline;// 1-подчеркнуть
BYTE lfStrikeOut; //1-перечеркнуть
BYTE lfCharSet; //символьный набор,0-ANSI char
BYTE lfOutPrecision; //OUT_STROKE_PRECIS
BYTE lfClipPrecision; //CLIP_STROKE_PRECIS
BYTE lfQuality; //DEFAULT_QUALITY
BYTE lfPitchAndFamily;
TCHAR lfFaceName[LF_FACESIZE]; //имя шрифта
} LOGFONT;
В структуре LOGFONT можно просто обнулить все поля, кроме первого и последнего, и тем самым предоставить Windows выбрать значения для всех остальных полей по умолчанию.
Например,
LOGFONT logfont;
logfont.lfHeight =50;
logfont.lfWidth =10;
//….
strcpy(logfont.lfFaceName, "Arial");
//…
2) Создать шрифт вызовом функции CreateFontIndirect() или CreateFont():
HFONT CreateFontIndirect(CONST LOGFONT *lplf);
Например,
HFONT newfont=CreateFontIndirect(&logfont);
3)Установить шрифт в контексте устройства вызовом функции SelectObject():
HGDIOBJ SelectObject(
HDC hdc, // handle to DC
HGDIOBJ hgdiobj // handle to GDI-объекта(в данном случае фонта)
);
Например,
SelectObject(hdc,(HGDIOBJ) newfont);
Если нужно установить цвет букв, отличный от по умолчанию, то вызываем функцию SetTextColor():
COLORREF SetTextColor(
HDC hdc, // handle to DC
COLORREF crColor // цвет символов
);
Например,
SetTextColor(hdc, RGB(255, 0,0));
-
Рисование графических примитивов
Рисование графических примитивов производится с помощью перьев. В Windows есть три предопределенных пера–черное(BLACK_PEN), белое(WHITE_PEN) и прозрачное (NULL_PEN). Handle каждого из них может быть получен с помощью функции GetStockObject(). Создать новое перо можно функцией CreatePen(). После создания пера, необходимо сделать его текущим в контексте устройства. Это делается функцией SelectObject(). После того как мы отработаем с пером, необходимо удалить его, вызвав функцию DeleteObject(). Стили пера определяются константами PS_XXXX.
Для рисования линий и геометрических фигур используются различные функции API:
Линия- LineTo()
Прямоугольник- Rectangle()
Прямоугольник с закругленными краями- RoundRect()
Эллипс- Ellipse()
Дуга- Arc()
Сектор- Pie()
Например,
BOOL Ellipse(
HDC hdc, // handle to DC
int nLeftRect, // x-coord of upper-left corner of rectangle
int nTopRect, // y-coord of upper-left corner of rectangle
int nRightRect, // x-coord of lower-right corner of rectangle
int nBottomRect // y-coord of lower-right corner of rectangle
);
BOOL Rectangle(
HDC hdc, // handle to DC
int nLeftRect, // x-coord of upper-left corner of rectangle
int nTopRect, // y-coord of upper-left corner of rectangle
int nRightRect, // x-coord of lower-right corner of rectangle
int nBottomRect // y-coord of lower-right corner of rectangle
);
После прорисовки замкнутой фигуры, она заливается цветом и атрибутами текущей кисти. Сплошная кисть создается функцией CreateSolidBrush(). Штриховая кисть создается функцией CreateHatchBrush(). Стили штриховки определяются константами HS_XXXX.
После создания кисти, необходимо сделать ее текущей в контексте устройства. Это делается функцией SelectObject().
Например,
1)Создается кисть нужного цвета
long color=RGB(125,125,225);
HBRUSH hNew;
hNew=CreateSolidBrush(color);
2)Устанавливается объект-кисть в контексте устройства
SelectObject(hdc,hNew);
Порядок выполнения работы
Создадим простейшее приложение Win32 с использованием средств Visual C++.
Пусть программа выполняет следующее - рисует одну из геометрических фигур - прямоугольник (при нажатие клавиши 1) или круг (при нажатие клавиши 2), если ни одна из этих клавиш не нажата, то выводится сообщение “Press 1 or 2”. Для этого создадим небольшой класс, инкапсулирующий в себе один из классов объектов GDI- класс контекста устройства(DC), получаемого при обработке сообщения WM_PAINT, а также небольшую иерархию классов для графических объектов типа прямоугольник и круг. Для этого выполним следующее:
1.Запустим VC++. Из меню File выберем пункт New.
Из списка возможных типов проектов, выберем тип проекта Win32 Application, введем имя проекта (например test) и выберем папку, в которой он будет создан.
2.В появившемся окне Win32 Application выберем вид приложения “A simple Win32 application.” AppWizard сгенерирует следующие файлы: StdAfx.h, StdAfx.cpp и файл с “имя_проекта”.cpp(пусть оно будет test.cpp).
Файлы StdAfx.h, StdAfx.cpp содержат служебную информацию о программе, поэтому их лучше не изменять.
Файл test.cpp будет содержать следующие строки
// test.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
return 0;
}
Эта программа завершает свою работу, не выполняя никаких действий.
Составим на ее основе программу, выполняющею указанную выше работу.
3.Создадим несколько классов- класс инкапсулирующий контекст отображения с именем DCclass, абстрактный базовый класс геометрических фигур с именем figures и два порожденных от него класса circle и rectangle.
Прежде всего создадим класс с именем DCclass. Для этого щелкнем на стрелочке вниз на панели Class Wizard Bar.
4. Из высветившегося списка выберем пункт New Class.
5. В появившемся диалоге New Class введем в поле Name имя класса DCclass, а так как у этого класса нет родительских классов, то в поле Base Classes ничего не вводим.
После нажатия на OK , будут сгенерированны следующие файлы: файл декларации классов DCclass.h и файл исходных кодов класса DCclass.cpp. Посмотрев на вкладку FileView , вы обнаружите эти файлы, они уже добавлены в проект.
6.Изменим аргументы конструктора DCclass::DCclass() на следующие
DCclass::DCclass(HWND hwnd) - это необходимо сделать вручную.
7.Добавим в класс функцию с именем gethdc() и типом возвращаемого значения HDC.
Это можно сделать вручную или с помощью Class Wizard Bar. Сделаем это с помощью Class Wizard Bar. Для этого переключимся на вкладку Classes и щелкнем на имени класса.
8. Из появившегося меню щелкните на Add Member Function. В появившемся диалоге введите в поле Function Type тип возвращаемого значения HDC, в поле- Function Declaration имя функции gethdc и так как аргументов у нее нет, то можно ничего больше не вводить. Если у функции есть аргументы, то их необходимо ввести вместе с именем функции, как обычно мы делаем при объявлении функции. Далее можно выбрать тип функции static или virtual и один из видов доступа к функции public, protected, private. Нажав на Ok вы прикажете Class Wizard сгенерировать декларацию функции с заданным именем и типом в декларации класса.
9.Добавим к этому классу несколько членов-данных. Для этого переключитесь на вкладку Classes и щелкните на имени класса, из появившегося меню щелкните на Add Member Variable. В появившемся диалоге введите в поле Variable Type тип переменной HDC, в поле Variable Name имя переменной hdc и выберите метод доступа protected. Нажав на Ok вы прикажете Class Wizard сгенерировать декларацию переменной с заданным именем и типом в декларации класса.
10.Добавим еще 2 переменные в декларацию класса.
PAINTSTRUCT ps;
HWND hwnd;