WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!


Pages:     | 1 || 3 |

4. Простая графическая задача Имея каркас приложения, мы можем теперь создать на его основе любую однодокументную задачу. Однако поскольку наши знания о библиотеке MFC ограничены, попытаемся создать приложение на базе функций этой библиотеки, не вдаваясь во все сложности иерархии классов и взаимосвязей объектов. Мы поработаем только с одним компонентом программы –– классом «вид» (class view), тесно связанным с объектом «окно». Такие компоненты, как классы «приложение» (application), «рамка-окно» (frame) и «документ», можно пока игнорировать.

Рассмотрим следующую графическую задачу.

На клиентской области окна лежит цветной плоский шарик. Пользователь ударяет мышкой в любой точке окна, и шарик начинает двигаться в эту точку.

4.1. Класс CNewprjView Класс CnewprjView –– это класс, производный от класса CView. Как и для любого объекта С++, поведение объекта «вид» определяется функциями-членами (и переменными членами) его класса, включая и специфичные для приложения функции из производного класса, и стандартные функции, унаследованные от базовых классов. Используя Visual C++, можно создавать достаточно интересные приложения, просто добавляя код в производный класс «вид», сгенерированный AppWizard. В ПРИЛОЖЕНИИ 2 представлен код класса «вид», разделенный между двумя исходными модулями –– заголовочным файлом (.h), и файлом реализации (.cpp).

Объект класса CView представляет собой прямоугольную клиентскую область окна, в которую производится вывод данных в графическом режиме. Если происходят изменения в клиентской области окна или изменения размеров окна, необходимо перерисовать окно. Для этого Windows посылает приложению сообщение WM_PAINT. Метод OnPaint класса «вид» создает контекст устройства класса CPaintDC и вызывает метод OnDraw производного класса CNewprjView, передавая ему в качестве параметра контекст устройства. Следовательно, при внесении изменений в окне, т.е. при рисовании в окне, необходимо переопределить метод OnDraw, внеся в него функции рисования. Дополнительно можно переопределить метод OnInitialUpdate, в который вносятся данные необходимые для рисования.

4.2. Контекст устройства В Visual C++ методы, обеспечивающие вывод на экран дисплея, используют контекст устройства. Контекст устройства является объектом класса CDC. При создании объекта данного класса в него заносится вся информация о графическом устройстве вывода. Указатель на контекст устройства передается как параметр при обработке метода OnDraw. Ниже представлен пример использования указателя на контекст устройства в функции OnDraw:

Void CNewprjView::OnDraw(CDC* pCDC) {pDC––>TextOut(300,150,”text”,4);

pDC––>Rectangle(20,20,300,200);} Здесь pDC –– указатель на контекст устройства, TextOut –– метод вывода строки текста, Rectangle –– метод отображает прямоугольник.

Класс CDC представляет собой набор методов, обеспечивающих работу с инструментами для рисования. Для того чтобы использовать контекст устройства, следует создать объект CDC.

Библиотека MFC содержит несколько классов производных от CDC. В нашем приложении мы будем использовать только класс контекста устройства клиентской области CClientDC. Класс CDC содержит два контекста устройства:

m_hDC и m_hAttribDC. Рассмотрим только те методы класса CDC, которые потребуются для нашей задачи. Остальные рекомендуем посмотреть в разделе Help VisualC++.

4.3. Средства работы с графикой Библиотека MFC содержит следующие классы, инкапсулирующие работу с объектами графического интерфейса пользователя:

CPen (перо), CBrush (кисть), CFont (шрифт), CBitmap (растровое изображение), CPalett (палитра), CRgn (область).

Каждый класс графического интерфейса имеет конструктор, выполняющий создание объекта.

Затем объект инициализируется соответствующей функцией, для пера –– CreatePen, и далее связывается с контекстом устройства с помощью метода SelectObject, возвращающего значение предыдущего объекта графического интерфейса. После завершения операций рисования можно вернуть предыдущее значение объекта графического интерфейса. Например:

