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

Паппас К., Мюррей У. - Visual C++ 6. Руководство разработчика - 2000

.pdf
Скачиваний:
289
Добавлен:
13.08.2013
Размер:
4.96 Mб
Скачать

//удаление кисти dc.SelectObject(oldbrush) ; newbrush.DeleteObject();

//удаление пера dc.SelectObject(oldpen); newpen.DeleteObject() ;

//рисование черного сектора и заливка его зеленым цветом newpen.CreatePen(PS_SOLID, I, dwColor[0]);

oldpen = dc.SelectObject(Snewpen); newbrush.CreatesolidBrush(dwColor[2]); oldbrush = dc.SelectObject(Snewbrush); dc.Pie(300,50,400, 150, 300, 50,300, 100); dc.TextOut(350,80,"<-pie wedge", 11);

//удаление кисти

dc.SelectObject(oldbrush);

newbrush.DeleteObject();

//удаление пера dc.SelectObject(oldpen); newpen.DeleteObj ect() ;

//рисование черного прямоугольника и заливка его серым цветом newbrush.CreateSolidBrush(dwColor[7]) ;

oldbrush = dc.SelectObject(Snewbrush); dc.Rectangle(50,300, 150, 400); dc.TextOut(160,350,"<-rectangle", 11);

//удаление кисти

dc.SelectObject(oldbrush); newbrush.DeleteObject() ;

// рисование черного закругленного прямоугольника //изаливка его синим цветом newbrush.CreateHatchBrush(HS_CROS5, dwColor[3]); oldbrush = dc.SelectObject(Snewbrush) ; dc.RoundRect(60, 310, 110,350, 20,20); dc.TextOut(120,310, "<————rounded rectangle", 24);

//удаление кисти dc.SelectObject(oldbrush); newbrush.DeleteObject();

//рисование нескольких зеленых точек for(xcoord = 400; xcoord < 450; xcoord += 3)

dc.SetPixel(xcoord, 150, OL); dc.TextOut(455, 145, "<-pixels", 8);

//рисование толстой ломаной линии пурпурного цвета newpen.CreatePen (PS_SOLID, 3, dwColor [5-] ); oldpen = dc.SelectObject(Snewpen);

polylpts[0].x = 10; polylpts[0].y = 30; polylpts[l].x = 10;

polylpts[l].y = 100;

;

polylpts[2].x = 50;

 

polylpts[2].y = 100;

 

polylpts[3].x

=

10;

 

polylpts[3].y

=

30;

 

dc.Polyline(polylpts, 4); dc.TextOut(10,110, "polyline", 8); // удалениепера dc.SelectObject(oldpen);

331

newpen.DeleteObject();

// рисование голубого многоугольника //изаливка его диагональной желтой штриховкой newpen.CreatePen(PS_SOLID, 4, dwColor[6]); oldpen = dc.SelectObject(Snewpen);

newbrush.CreateHatchBrush(HS_FDIAGONAL, dwColor[4]); oldbrush = dc.SelectObject(Snewbrush); polygpts[0].x = 40;

polygpts[0].y = 200; polygptsfl].x = 100; polygpts[l].y = 270; polygpts[2].x = 80; polygpts[2].y = 290; polygpts[3].x = 20; polygpts[3].y = 220; polygpts[4].x = 40; polygpts[4].y = 200; dc.Polygon(polygpts, 5);

dc.TextOut(70,210,"<-polygon", 9) ;

//удаление кисти dc.SelectObject(oldbrush); newbrush.DeleteObject();

//удаление пера dc.SelectObject(oldpen);

newpen.DeleteObject(); } BEGIN MESSAGE MAP(CMainWnd, CFrameWnd) ON_WM_PAINT () END_MESSAGE_MAP()

BOOL CgdiAApp::Initlnstance() { m_jpMainWnd = new CMainWnd () ; m_pMainWnd->ShowWindow(m_nCmdShow) ; m_pMainWnd->UpdateWindow();

return TRUE;

}.

Файл GDI.CPP

