Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Реалізація функцій класу CDib






Конструктор класу CDib наводиться нижче. Його текст, власне, зводиться до виклику вже згаданої функції LoadBitmapFile():

 

CDib:: CDib(const char* fileName) {LoadBitmapFile(fileName); }

Для створення об’єкта класу CDib необхідно вказати ім’я файла растрового зображення, що необхідно завантажити. Конструктор передає це ім'я до захищеної члена класу CDib - LoadBitmapFile(), який здійснює фактичне завантаження.

Код функції LoadBitmapFile() є досить складним. Фактично, ця функція є основною у класі і за обсягом і за важливістю. Текст функції демонструє приклад 8.2.

 

Приклад 8.2 – Вигляд функції LoadBitmapFile()

 

void CDib:: LoadBitmapFile (const char* fileName)

{ CFile file(fileName, CFile:: modeRead); // конструювання об’єкта файла

BITMAPFILEHEADER bmFileHeader;

file.Read((void*)& bmFileHeader, sizeof(bmFileHeader)); // зчитування заголовку файла

if (bmFileHeader.bfType! = 0x4d42) // перевірка чи є відповідним тип файла

{ AfxMessageBox(" Not a bitmap file"); // невідповідний формат файла

m_pBmFileHeader = 0; m_pBmInfo = 0; // усі поля – до значення 0

m_pBmInfoHeader = 0; m_pRGBTable = 0;

m_pDibBits = 0; m_numColors = 0;

}

else { DWORD fileLength = file.GetLength(); // розрахунок довжини файла

DWORD dibSize = fileLength - sizeof(bmFileHeader); // розрахунок розміру DIB

BYTE* pDib = (BYTE*)GlobalAlloc(0, dibSize); // розміщення у пам’яті

file.Read((void*)pDib, dibSize); // зчитування файла

file.Close(); // його закриття

m_pBmInfo = (LPBITMAPINFO) pDib; // ініціалізація основних структур

m_pBmInfoHeader = (LPBITMAPINFOHEADER) pDib;

// розрахунок покажчика на таблицю кольорів растрового зображення

m_pRGBTable =(RGBQUAD*)(pDib + m_pBmInfoHeader-> biSize);

int m_numColors = GetDibNumColors(); // отримання кількості кольорів

// розрахунок розміру зображення

m_pBmInfoHeader-> biSizeImage =GetDibSizeImage();

// перевірка ініціалізації поля biClrUsed

if (m_pBmInfoHeader-> biClrUsed == 0)m_pBmInfoHeader-> biClrUsed = m_numColors;

// розрахунок покажчика на дані растрового зображення

DWORD clrTableSize = m_numColors * sizeof(RGBQUAD);

m_pDibBits =pDib + m_pBmInfoHeader-> biSize + clrTableSize;

}}

 

Спочатку, функція LoadBitmapFile() створює об’єкт класу CFile:

 

CFile file (fileName, CFile:: modeRead);

При цьому створюється об’єкт типу CFile, також файл, заданий своїм ім’ям відкривається у режимі зчитування.

Далі оголошується структура заголовка растрового зображення і відбувається зчитування заголовка відповідно до розміру останнього:

 

BITMAPFILEHEADER bmFileHeader; file.Read((void*)& bmFileHeader, sizeof(bmFileHeader));

Наступним кроком перевіряється відповідність відкритого файла формату *.bmp. При цьому слід перевірити чи дорівнює член заголовка bfType коду 0x4D42 (16-кове значення літер ВМ). У випадку, коли такий код не знайдений, після повідомлення, що відкритий файл має некоректний формат, усім елементам структур присвоюється значення 0, на чому дія функції закінчується. Якщо формат файла є коректним, здійснюється певна послідовність дій.

Спочатку отримується розмір відкритого файла:

 

DWORD fileLength = file.GetLength();

 

Після цього обчислюється розмір растрового зображення. Він є різницею між розміром усього файла та розміром заголовка:

 

DWORD dibSize = fileLength - sizeof(bmFileHeader);

Розмір зображення dibSize використовується для виділення пам’яті:

 

BYTE* pDib = (BYTE*)GlobalAlloc(0, dibSize);

 

GlobalAllocPtr() є функцією Windows, що розподіляє пам'ять і повертає покажчик на область пам’яті.

