Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Технологии программирования. Программирование графических интерфейс

.pdf
Скачиваний:
3
Добавлен:
15.11.2022
Размер:
2.24 Mб
Скачать

Вгруппе Class information в поле Name укажите имя нового класса, а в поле File name – имя файла с реализацией данного класса.

Вгруппе Base class в поле Derived From укажите имя базового класса (если новый класс наследуется), а в поле As – тип наследования.

При создании класса будет сгенерирован прототип класса, состоящий из определения класса и пустого конструктора и деструктора.

Затем в класс можно добавить члены-данные и членыфункции, как было показано выше (рис. 2.5).

Рис. 2.5

2.6. Пример создания простейшего приложение Win32 с графикой

Необходимо создать программу, которая выполняет следующее: рисует одну из геометрических фигур – прямоугольник (при нажатии клавиши 1) или круг (при нажатии клавиши 2),

41

если ни одна из этих клавиш не нажата, то выводится сообще-

ние «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;

}

Эта программа завершает свою работу, не выполняя никаких действий.

Составим на ее основе программу, выполняющею указанную выше работу.

42

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 Wiz-

ard сгенерировать декларацию функции с заданным именем и типом в декларации класса.

43

9.Добавим к этому классу несколько членов-данных. Для этого переключимся на вкладку Classes и щелкнем на имени класса, в появившемся меню щелкнем на Add Member Variable.

Впоявившемся диалоге введем в поле Variable Type тип переменной HDC, в поле Variable Name – имя переменной hdc и выберем метод доступа protected. Нажав на OK, вы прикажете Class Wizard сгенерировать декларацию переменной с заданным именем и типом в декларации класса.

10.Добавим еще 2 переменные в декларацию класса.

PAINTSTRUCT ps;

HWND hwnd;

11.Перейдем к файлу DCclass.cpp и определим функции – члены класса.

Когда будем набирать этот файл, заметим, что набирать заголовки функций и скобки блока тела функции не нужно, так они будут сгенерированы средствами Class Wizard, нам нужно будет только набрать исходный код внутри этих скобок.

12.Откомпилируем класс и убедимся, что ошибки отсут-

ствуют.

13.Добавим абстрактный базовый класс геометрических фигур с именем figures и два порожденных от него класса: circle

иrectangle.

Как описано выше, создаем класс figures, описанный в файле декларации класса figures.h, и файл кода функций класса figures.cpp.

14. Добавим в класс figures чистую виртуальную функцию draw() с типом возвращаемого значения void. Для этого можно воспользоваться средствами Class Wizard. Как мы это уже делали для класса DCclass, вызовем плавающее меню, щелкнув на имени класса figures, выберем из него пункт Add Member Function.

В появившемся диалоге введем тип возвращаемого значения void и декларацию функции draw(HDC hdc) = 0, отметим тип функции

как virtual.

15.Добавим к этому классу два порожденных от него класса: circle и rectangle.

44

16. Для добавления класса circle воспользуемся средствами Class Wizard, вызовем средство генерации классов, как описано выше. Введем имя класса circle, в поле File Name введем имя файла декларации figures.h, файла исходных кодов figures.cpp (для этого необходимо нажать на change, появится следующий диалог) (рис. 2.6).

Рис. 2.6

В строках Header File и Implementation File введем имена файлов, где вы хотите разместить заголовки классов и их программную реализацию (в данном случае figures.h и figures.cpp).

Введем в разделе Base Class(es) имя базового класса figures и тип наследования для класса circle – public. Class Wizard сгенерирует в заданных файлах декларацию данного класса (конструктор + деструктор) и исходный код конструктора и деструктора (пустые функции).

17. Переопределим в данном классе чистую виртуальную функцию из базового класса с именем draw (HDC hdc). Это можно сделать вручную или с помощью Class Wizard, не забудьте только про правила переопределения и декларации виртуальных функций.