В функции OnPaint( ) создается массив dwColor, в котором хранятся девять RGB-значений цветов для используемых кистей и перьев.

static DWORD dwColor[9] = {RGB(0,0, 0), //

черный

RGB(255,

0, 0),//

 

красный

 

RGB(0,255, 0),

//

зеленый

 

RGB(О,О,

255),

//

синий

 

RGB(255,255, 0),

//

желтый

 

RGB(255, 0, 255),

//

 

пурпурный

RGB(0,255,255),

//

голубой

RGB(127,127,

127),//

серый

RGB(255,255,

255)};

//

белый

Классы CBrush и СРеn позволяют создавать объекты кистей и перьев, которые могут использоваться любыми функциями класса cdcи его потомков (классов, связанных с контекстами устройств). Кисти могут иметь сплошную и штриховую заливку, а также заливку с применением растрового узора. Перья рисуются сплошной (ps_solid), штриховой (ps_dash), пунктирной (ps_dot), штрихпунктирной (ps_dashdot) и штрихточечной (ps_dashdotdot) линиями. Ниже показан синтаксис создания объектов кистей и перьев:

CBrush newbrush;

CBrush* oldbrush;

CPen newpen;

332

CPen* oldpen;

Поскольку для рисования различных графических примитивов применяются аналогичные алгоритмы, мы рассмотрим лишь два типичных примера. В первом на экран выводится толстая черная диагональная линия:

// рисование толстой черной диагональной линии newpen. CreatePen(PS_SOLID, 6, dwColor[0]); oldpen = dc.SelectObject (Snewpen) ; dc.MoveTo(0, 0);

dc.LineTo(640, 430);

dc.TextOut (70, 20, "odiagonal line", 15); // удаление пера

dc.SelectObject (oldpen) ; newpen. DeleteObject() ;

Объект пера создается функцией CreatePen() „которая задает рисование черных сплошных линий толщиною в шесть логических единиц. Сразу после этого функция SelectObject() загружает созданный объект в контекст устройства и возвращает указатель на предыдущий объект пера. Функции Moveто() и LineTo() формируют линию, которая рисуется выбранным пером. Наконец, функция Textout() выводит надпись рядом с нарисованной фигурой. В завершение снова вызывается функция Selectobject(), которая восстанавливает прежнее перо, а функция DeleteObject() удаляет ненужное перо.

Работа с кистями организуется аналогичным образом. В следующем фрагменте кода создается кисть с заливкой горизонтальными и вертикальными штрихами (hs_cross) синего цвета.

//рисование черного закругленного прямоугольника //и заливка его синим цветом newbrush.CreateHatchBrush(HS_CROSS, dwColor[3]);. oldbrush = dc.Selectobject(Snewbrush); dc.RoundRect(60, 310, 110, 350, 20,20); dc.TextOut(120,310,"<—————rounded rectangle", 24);

//удаление кисти

dc.Selectobject(oldbrush);

newbrush.DeleteObject();

Функция RoundRect() рисует закругленный прямоугольник с черным контуром, который заливается с помощью выбранной кисти.

Запуск программы

Окно аналогичной программы представлено на рис. 19.2.

333

Рис. 19.2. Построение различных GDI объектов

Возможно, вы заметили, что в программе имеется один недостаток. Заключается он в том, что все координаты графических объектов, выводимых GDI-функциями, задаются в пикселях. А что произойдет, если изменится разрешение экрана, например вместо режима 800x600 будет установлен режим 1024x768? В этом случае выводимое изображение займет только верхнюю левую часть окна.

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

Построение ряда Фурье

Следующая программа выводит в рабочей области окна графическое представление ряда Фурье. В данном приложении используются ресурсы двух видов: меню и диалоговые окна. По мере возрастания сложности программы увеличивается и число файлов, вовлеченных в проект. Данное приложение включает файл заголовков FOURIER.H, файл ресурсов FOURIERR.H(обратите внимание на дополнительное 'R' в конце имени файла), файл сценариев ресурсов FOURIER. RCи программный файл FOURIER.CPP.