Після виділення пам'яті, викликається функція Read() класу CFile, яка здійснює зчитування растрового зображення відповідно до визначеного розміру:

file.Read((void*)pDib, dibSize);

Після зчитування файл має бути закритим, що й здійснює функція Close(). Наступним кроком розраховуються необхідні змінні класу, відповідні типам BITMAPINFO і BITMAPINFOHEADER, та таблиці кольорів типу:

 

m_pBmInfo = (LPBITMAPINFO) pDib; m_pBmInfoHeader = (LPBITMAPINFOHEADER) pDib; m_pRGBTable =(RGBQUAD*)(pDib + m_pBmInfoHeader-> biSize);

При обрахуванні m_pRGBTable виходять з того, що покажчик на таблицю кольорів отримується додаванням розміру структури BITMAPINFOHEADER та адреси pDib растрового зображення у пам’яті.

Подальшими викликами визначають кількість кольорів m_numColors, розраховують розмір зображення m_pBmInfoHeader-> biSizeImage:

 

int m_numColors = GetDibNumColors(); m_pBmInfoHeader-> biSizeImage = GetDibSizeImage();

Якщо член biClrUsed структури BITMAPINFOHEADER дорівнює 0, ініціалізується його коректне значення, що отримується зі змінної m_numColors:

 

if (m_pBmInfoHeader-> biClrUsed == 0)m_pBmInfoHeader-> biClrUsed = m_numColors;

 

Насамкінець, функція LoadBitmapFile() обчислює адресу зображення як суму розміру структури BITMAPINFOHEADER, розміру таблиці кольорів та покажчика pDib:

 

DWORD clrTableSize = m_numColors * sizeof(RGBQUAD); m_pDibBits = pDib + m_pBmInfoHeader-> biSize + clrTableSize;

Інші функції класу CDib не є такими складними, як LoadBitmapFile().

Функція GetDibSizeImage() обчислює розмір растрового зображення в байтах. Спочатку вона перевіряє чи містить biSizeImage (елемент структури BITMAPINFOHEADER) нульове значення. Якщо це так, тобто немає обчисленого значення розміру зображення, обчислюються коректні значення висоти та ширини, що, перемножені, дають розмір зображення DIB-файла:

 

DWORD CDib:: GetDibSizeImage()

{ if (m_pBmInfoHeader-> biSizeImage == 0)

{ DWORD byteWidth = (DWORD) GetDibWidth(); DWORD height = (DWORD) GetDibHeight();

DWORD imageSize = byteWidth * height;

return imageSize; }

else return m_pBmInfoHeader-> biSizeImage; // повертається, якщо елемент структури не є порожнім

}

Ще одна функція – GetDibNumColors() обчислює кількість кольорів зображення. У ній аналогічно перевіряється структура BITMAPINFOHEADER. Якщо її елемент biClrUsed має ненульове значення (визначене раніше), це значення повертається, якщо biClrUsed =0, відбувається зсув поля m_pBmInfoHeader-> biBitCount на одиницю. В результаті маємо отримати значення 2 для 1-бітного (монохромного) зображення, 16 – для 4-бітного та 256 – для 8-бітного зображення DIB-файла:

 

UINT CDib:: GetDibNumColors()

{ if ((m_pBmInfoHeader-> biClrUsed == 0) & & (m_pBmInfoHeader-> biBitCount < 9)) return (1 < < m_pBmInfoHeader-> biBitCount); else return (int) m_pBmInfoHeader-> biClrUsed; }

Інші функції класу діють у простий спосіб і повертають необхідні значення відповідних структур, наприклад функція GetDibRGBTablePtr() повертає покажчик на таблицю кольорів, що зберігається у компоненті m_pRGBTable:

 

LPRGBQUAD CDib:: GetDibRGBTablePtr() { return m_pRGBTable; } 8.5 Розробка програми для відкриття та відображення файлів формату DIB Метою розроблюваної програми є відкриття та відображення файлів формату DIB. Зазвичай ці файли мають розширення *.bmp. Розроблювана програма не реалізує функцій збільшення або зменшення зображень, перегляду послідовності зображень, як це зроблено у спеціальних програмах перегляду графіки (на зразок ACDC), до того ж програма підтримуватиме лише формат *.bmp.Розробка програми вкладається у певну послідовність кроків: 1) створити проект типу “Win32 Application” (опція “Empty project”); 2) оголосити клас прикладки CApp з функцією ініціалізації InitInstance(); 3) оголосити клас CMainWin головного вікна програми та реалізувати необхідні об’єкти віртуального вікна:

 