Как это уже делали для класса DCclass, вызовем плавающее меню, щелкнув на имени класса circle, выберем из него пункт Add Member Function. В появившемся диалоге введем тип возвращаемого значения void и декларацию функции draw (HDC

45

hdc), отметим тип функции как virtual. Данная функция будет рисовать в контексте устройства hdc круг с центром в точке (100,100) изаданным впеременнойint circlre::usedradius радиусом.

Добавим также функцию int circle::setradius(const int newradius), которая будет возвращать старое значение радиуса и устанавливать новоезаданноев newradius.

Добавим также в класс переменную int circlre::usedradius,

вкотором будем хранить используемый радиус круга.

18.Добавим в проект новый класс с именем rectangle, порожденный от класса figures, в котором переопределим функцию draw так, чтобы она отображала прямоугольник с координатой левого верхнего угла в точке (100,100) и заданной шириной и высотой. В данный класс добавим переменные int

rectangle::usedwidth и int rectanlge::usedheight, в которых будут храниться ширина и высота прямоугольника, и функцию класса

void setrectsize(const int rectwidth,const int rectheight), которая будет устанавливать ширину и высоту прямоугольника.

Пусть этот класс будет декларироваться в файле figures.h,

аего код размещаться в файле figures.cpp

19.Перейдем на файл figures.cpp и определим в нем методы классов.

20.Запишем главную часть программы – файл test.cpp, содержащий текст функции WinMain и функцию обработчик сообщений Windows с именем WndProc.

Стратегия обработки сообщений в оконной функции следующая.

Обработчик сообщения WM_KEYDOWN (нажали клавишу) устанавливает значение переменной pressedkey в зависимости от кода нажатой клавиши. Код нажатой клавиши передается в оконную функцию через параметр wParam. После установки значения переменной pressedkey необходимо вызвать API-функцию InvalidateRect(), для того чтобы было сгенеровано сообщение WM_PAINT.

Обработчик сообщения WM_PAINT создает объект класса DCclass, в котором определяются контекст устройства и объек-

46

ты классов circle и rectangle. Затем в зависимости от значения переменной pressedkey вызывается виртуальная функция draw, которая будет рисовать ту или иную фигуру.

Если не нажата ни одна из названных клавиш, то выводится текст «Press 1 or 2». Вывод текста выполняется API-функцией

TextOut().

21. Откомпилируем и выполним программу.

Вопросы для самоконтроля

1.Что такое контекст устройства? Каковы его функции?

2.Как получить и освободить контекст устройства?

3.Назовите две пары функций, которые используются для управления контекстом устройства.

4.Какие объекты рисования вы знаете?

5.Какие шаги необходимо выполнить в программе для работы с графическими объектами?

6.Как выбрать и освободить графический объект в контексте устройства?

7.В каком месте программы создаются и используются объекты рисования?

8.Какие API-функции для рисования графических фигур вы знаете?

9.ВкакихслучаяхокнупосылаетсясообщениеWM_PAINT?

10.Какова цель вызова функции InvalidateRect()?

11.Для чего и каким образом в программе можно использовать макрос HANDLE_MSG?

12.Какимобразомобрабатыватьсообщенияотклавиатуры?

13.В чем отличие сообщений WM_KEYDOWN и

WM_CHAR?

14.Какие виртуальные коды клавиш вы знаете?

15.Назовите две функции, которые можно использовать для вывода текста.

16.Как проще всего выводить текст в центре экрана?

17.В чем отличие функций TextOut() и DrawText()?

47

18.Как изменить шрифт?

19.Как установить и освободить таймер?

20.Что таймер делает?

21.Для чего предназначен мастер ClassWizard?

22.Как активизировать функции ClassWizard?

Упражнения

1. Замените обработчик сообщения WM_KEYDOWN на

WM_CHAR.

2.Измените программу так, чтобы для обработки сообщений использовался макрос HANDLE_MSG(). Определение этого макроса смотрите в файле windowsx.h.

3.Для вывода теста в середине экрана используйте

функции GetClientRect(),GetTextMetrics() и TextOut().