Void CNewprjView::OnDraw(CDC* pCDC) CPen myPen;

CPen* myOldPen;

myPen. CreatePen(PS_SOLID, 5, RGB(200,100,140));

myOldPen=pDC-> SelectObject(&myPen);

pDC––> SelectObject(myOldPen);

Рассмотрим метод CreatePen. Он содержит параметра:

1. Структура линии, которой будем рисовать.

PS_SOLID –– сплошная, PS_DOT –– пунктирная и т.д.

2. Толщина линии.

3. Цвет линии. Каждый цвет в Windows представляется сочетанием значений «красный», «зеленый» и «синий» (RGB). Три целочисленных параметра функции RGB меняют свое значение от 0 до 255. Ниже представлена таблица 16-ти стандартных чистых цветов, записанных с помощью функции RGB.

Красный Зеленый Синий Цвет 0 0 0 черный 0 0 255 синий 0 255 0 зеленый 0 255 255 бирюзовый 255 0 0 красный 255 0 255 малиновый 255 255 0 желтый 255 255 255 белый 0 0 128 темно-синий 0 128 0 темно-зеленый 0 128 128 темно-бирюзовый 128 0 0 темно-красный 128 0 128 темно-малиновый 128 128 0 темно-желтый 128 128 128 темно-серый 192 192 192 светло-серый 4.4. Первый рисунок Теперь уже можно приступить к нашей задаче. Сначала нарисуем цветной шарик в клиентской области окна. Для этого исправим метод OnDraw в файле NewprjView.cpp. Шарик будем рисовать с помощью функции Ellipse. Воспользуемся также карандашом и кистью. Метод OnDraw будет иметь следующий вид:

Void CNewprjView::OnDraw(CDC* pCDC) { CPen myPen;

CPen *myOldPen;

myPen.CreatePen(PS_SOLID,2,RGB(250,8,200));



myOldPen=pDC––>SelectObject(&myPen);

CBrush myBrush;

CBrush *myOldBrush;

myBrush.CreateSolidBrush(RGB(255,255,0));

myOldBrush=pDC–– >SelectObject(&myBrush);

pDC––>Ellipse(10, 10, 50, 50);

} Теперь оттранслируем только файл «вид». Для этого выберем в меню Build––>Compile––> Build––>Execute. Если ошибок не было, на экране появится окно с меню, в клиентской области которого лежит небольшой плоский шарик желтого цвета с красной окантовкой.

4.5. Добавление обработчика сообщений На следующем этапе мы должны заставить шарик двигаться. Для этого прежде всего заменим формулу для эллипса, вставив переменные координаты. Например, так:

pDC––>Ellipse(current_point.x, current_point.y, current_point.x-10, current_point.y-10);

Переменная current_point будет указывать координаты шарика на клиентской плоскости в некоторый момент времени при его движении.

Конечная точка движения будет находиться в месте удара мышью по клиентской области. Назовем ее end_point. Начальная точка положения шарика нам также понадобится, назовем ее new_point. Эти точки потребуются в разных методах внутри класса View. Поэтому определим их как глобальные в классе т.е. как члены класса. Но эти точки должны быть видны только в классе View, и, следовательно, их можно определить с модификатором protected.

В библиотеке MFC для определения точки на плоскости имеется класс CPoint. В этом классе каждая точка имеет координаты x и y.

Для определения переменной–члена класса проделаем следующую процедуру.

Обратимся к окну ClassView. Выделим класс CNewprjView. Затем щелкнем по нему правой кнопкой мыши. Откроется контекстное меню.

Нажмем строчку member variable. Откроется окно, в котором надо указать класс определяемой переменной, имя переменной и модификатор доступа к переменной. Укажем CPoint, current_point и protected. После нажатия на кнопку ОК в файле CNewprjView.h в разделе protected появится переменная current_point. Затем надо проделать то же самое с переменными end_point, new_point.