class CMainWin: public CFrameWnd

{public: void OnExit(); // обробник виходу з програми

void OnPaint(); // обробник оновлення екрана

void OnPicOpen(); // обробник відкриття зображення

CMainWin(); // конструктор класу

DECLARE_MESSAGE_MAP()

private: CBrush mBrush; // пензель віртуального вікна

CDC memDC; // контекст віртуального вікна

CBitmap vbmp; // зображення віртуального вікна

};

4) реалізувати конструктор головного вікна із ініціалізацією необхідних об’єктів віртуального вікна:

 

CMainWin:: CMainWin()

{Create(NULL, " Перегляд файлів формату DIB", WS_OVERLAPPEDWINDOW, rectDefault, NULL,

MAKEINTRESOURCE(IDR_MENU1));

CClientDC dc(this);

maxX=GetSystemMetrics(SM_CXSCREEN); // maxX та maxY – глобальні змінні програми

maxY=GetSystemMetrics(SM_CYSCREEN);

memDC.CreateCompatibleDC(& dc);

vbmp.CreateCompatibleBitmap(& dc, maxX, maxY);

memDC.SelectObject(& vbmp);

mBrush.CreateStockObject(WHITE_BRUSH);

memDC.SelectObject(& mBrush);

memDC.PatBlt(0, 0, maxX, maxY, PATCOPY); }

5) в окремих файлах cdib.h та cdib.cpp реалізувати відповідно клас CDib та його функції-члени та включити їх до складу проекту;

6) реалізувати функцію відкриття та відображення графічних файлів, що здійснено на основі вибору файла зі стандартного діалогу відкриття CFileDialog із фільтром (*.bmp) та виведення на екран за допомогою API-функції StretchDIBits()):

void CMainWin:: OnPicOpen()

{static char BASED_CODE szFilter[] = " Bitmap Files (*.bmp)|*.bmp| All Files (*.*)|*.*||";

CFileDialog a(TRUE, " *.bmp", NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter, NULL);

a.DoModal();

if(a.GetFileName())

{memDC.PatBlt(0, 0, maxX, maxY, PATCOPY);

CDib pDib(a.GetFileName());

BYTE *pBmBits = pDib.GetDibBitsPtr();

LPBITMAPINFO pBmInfo = pDib.GetDibInfoPtr();

UINT bmWidth = pDib.GetDibWidth(); UINT bmHeight = pDib.GetDibHeight();

StretchDIBits (memDC, 0, 0, bmWidth, bmHeight, 0, 0, bmWidth, bmHeight, pBmBits, pBmInfo, DIB_RGB_COLORS, SRCCOPY);

InvalidateRect(NULL);

}}

7) реалізувати обробники оновлення вікна, виходу з програми, реалізувати карту повідомлень.