4. Для вывода текста в середине экрана используйте функции GetClientRect() и DrawText().

5.Для вывода текста используйте функции SetTextAling()

иDrawText().

6.Кроме текста «Press 1 or 2» выведите в центре окна текст «Win32 API» крупными буквами.

7.Выведите оба текста разным шрифтом и разным цветом.

8.Фигуры закрасьте в разные цвета.

9.Добавьте обработку нажатия клавиши «3» для рисования круговой диаграммы.

10.Добавьте в программу таймер и обработку сообщения WM_TIMER. По сигналу от таймера изображается следующая фигура, то есть на экране последовательно показываются прямоугольник, круг, круговая диаграмма, текст, прямоугольник, круг, круговая диаграмма, текст и т.д.

11.Сделайте так, чтобы частота таймера изменялась при нажатии клавиш ↑ и ↓ .

48

3. ПРОСТОЕ MFC ПРИЛОЖЕНИЕ

3.1. Microsoft Foundation Classes

MFC-библиотека (MFC – Microsoft Foundation Class library) –

это базовый набор классов, написанных на языке С++ и предназначенных для упрощения и ускорения процесса программирования под Windows.

Все MFC-программы включают заголовочный файл AFXWIN.H. В нем, а также в различных вспомогательных файлах, содержатся описания классов, структур, переменных и других объектов MFC. Файл AFXWIN.H автоматически подключает большинство заголовочных файлов, относящихся к MFC, в том числе и WINDOWS.H, в котором определены все функции Windows API и другие объекты, которые используются при традиционном программировании на С и «чистом» API.

Большинство функций, вызываемых в MFC-программе, являются членами одного из классов, определенных в библиотеке. Через функции-члены MFC доступно большинство функций API. Тем не менее в MFC-программе всегда можно обращаться к функциям API напрямую.

3.2. Простейшая MFC-программа

Для простейшей программы необходимо создать два объекта MFC: объект приложение, производный от класса CWinApp, и объект главного окна, производный от класса CWnd или его потомков – классов CFrameWnd, CMDIFrameWnd и CDialog.

Вспомним, что при разработке простейшего приложения с использованием функций API, создавались две функции: WinMain() и оконная функция WndProc(). Существует аналогия между структурой этого приложения и структурой простейшего приложения на основе MFC.

49

Аналогом WinMain является класс приложения CWinApp, а аналогом оконной функции – класс окна CWnd. Требуется создать свой класс, производный от CWinApp, например CMyApp, и свой класс, производный от CWnd, например CMyMainWnd.

Всю работу, которую выполняет функция WinMain, теперь осуществляет класс CWinApp. Нам остается только переопределить в классе виртуальную функцию InitInstance(); создать внутри этой функции объект CWnd – аналог оконной процедуры.

В простейшем случае в конструкторе класса CMyMainWnd вызывается метод Create(), который наш класс наследует от родительского класса.

Если хотим, чтобы программа обрабатывала события (от мыши, клавиатуры, меню и т.д.), то следует:

1. Вставить в конце определения оконного класса макрос

DECLARE_MESSAGE_MAP()

Этот макрос декларирует, что класс будет реагировать на некоторые события.

2. После определения класса добавить два макроса

BEGIN_MESSAGE_MAP (CMyMainWnd, CFrameWnd) и

END_MESSAGE_MAP()

Это так называемая карта сообщений. В первом макросе первый параметр – имя вашего класса, второй – имя родительского класса. Первый параметр показывает, для какого класса пишем карту сообщений, а второй – кто должен обрабатывать сообщение, которое наш класс обработать не может. Между двумя этими макросами записываются макросы для сообщений, которые должна обрабатывать наша программа.

3. В классе «окна» объявить метод для обработки сообщения. Для стандартных сообщений имена методов стандартны. Для того чтобы выделить функции обработки сообщений в отдельную группу, введен специальный спецификатор afx_msg, который при расширении образует пустое место. Поэтому запишем перед названием метода этот спецификатор.

50