Ниже показан текст файла FOURIER. H: class CMainWnd : public CFrameWnd

{

 

public:

 

CMainWnd();

 

afx_msg void

OnPaintO;

afx_msg void

OnSize(UINT, int, int);

afx_msg int

OnCreate(LPCREATESTRUCT cs);

afx_msg void

OnAboutO;

afx_msg void

OnFourierData() ;

afx_msg void

OnExit();

DECLARE MESSAGE MAP() );

class CTheApp : public CWinApp

{

public:

virtual BOOL Initlnstance(); );

334

class CFourierDataDialog : public CDialog

{

public:

CFourierDataDialog(CWnd* pParentWnd=NULL) : CDialog("FourierData", pParentWnd)

{}

virtual void OnOK(); };

Файл FOURIERR.H содержит идентификаторы элементов меню и диалоговых окон.

#define IDM_FOUR 100 #define IDM_ABOUT 110 #define IDM_EXIT 120 #define IDD_TERMS 200 #define IDD_TITLE 201

Файл FOURIER.RC включает описания меню и двух диалоговых окон. В приложении используются довольно простые диалоговые окна, а именно About и окно ввода данных.

#include "fourierr.h"

#define APSTUDIO_READONLY_SYMBOLS

////////////////////////////////////////////////////

#define APSTUDIO_HIDDEN_SYMBOLS #include "windows. h"

#undef APSTUDIO_HIDDEN_SYMBOLS #include "afxres.h"

/////////////////////////////////////////

tundef APSTUDIO_READONLY_SYMBOLS

//////////////////////////////////////////

// Ресурсы для английского (США) языка

#if !defined(AFX_RESOURCE_DLL) || defined (APX_TARG_ENU) . -tifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

#pragma code_page (1252) #endif

//_WIN32

//////////////////////////////////////////

//

// Меню//

FOURIERMENU MENU DISCARDABLE BEGIN POPUP "Fourier Data" BEGIN

MENUITEM "Fourier Data...",IDM_FOUR MENUITEM "Fourier About...",IDM_ABOUT MENUITEM "Exit",IDM_EXIT END END

/////////////////////////////////////////

//

// Диалоговые окна

//

ABOUTBOX DIALOG DISCARDABLE 14,22,200, 75 STYLE WS_POPUP | WS_CAPTION

CAPTION "About Box" BEGIN

CTEXT "A Fourier Series Waveform", -1, 30, 5, 144, 8 CTEXT "A MFC Application", -1,30, 17,144,8

CTEXT "By William H. Murray and Chris H. Pappas", -1,28,28, 144, 8 CTEXT "(c)Copyright'1998",201, 68,38, 83, 8

DEFPUSHBUTTON "ОК",IDOK, 84,55,32,14,WS_GROUP END

FOURIERDATA DIALOG DISCARDABLE 74,21,142, 70 STYLE WS_POPUP | WS_CAPTION CAPTION "Fourier Data" BEGIN

LTEXT "Title: ", -1,6, 5, 28,8, NOT WS_GROUP

335

EDITTEXT IDDJTITLE, 33,1, 106,12

LTEXT "Number of terms: ", -1,6, 23,70/ 8, NOT WS_GROUP EDITTEXT IDDJTERMS, 76,18, 32, 12

PUSHBUTTON "ОК", IDOK, 25,52,24,14

PUSHBUTTON "Cancel", IDCANCEL, 89,53,28,14 END tifdef APSTUDIO_INVOKED

//////////////////////////////////////

1 TEXTINCLUDE DISCARDABLE BEGIN "resource.hNO" END

2 TEXTINCLUDE DISCARDABLE BEGIN

"#define APSTUDIO_HIDDEN_SYMBOLSNrNn" "#include ""windows.h""NrNn"

"tundef APSTUDIO_HIDDEN_SYMBOLSNr\n" "#include ""afxres.h""NrNn"

"NO" END