Вигляд вікна розглянутої програми наводиться на рисунку 8.1. Рисунок 8.1 – Вигляд вікна програми перегляду растрових зображень формату DIB (відкрито файл “himeri.bmp”) Повний текст програми наводиться у прикладі 8.3. Приклад 8.3 – Текст програми перегляду растрових зображень формату DIB // файл m1.h class CMainWin: public CFrameWnd {public: void OnExit(); void OnPaint(); void OnPicOpen(); CMainWin(); DECLARE_MESSAGE_MAP()private: CBrush mBrush; CDC memDC; CBitmap vbmp; }; class CApp: public CWinApp {public: BOOL InitInstance(); }; // файл cdib.hclass CDib: public CObject{protected: LPBITMAPFILEHEADER m_pBmFileHeader; LPBITMAPINFO m_pBmInfo; LPBITMAPINFOHEADER m_pBmInfoHeader; RGBQUAD* m_pRGBTable; BYTE* m_pDibBits; UINT m_numColors; public: CDib(const char* fileName); ~CDib(); DWORD GetDibSizeImage(); UINT GetDibWidth(); UINT GetDibHeight(); UINT GetDibNumColors(); LPBITMAPINFOHEADER GetDibInfoHeaderPtr(); LPBITMAPINFO GetDibInfoPtr(); LPRGBQUAD GetDibRGBTablePtr(); BYTE* GetDibBitsPtr(); protected: void LoadBitmapFile(const char* fileName); }; // файл m1.cpp #include < afxwin.h> #include < afxdlgs.h> #include " m1.h" #include " cdib.h" #include " resource.h" int maxX, maxY; CMainWin:: CMainWin(){Create(NULL, " Перегляд файлів формату DIB", WS_OVERLAPPEDWINDOW, rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU1)); CClientDC dc(this); maxX=GetSystemMetrics(SM_CXSCREEN); maxY=GetSystemMetrics(SM_CYSCREEN); memDC.CreateCompatibleDC(& dc); vbmp.CreateCompatibleBitmap(& dc, maxX, maxY); memDC.SelectObject(& vbmp); mBrush.CreateStockObject(WHITE_BRUSH); memDC.SelectObject(& mBrush); memDC.PatBlt(0, 0, maxX, maxY, PATCOPY); }BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd) ON_COMMAND(ID_FILE_OPENPICTURE, OnPicOpen) ON_COMMAND(ID_FILE_EXIT, OnExit) ON_WM_PAINT()END_MESSAGE_MAP() CApp App; BOOL CApp:: InitInstance(){m_pMainWnd = new CMainWin; m_pMainWnd-> ShowWindow(m_nCmdShow); m_pMainWnd-> UpdateWindow(); return TRUE; } void CMainWin:: OnPicOpen(){ static char BASED_CODE szFilter[] = " Bitmap Files (*.bmp)|*.bmp| All Files (*.*)|*.*||"; CFileDialog a(TRUE, " *.bmp", NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter, NULL); a.DoModal(); if(a.GetFileName()) {memDC.PatBlt(0, 0, maxX, maxY, PATCOPY); CDib pDib(a.GetFileName()); BYTE *pBmBits = pDib.GetDibBitsPtr(); LPBITMAPINFO pBmInfo = pDib.GetDibInfoPtr(); UINT bmWidth = pDib.GetDibWidth(); UINT bmHeight = pDib.GetDibHeight(); StretchDIBits(memDC, 0, 0, bmWidth, bmHeight, 0, 0, bmWidth, bmHeight, pBmBits, pBmInfo, DIB_RGB_COLORS, SRCCOPY); InvalidateRect(NULL); }} void CMainWin:: OnPaint(){CPaintDC dc(this); dc.BitBlt(0, 0, maxX, maxY, & memDC, 0, 0, SRCCOPY); } void CMainWin:: OnExit() {SendMessage(WM_CLOSE); } // файл cdib.cpp #include < afxwin.h> #include " cdib.h" #include " windowsx.h" CDib:: CDib(const char* fileName){LoadBitmapFile(fileName); }CDib:: ~CDib() { GlobalFree(m_pBmInfo); } void CDib:: LoadBitmapFile (const char* fileName){ CFile file(fileName, CFile:: modeRead); BITMAPFILEHEADER bmFileHeader; file.Read((void*)& bmFileHeader, sizeof(bmFileHeader)); if (bmFileHeader.bfType! = 0x4d42) { AfxMessageBox(" Not a bitmap file"); m_pBmFileHeader = 0; m_pBmInfo = 0; m_pBmInfoHeader = 0; m_pRGBTable = 0; m_pDibBits = 0; m_numColors = 0; } else { DWORD fileLength = file.GetLength(); DWORD dibSize = fileLength - sizeof(bmFileHeader); BYTE* pDib = (BYTE*)GlobalAlloc(0, dibSize); file.Read((void*)pDib, dibSize); file.Close(); m_pBmInfo = (LPBITMAPINFO) pDib; m_pBmInfoHeader = (LPBITMAPINFOHEADER) pDib; m_pRGBTable = (RGBQUAD*)(pDib + m_pBmInfoHeader-> biSize); int m_numColors = GetDibNumColors(); m_pBmInfoHeader-> biSizeImage = GetDibSizeImage(); if (m_pBmInfoHeader-> biClrUsed == 0) m_pBmInfoHeader-> biClrUsed = m_numColors; DWORD clrTableSize = m_numColors * sizeof(RGBQUAD); m_pDibBits = pDib + m_pBmInfoHeader-> biSize + clrTableSize; }} DWORD CDib:: GetDibSizeImage(){ if (m_pBmInfoHeader-> biSizeImage == 0) { DWORD byteWidth = (DWORD) GetDibWidth(); DWORD height = (DWORD) GetDibHeight(); DWORD imageSize = byteWidth * height; return imageSize; } else return m_pBmInfoHeader-> biSizeImage; } UINT CDib:: GetDibWidth() { return (UINT) m_pBmInfoHeader-> biWidth; }UINT CDib:: GetDibHeight() {return (UINT) m_pBmInfoHeader-> biHeight; } UINT CDib:: GetDibNumColors() { if ((m_pBmInfoHeader-> biClrUsed == 0) & & (m_pBmInfoHeader-> biBitCount < 9)) return (1 < < m_pBmInfoHeader-> biBitCount); else return (int) m_pBmInfoHeader-> biClrUsed; } LPBITMAPINFOHEADER CDib:: GetDibInfoHeaderPtr() { return m_pBmInfoHeader; } LPBITMAPINFO CDib:: GetDibInfoPtr() { return m_pBmInfo; } LPRGBQUAD CDib:: GetDibRGBTablePtr() { return m_pRGBTable; } BYTE * CDib:: GetDibBitsPtr() { return m_pDibBits; } 8.6 Контрольні завдання