Следующий этап –– добавление методаобработчика сообщения Windows об ударе мыши по клиентской области окна. Для этого откроем ClassWizard на вкладке Message Maps (Рис. 4.1). Прежде всего надо убедиться, что в окне ClassName набрано имя класса CNewprjView. В окне Object ID также должно быть это имя, так как сообщение посылается классу. В окне Messages ищем сообщение WM_LBUTTONDOWN, нажимаем кнопку AddFunction. В окне Member functions появится имя функции OnLbuttondown. С помощью кнопки Edit Code можно сразу перейти в файл NewprjView.cpp, где уже имеется заголовок функции и фигурные скобки. Теперь запишем необходимые действия после удара мышкой по клиентской области окна. У метода OnLbuttondown имеются два параметра. Один из них –– point, переменная типа CPoint.

Рис. 4.1. ClassWizard В этой переменной сохраняются координаты точки на клиентской области, где ударила мышь. Эти координаты необходимо переписать в глобальную переменную end_point. Теперь у нас есть начальные и конечные точки движения шарика. Для визуального представления движения воспользуемся таймером.

4.6. Таймер Таймер Windows –– это полезный элемент, который позволяет выполнять некоторые действия через равные промежутки времени. Для запуска таймера надо в тексте программы вставить вызов функции CWnd::SetTimer с параметром –– интервалом времени. После этого с помощью ClassWizard определить обработчик сообщения WM_TIMER. После запуска таймера с заданным интервалом в миллисекундах сообщения WM_TIMER постоянно посылаются окну до тех пор, пока не будет вызван метод CWnd::KillTimer или уничтожено окно. Функция SetTimer выглядит следующим образом:

UINT SetTimer(UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer) (HWND, UINT, UINT, DWORD));

Параметры:

nIDEvent –– идентификатор таймера (целое, не равное нулю).

nElapse –– интервал в миллисекундах.

lpfnTimer –– определяет адрес приложения для функции обратного вызова, обрабатывающей сообщение WM_TIMER. Если значение параметра равно NULL, то сообщение будет поступать в очередь окна приложения и передаваться обработчику сообщения окна CWnd.

Функция KillTimer выглядит следующим образом:

BOOL KillTimer (int nIDEvent);

Метод удаляет указанный таймер.

Вернемся к нашей задаче. Таймер мы установим в функции OnLbuttondown, которая будет выглядеть следующим образом:

void CNewprjView::OnLButtonDown(UINT nFlags, CPoint point) { end_point.x = point.x;

end_point.y = point.y;

new_point.x=current_point.x;

new_point.y=current_point.y;

SetTimer(1, 40, NULL);

} 4.7. Обработчик сообщения OnTimer Создадим обработчик сообщения OnTimer так же, как мы создавали обработчик сообщения OnLbuttondown. Эта функция будет выполняться через равные промежутки времени и каждый раз положение шарика на клиентской области окна должно продвигаться в направлении конечной точки, т.е. координаты шарика current_point будут двигаться равномерно по прямой, соединяющей эту точку с точкой end_point.

Движение должно закончиться по достижении конечной точки, поэтому в начале функции будет проверка на точку end_point. Если значение new _point равно end_point, то работает метод KillTimer. Ниже приведена функция OnTimer.