3 TEXTINCLUDE DISCARDABLE BEGIN

"NrNn"

 

 

"NO"

 

 

END

 

 

#endif

//

APSTUDIO_INVOKED

#endif

.11

Ресурсы для английского (США) языка

Текст файла FOURIER.CPP несколько сложнее, чем в предыдущем примере, поскольку программа должна поддерживать работу меню и двух диалоговых окон.

//

//fourier.cpp

//Построение ряда Фурье.

#include <afxwin.h> #include <string.h> #include <math.h>

#include"fourierR.h" // идентификаторы ресурсов #include "fourier.h"

int m_cxClient, m_cyClient; char mytitle[80] = "Title"; int nterms = 1;

CTheApp theApp; CMainWnd::CMainWnd() {

Create(AfxRegisterWndClass(CS_HREDRAW I CS_VREDRAW,

LoadCursor(NULL, IDC_CROSS), (HBRUSH) (GetStockObject>{WlJJTE._BRUSH) ) NULL),

"Fourier Series Application with the MFC ", WS OVERLAPPEDWINDOW, rectDefault, NULL, "FourierMenu");

}

void CMainWnd::OnSize(UINT,int x, int y) { m_cxClient = x;

m_cyClient = y; }

void CMainWnd::OnPaint() { CPaintDC dc(this);

static DWORD dwColor[9J= {

RGB(0,0, 0),

// черный

RGB (245,0, 0),

//

красный

RGB(0, 245, 0),

//

зеленый

RGB(0,0,245),

// синий

336

RGB(245,245, 0),

// желтый

RGB(245,0, 245),

//

пурпурный

RGB(0, 245, 245),

//голубой

RGB(127,127, 127),

//

серый

RGB(245, 245, 245)};

// белый

int i, j, Ititle, ang; double y, yp;

CBrush newbrush; CBrush* oldbrush; CPen newpen; CPen* oldpen;

//задание области просмотра dc. SetMapMode (MM_ISOTROPIC) ; dc.SetWindowExt (500,500);

dc. SetViewportExt (m_cxClient, -m_cyClient) ; dc.SetViewportOrg(m_cxClient/20, m_cyClient/2) ; ang = 0; yp = 0 . 0 ; newpen.CreatePen(PS_SOLID, 2, RGB(0,0, 0) ) ; oldpen = dc.SelectObject (Snewpen) ;

//рисование осей координат х и у

dc.MoveTo(0,

240);

 

dc.LineTo(0,

-240);

dc.MoveTo(0,

0)

;

 

dc.LineTo(400, 0)

;

dc.MoveTo(0,

0)

;

 

// рисование

ряда

Фурье

for(i = 0; i

<= 400; i++) {

for(j = 1; j

<= nterms; JH-+) (

y= (150.0/{ (2.0*j)-1.0)) * sin(((j*2.0)-1.0)*0.015708*ang); УР = УР +

у;

}

dc.LineTo(i, (int)yp); УР -= УР; ang'+t;

}

//заливка внутренних областей графика серым цветом newbrush.CreateSolidBrush(dwColor [7]) ;

oldbrush = dc.SelectObject (Snewbrush) ; dc.ExtFloodFill (150,10,dwColorfO],FLOODFILLBORDER) ; dc.ExtFloodFill (300,-10, dwColor[0], FLOODFILLBORDER)

//вывод заголовка графика

Ititle= strlen(mytitle) ;

dc.TextOut (200-(ltitle*8/2) , 185, mytitle, Ititle); // удаление кистей

dc. SelectObject (oldbrush) ; newbrush.DeleteObject () ;

}

int CMainWnd::OnCreate(LPCREATESTRUCT) { UpdateWindow();

return (0); }

void CMainWnd::OnAbout() { CDialog about("AboutBox", this); about.DoModal(); }

void CFourierDataDialog: :OnOK() { GetDlgltemText (IDDJTITLE, mytitle, 80);

337

nterms = GetDlgItemInt(IDD_TERMS, NULL, 0) CDialog: :OnOK();

}