1. Пояснити різницю між графічними форматами DDB та DIB.

2. Пояснити організацію структур зображень типу DIB.

3. Реалізувати обробник із ініціалізацією масиву – вмісту бітової таблиці графічного файла.

4. Реалізувати програму, що забезпечує відкриття файлів із розширенням *.bmp.

 


9 Елементи КОНЦЕПЦІЇ “ДОКУМЕНТ – ВИГЛЯД”

9.1 Загальні особливості концепції “Документ – вигляд”

Слід зауважити, що протягом восьми попередніх розділів розглядалася лише одна концепція програмування засобами Visual C++. Ця концепція передбачала розробку програми на основі щонайменше двох основних класів: класу головного вікна (породжуваного від CFrameWnd або CDialog) та класу при-кладки (породжуваного від CWinApp). Об’єкти цих класів – об’єкти прикладки і вікна забезпечували працездатність практично усієї програми. При цьому практично завжди створювався пустий проект типу “Win32 Application”, до якого додавалися необхідні класи, об’єкти та функції. Таким чином, побудова проекту проваджувалася “з чистого аркуша”.

Але є й інші підходи. Вони тією чи іншою мірою реалізують концепцію швидкої розробки (RAD – rapid application development), в якій певна структура програми має організовуватися автоматично засобами середовища програмування. У Visual C++ ця концепція підтримується програмними проектами типу MFC AppWizard (див. підрозділ 1.1) та проектами більш складного типу. Слід зазначити, що й більшість літератури з програмування на Visual C++(наприклад [6, 9]) акцентує увагу на створенні програм саме у цей спосіб. Щоправда, програміст-початківець, створивши засобами Application Wizard свій проект, може задати запитання: чому порожня програма займає декілька сторінок тексту, складається з декількох класів та багатьох функцій і чи всі ці класи та функції є конче необхідними? Також може виникати певний сумнів у тому чи повністю програміст контролює поведінку створюваного проекту, чи може призвести поведінка програми до неконтрольованих наслідків.

Як наведено протягом 8-ми розділів, створення проектів на базі класів вікна та прикладки є досить прозорим і дозволяє наочно продемонструвати реалізацію об’єктно-орієнтованого програмування для вирішення завдань розробки інтерфейсів програмного забезпечення. Але такий підхід має і окремі вади, а саме: дані та спосіб їх подання є тісно пов’язаними між собою. Через такий взаємний зв’язок усі поля даних розміщуються в межах одного класу вікна. У цьому ж класі вказується яким чином дані мають відображатися, що не завжди бажано, наприклад, коли дані спочатку виводяться на екран комп’ютера, а потім – друкуються за допомогою принтера. Якщо програма складається лише з класів прикладки та вікна, поняття даних та способу їх подання змішуються.