void CNewprjView::OnTimer(UINT nIDEvent) { If( 50*abs( end_point.x- current_point.x)>abs(end_point.x- new_point.x))&& (50*abs(( end_point.y- curent_point.y) >abs(end_point.y - new_point.y))){ cpointx+=(float) (end_point.x - new_point.x)/50;





cpointy+=(float) (end_point.y - new_point.y)/50;

current_point.x = (int) cpointx;

current_point.y = cpointy;

GetDocument()––>UpdateAllViews(NULL);

} Последний метод UpdateAllViews(NULL) пересылает полученный документ на обработку в функцию OnDraw. Без этого метода мы не получим изображение шарика на экране.

4.7. Меню Программа написана почти полностью, но если сейчас запустим последний вариант, ничего на клиентской области окна не увидим. Мы забыли определить начальное значение переменной current_point, которая собственно выводится в функции OnDraw. Инициализацию начальных данных обычно делают в методе OnInitialUpdata(). Но мы вставим новый пункт меню в окне нашего приложения. Нажав на этот пункт меню, увидим на экране шарик.

Для создания нового пункта меню следует выполнить два действия:

1. Создать элемент меню в ресурсе меню.

2. Создать обработчик этого элемента меню с помощью ClassWiz ard.

Создание элемента меню начинается с открытия ресурса меню. Ресурс меню найдем в окне ResourseView. Щелкнув мышкой по слову «меню», увидим редактор меню. Пустая рамка следующего элемента меню всегда присутствует в окне редактора меню. Щелкнув мышью по новому элементу меню, увидим диалоговое окно свойств определяемого элемента меню. Здесь можно ввести заголовок элемента меню. Из свойств отметим только одно –– Pop-up. По умолчанию этот переключатель включен и указывает, что элемент меню формируется как открывающий подменю.

Назовем элемент меню –– Function. Появится подменю. Назовем элемент подменю –– Circle.

Следующий этап –– программирование обработчика команды меню. Для этого вызываем ClassWiz ard. На вкладке Message Maps укажем класс CNewprjView, в котором будем создавать обработчик сообщений меню. В окне Object ID найдем идентификатор ID_FUNCTION_CIRCLE.

В окне Messages появятся имена двух методов– обработчиков сообщений меню. Выберем метод COMMAND и нажмем кнопки AddFunction и Edit Code. В окне обработчика сообщений наберем следующий код:

void CNewprjView::OnFunctionCircle() { current_point.x =cpointx= 100;

current_point.y =cpointy= 100;

GetDocument()->UpdateAllViews(NULL);

} ПРИЛОЖЕНИЕ Листинг файла newprj.h.

// newprj.h : main header file for the NEWPRJ application #include "resource.h" // main symbols /////////////////////////////////////////////////////////////////////////// // // CNewprjApp:

// See newprj.cpp for the implementation of this class // class CNewprjApp : public CWinApp { public:

CNewprjApp();

// Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CNewprjApp) public:

virtual BOOL InitInstance();

//}}AFX_VIRTUAL // Implementation //{{AFX_MSG(CNewprjApp) afx_msg void OnAppAbout();

// NOTE - the ClassWizard will add and remove member functions here.

// DO NOT EDIT what you see in these blocks of generated code ! //}}AFX_MSG DECLARE_MESSAGE_MAP() };

Листинг файла newprj.cpp.

// newprj.cpp : Defines the class behaviors for the application.

#include "stdafx.h" #include "newprj.h" #include "MainFrm.h" #include "newprjDoc.h" #include "newprjView.h" /////////////////////////////////////////////////////////////////////////// // // CNewprjApp BEGIN_MESSAGE_MAP(CNewprjApp, CWinApp) //{{AFX_MSG_MAP(CNewprjApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout) // NOTE - the ClassWizard will add and remove mapping macros here.

// DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG_MAP // Standard file based document commands ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) // Standard print setup command ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup) END_MESSAGE_MAP() /////////////////////////////////////////////////////////////////////////// // // CNewprjApp construction CNewprjApp::CNewprjApp() { // TODO: add construction code here, // Place all significant initialization in InitInstance } /////////////////////////////////////////////////////////////////////////// // // The one and only CNewprjApp object CNewprjApp theApp;

/////////////////////////////////////////////////////////////////////////// // // CNewprjApp initialization BOOL CNewprjApp::InitInstance() { AfxEnableControlContainer();

// Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need.

#ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif // Change the registry key under which our settings are stored.

// TODO: You should modify this string to be something appropriate // such as the name of your company or organization.

SetRegistryKey(_T("Local AppWizardGenerated Applications"));

LoadStdProfileSettings(); // Load standard INI file options (including MRU) // Register the application's document templates. Document templates // serve as the connection between documents, frame windows and views.

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CNewprjDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CNewprjView));

AddDocTemplate(pDocTemplate);

Pages:     | 1 || 3 |










© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.