void CMainWnd::OnFourierData() {

CFourierDataDialog dlgFourierData(this); if (dlgFourierData.DoModal() == IDOK) ( InvalidateRect(NULL, TRUE);

UpdateWindow(); } };

void CMainWnd::OnExit() { DestroyWindowO ; }

BEGIN_MESSAGE_MAP (CMainWnd, CFrameWnd) on_wm_paint() on_wm_size'o on_wm_create ( )

ON_COMMAND(IDM_ABODT, OnAbout) '! '"6Sf_%OMMAND(IDM_FOUR., OnFourierData)

O^COMMAND(IDM_EXIT, OnExit) END_MESSAGE_MAP ( ) BOOL CTheApp: : Initlnstance () {

m_pMainWnd = new CMainWndO; m_pMainWnd->ShowWindow(m_nCmdShow) ; m_pMainWnd->UpdateWindow() ;

return TRUE;

}

Файл FOURIER.H

Класс CMainWnd теперь содержит несколько обработчиков сообщений: OnPait (), OnSize(), OnCreate(), OnAbout(), OnFourierData(} И OnExit():

afx_msg void

OnPaint();

afx_msg void

OnSize(UINT, int, int);

afx_msg int

OnCreate(LPCREATESTRUCT cs);

af x_msg void OnAbout ( ) ;

afx_msg void

OnFourierData ();

afx_msg void

OnExit();

Функция OnPait() вызывается автоматически, когда объекту CMainWnd поступает сообщение wm_paint от Windows или от самого приложения. Функция OnSize() вызывается в ответ на сообщение wm_size, которое генерируется при изменении размеров окна приложения. Информация о размерах необходима для динамического масштабирования содержимого окна. Функции OnCreate( ) передается структура, содержащая информацию о создаваемом окне: его размерах, стиле и других атрибутах. Функции OnAbout( ) , OnFourierData ( ) и OnExit ( ) определяются пользователем и вызываются при получении сообщений wm_command, генерируемых при выборе соответствующих команд меню.

Для работы с диалоговыми окнами в MFC существует класс CDialog. Его можно непосредственно использовать для вывода простейших диалоговых окон, например окна About. В случае более сложных окон потребуется создать собственный класс. В нашем примере используется диалоговое окно, в котором пользователь может ввести заголовок для графика и целочисленное значение, задающее число членов ряда Фурье. Класс CFourierDataDialogпорождается от CDialog. Для ввода данных создается модальное окно, т.е. с приложением невозможно будет продолжать работу до тех пор, пока пользователь не введет данные и не закроет диалоговое окно. Объявление класса выглядит следующим образом:

class CFourierDataDialog : public CDialog

{

public:

CFourierDataDialog (CWnd* pParentWnd=NULL) : CDialog ("FourierData", pParentWnd)

{}

virtual void OnOK(); };

Классы диалоговых окон, порождаемые от CDialog, могут иметь собственную схему сообщений. Правда, если переопределяются только функции OninitDialog(), ОnОК () и OnCancel(), ее можно не создавать. В нашем простом примере конструктор

338

CFourierDataDialog() передает конструктору родительского класса имя диалогового окна, FourierData, и указатель на родительское окно.

Диалоговое окно возвращает введенные данные после щелчка пользователя на кнопке ОК. Для диалоговых окон, требующих предварительной инициализации, может быть переопределен метод OninitDialog().

Файлы ресурсов

Файл FOURIERR.H содержит пять идентификаторов. Константы idm_four, idm_aboutи Idm_exitслужат идентификаторами команд меню, тогда как константы IDD_TERMS и IDD_TITLE используются для описания элементов диалогового окна. Файл FOURIER. RC содержит описания меню и диалоговых окон.

Файл FOURIER.CPP

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

определить текущие размеры окна;

нарисовать объект в окне и выполнить его заливку;

выбрать новый указатель мыши;

задать область просмотра и начало координат;

установить цвет фона.

Создание окна