В архітектурі концепції “Документ – вигляд” все побудовано інакше. Вона у своїй основі орієнтується на розробку програм, що мали б забезпечувати обробку документів різного типу, тому у ній дані чітко відокремлені від способу їх подання – вигляду документа. Клас області перегляду (або вигляду) дозволяє керувати введенням даних від користувача. При цьому самі дані розміщуються у класі створення документа.

Програми, що підтримують таку концепцію, породжують документ від класу CDocument, а об’єкт вигляду – від класу CView. Щоправда у таких програмах зберігаються і “старі” класи – породжені від класу головного (діалогового) вікна та класу прикладки, причому клас вікна має зменшену роль, тому що CView перекриває у більшості функцій клас CFrameWnd.

У концепції “Документ – вигляд” документом є блок даних, з яким співпрацює програма, а виглядом документа є фізичне відображення даних. Вигляд даних є неоднозначним і неоднаковим, наприклад під час виведення на екран або на принтер. Можна сказати, що документ є “чистими” даними, тоді як вигляд є конкретним способом їх відображення.

У Microsoft Windows програми на основі концепції “Документ – вигляд” можуть будуватися на основі інтерфейсу SDI (single document interface – інтерфейс одного документу) та MDI (multi-document interface – інтерфейс багатьох документів). З точки зору користувача різниця між двома інтерфейсами полягає у способі відображення документів.

SDI відображує кожен новий документ у новій копії програми. Це наявно демонструється програмою Internet Explorer, де кожна нова сторінка відображається за допомогою нового запуску програми. Програма, побудована відповідно до інтерфейсу MDI міститиме декілька вікон одночасно. Під час побудови проектів типу “MFC AppWizard” можна обрати будь-який з інтерфейсів, хоча Microsoft з точку зору побудови самої операційної системи як базовий інтерфейс рекомендує SDI.

Класи MFC дозволяють автоматизувати зберігання документів у файлах на диску. Цей процес має назву серіалізації – від назви функції Serialize() класу CDocument. Клас CDocument підтримує стандартні операції створення доку-мента, завантаження та збереження.

 

9.2 Програмна реалізація концепції “Документ – вигляд”

9.2 1 Динамічне створення об’єктів

У програмах обробки документів усі об’єкти є динамічними. Таким чином документи можуть породжуватися в ході виконання програми, завантажуватися, зберігатися та копіюватися з іншим ім’ям. Через це класи документа, вигляду та вікна мають підтримувати динамічне створення об’єктів. Процес забезпечується спеціальними макрокомандами:

 

DECLARE_DYNCREATE(class_name)

IMPLEMENT_DYNCREATE(class_name, base_class_name)

 

Їх параметрами є class_name – ім’я класу (не вміщене у лапки), для якого оголошується можливість динамічного створення об’єктів та base_class_name –ім’я базового класу (також не вміщене у лапки).

Можна вказати на подібність двох вказаних макросів макрокомандам оголошення карти повідомлень програми. Перша – лише оголошує потенційну можливість процесу (на разі – динамічного створення об’єктів), тоді як друга – безпосередньо реалізує властивість.

Макрокоманда DECLARE_DYNCREATE використовується для оголошення можливості динамічного створення (під час виконання програми) об’єктів класів, наслідуваних від CObject. Така макрокоманда дозволяє створювати документи у динамічний спосіб, наприклад, під час зчитування їх з файлів під час здійснення серіалізації. DECLARE_DYNCREATE має включатися у файл заголовків проекту.

Друга макрокоманда – IMPLEMENT_DYNCREATE має дозволити динамічне створення об’єктів класів, породжених від CObject, під час виконання програми. Цей макрос додається у *.cpp-файл програми.

Якщо використовуються макроси DECLARE_DYNCREATE та IMPLEMENT_DYNCREATE, можна використовувати ще один макрос – RUNTIME_CLASS та функцію-член CObject:: IsKindOf() для визначення класу об’єктів під час виконання програми.

 

9.2.2 Загальний порядок створення програми

Визначимо особливості створення програми відповідно концепції “Документ – вигляд”. Зазначимо, що при створенні проекту типу “MFC AppWizard” така послідовність здійснюється автоматично без втручання програміста.

Для створення програми, що відповідає концепції “Документ – вигляд” необхідно здійснити такі кроки:

1) створити класи прикладки, головного вікна програми, документа, вигляду;

2) дозволити динамічне створення об’єктів класів головного вікна, документа та вигляду;

3) створити шаблон документа, що має об’єднати класи головного вікна, документа та вигляду;

4) реалізувати обробку командного рядка програми;

5) перевизначити необхідні функції класів програми, наприклад COblect:: Serialize(); або CView:: OnDraw();

 

9.2.3 Створення класів програми

Під час створення класів прикладки та головного вікна слід зауважити, що клас головного вікна міститиме меншу кількість функцій, а клас прикладки – більшу через підтримку механізму серіалізації. Клас прикладки, як і раніше, створюється як нащадок класу CWinApp.

Для класу головного вікна, виводиться з класу CFrameWnd, має забезпечуватися динамічне створення об’єктів. Таким чином опис класу вікна міститиме макрос DECLARE_DYNCREATE(). Клас головного вікна також включатиме всі об’єкти елементів керування вікна. Приклад 9.1 демонструє такий клас вікна.

 

Приклад 9.1 – Реалізація класу головного вікна відповідно до концепції “Документ – вигляд”

 

сlass CMainFrame: public CFrameWnd

{DECLARE_DYNCREATE(CMainFrame)

public: CMainFrame ();

DECLARE_MESSAGE_MAP()

};

Клас документа породжується від класу CDocument. Він також містить макрос DECLARE_DYNCREATE() для забезпечення динамічного створення об’єктів. Також клас документа у складі містить карту повідомлень усіх команд, пов’язаних із змінами стану документа. Функції класу мають забезпечувати обробку даних документа.

Деякі функції класу CDocument мають перевизначатися. Наприклад, функція virtual BOOL CDocument:: OnNewDocument();

Доволі часто наново визначається також і функція Serialize(). Приклад 9.2 ілюструє створення класу документа.

 

Приклад 9.2 – Вигляд класу документа для проекту відповідно до кон-цепції “Документ – вигляд”

 

class CSampleDoc: public CDocument

{DECLARE_DYNCREATE(CSampleDoc)

public:

CSampleDoc();

BOOL OnNewDocument();

void Serialize(Carchive & arch);

DECLARE_MESSAGE_MAP()

};

 

Клас вигляду забезпечує керування відображенням документа. Об’єкт класу перекриває об’єкт головного вікна програми і забезпечує виконання основних функцій. При цьому такі операції, як зміна розміру вікна та згортання-розгортання все-таки залишаються за класом головного вікна та його обробниками. Клас вигляду є нащадком класу CView або будь-якого дочірнього до CView класу (наприклад CScrollView). Клас вигляду також оголошується динамічним і містить макрос DECLARE_DYNCREATE().

Клас СView містить ряд корисних функцій. Під час створення програми не обов’язково перевизначати більшість з них. Але одна функція – OnDraw() має перевизначатися завжди. OnDraw() викликається якщо вигляд документа програми має оновлюватися і у цьому сенсі нагадує функцію OnPaint(). OnDraw() має такий прототип:

 

virtual void CView:: OnDraw (CDC* pDC) = 0;

 

де pDC – є покажчиком на контекст пристрою, що має використовуватися для відображення документа. Зазначимо, що раніше у функції OnPaint() було необхідно отримувати поточний контекст пристрою вікна, а у функції OnDraw() він є параметром за замовчуванням. Функція OnDraw() має перевизначатися у кожному класі, дочірньому від СView.

Приклад 9.3 демонструє вигляд класу вигляду у своїй найстислішій формі.

 

Приклад 9.3 – Клас вигляду відповідно до концепції “Документ – вигляд”

сlass CSampleView: public CView

{DECLARE_DYNCREATE(CSampleView)

public: void OnDraw(CDC *dc);

DECLARE_MESSAGE_MAP()

};

 

Для забезпечення увімкнення режиму динамічного створення об’єктів необхідно, по-перше, додати макроси DECLARE_DYNCREATE() до описів відповідних створюваних класів, по-друге, – додати у програмний файл макрокоманди IMPLEMENT_ DYNCREATE() для класів вікна, вигляду та документа:

 

IMPLEMENT_ DYNCREATE(CMainFrame, CFrameWnd)

IMPLEMENT_ DYNCREATE(CSampleView, CView)

IMPLEMENT_ DYNCREATE(CSampleDoc, CDocument)

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.