Одновременно с созданием окна выполняется регистрация класса окна с помощью функции AfxRegisterWndciass() . В качестве указателя мыши устанавливается перекрестие (idc_cross), для заливки фона выбирается белая кисть (white_brush), а значком приложения становится стандартный системный значок (последний параметр равен null).

CMainWnd::CMainWnd() ( Create(AfxRegisterWndciass(CS_HREDRAW I CS_VREDRAW,

LoadCursor(NULL, IDC_CROSS), (HBROSH)(GetStockObject(WHITE_BRUSH)), NULL),

"Fourier Series Application with the MFC ", WSJDVERLAPPEDWINDOW, rectDefault, NULL, "FourierMenu"); 1

Обратите также внимание, что в функции Create() задается название меню приложения.

Определение текущих размеров окна

Сообщение wm_sizeгенерируется всякий раз, когда изменяются размеры окна приложения. В функцию OnSizet)передаются текущие размеры окна, которые сохраняются в переменных m_cxdientи m_cyClient:

void CMainWnd::OnSize(UINT, int x, int y) { m_cxClient = x;

m_cyClient = y;

}

Значения этих переменных используются для масштабирования содержимого окна в соответствии с его размерами.

Построение ряда Фурье

Чтобы избежать проблем с масштабированием выводимого изображения, о которых упоминалось выше, создается свободно масштабируемая поверхность рисования. Сначала с помощью функции SetMapMode() устанавливается режим отображения MM_ISOTROPIC:

339

dc.SetMapMode(MM_ISOTROPIC);

Далее логические размеры окна задаются равными по вертикали и горизонтали 500 единицам:

dc.SetWindowExt(500,500);

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

dc.SetViewportExt(ra_cxClient, -m_cyClient);

Это является гарантией того, что все содержимое окна будет видимым. Отрицательное значение у означает, что ось у увеличивается в направлении снизу вверх. В следующей строке точка начала области просмотра устанавливается на пересечении середины оси у и одной пятой от левого края оси х.

dc.SetViewportOrg(m_cxClient/20, m_cyClient/2);

Затем строятся оси координат х и у.

//рисование осей координат х и у dc.MoveTo(0, 240);

dc.LineTo(0, -240); dc.MoveTo(0, 0); dc.LineTo(400, 0); dc.MoveTo(0,0);

Показанный ниже фрагмент программы, ответственный за выведение на экран ряда Фурье, содержит два цикла for. В переменной цикла i хранится значение координаты х, я в переменной цикла j — значение текущей гармоники. Координата у каждой точки представляет собой сумму значений всех гармоник для заданного угла.

// рисование ряда Фурье for(i= 0; i <= 400; i++) { for (j = 1; j <= nterms; j++){

y= (150.0/((2.0*j)-1.0)) * sin(((j*2.0)-1.0)*0.015708*ang);

yp = yp + y; }

 

dc.LineTo (i,

(int)yp);

yp -= ур;

 

ang++;

 

}

 

Для связи всех точек графика в единую кривую используется функция LineTo(). Внутренняя область графика будет закрашена серым цветом с помощью функции ExtFloodFill(). Эта функция требует указания координат произвольной точки внутри закрашиваемой области и цвета границы области. Установка параметра floodfillborder означает, что функция будет закрашивать всю область до границы, заданной указанным цветом.

// заливка внутренних областей графика серым цветом newbrush.CreateSolidBrushfdwColor[7]) ;

oldbrush = dc.SelectObject(Snewbrush); dc.ExtFloodFill (150,10, dwColor[0], FLOODFILLBORDER); dc.ExtFloodFill(300,-10,dwColorfO],FLOODFILLBORDER);

Построение графика завершается выведением надписи и удалением из памяти созданного ранее объекта кисти:

//вывод заголовка графика Ititle = strlen(mytitle); dc.TextOut(200-(ltitle*8/2), 185, mytitle, Ititle);

//удаление кистей

dc.SelectObject(oldbrush); newbrush.DeleteObjeot() ;

340

Соседние файлы в предмете Программирование на C++