Міністерство освіти і науки молоді та спортуУкраїни
Національний університет „Львівська політехніка”
Кафедра ЕОМ
Розрахункова-графічна робота
з дисципліни об’єктна орієнтоване програмування
РОЗРОБКА ДІАЛОГОВИХ ПРОГРАМ ЗАСОБАМИ MFC
Мета: Оволодіти навиками розробки програм з графічними діалоговими інтерфейсами з використанням бібліотеки класів MFC.
ТЕОРЕТИЧНІ ВІДОМОСТІ
Концепція роботи windows програм
Програма, що написана мовою С/С++, з консольним інтерфейсом працює від початку функції main до її кінця. Для здійснення операцій вводу/виводу програма викликає функції вводу/виводу операційної системи (ОС). ОС не викликає прикладну програму. Windows програма з віконним інтерфейсом працює навпаки. Програма тільки запускається операційною системою і все. Далі програма нічого не робить, а чекає поки не отримає повідомлення від ОС, яке потім буде опрацьовуватися. Повідомлення – це сигнал про те, що відбулася деяка подія. Будь-яка подія супроводжується повідомленнями, що надсилаються або конкретному вікну, кільком вікнам, чи всім вікнам одразу. Деякі події можуть породити ще кілька подій, наприклад створення вікна супроводжується його перемальовуванням. Прикладами події є переміщення курсору мишки, натискання кнопки, тощо.
На відміну від звичайних С/С++ програм, де операції в програмі виконувалися лінійно, в Windows програмах виконується опрацювання повідомлень, які з’являються в довільному порядку, тобто неочікувано (асинхронно). Цим Windows програма схожа на обробник переривань.
Повідомлення мають унікальний номер і часто мають символьні мнемонічні позначення, наприклад WM_PAINT замість 0x000F, і два числові параметри. Список повідомлень є у файлі winuser.h. Сюди можна додати свої повідомлення з унікальними номерами. М
Повідомлення передається програмі від ОС через спеціальну функцію Windows. Після чого вони надходять в чергу повідомлень програми, яка об’являється наступним макросом в класі діалогу: DECLARE_MESSAGE_MAP(). При надходжені повідомлення з черги на обробку відбувається пошук його номера в карті повідомлень. При наявності номера повідомлення в карті повідомлень відбувається виклик зв’язаного з повідомленням обробника. Повідомлення, що відслідковуються і мають свої нестандартні обробники заносяться між макросами BEGIN_MESSAGE_MAP і END_MESSAGE_MAP.
Макрос обробника повідомлення має наступну структуру: тип повідомлення, наприклад ON_BN_CLICKED, ON_COMMAND,....; номер повідомлення; назва обробника події.
Наприклад:
BEGIN_MESSAGE_MAP(C***App, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CLogin, CDialog)
ON_BN_CLICKED(IDOK, OnBnClickedOk)
END_MESSAGE_MAP()
Події можна генерувати вручну методами SendMessage – синхронний метод (чекає поки повідомлення не буде опрацьоване), PostMessage – асинхронний метод (не чекає на опрацювання повідомлення, а продовжує виконання програми).
Структура віконної діалогової MFC програми
Бібліотека Microsoft Foundation Classes (MFC) дає можливість розробляти GUI-застосунки для Microsoft Windows на мові C++ з використанням багатого набору бібліотечних класів. Велика частина MFC є відносно тонким об'єктно-орієнтованим шаром над Windows API. Це рішення, з одного боку, підвищує продуктивність, але, з другого боку, успадковує всі недоліки дизайну Windows API і перешкоджає перенесенню програм на інші платформи.
Типова діалогова програма, що написана з використанням бібліотеки класів MFC складається з двох основних класів: класу C***App і класу C***Dlg, де замість зірочок по замовчуванню мітиться назва проекту.
Клас C***App містить метод InitInstance(), з якого починається виконання програми і створення об’єкту програми theApp. В функції InitInstance() ініціюється черга повідомлень, створюється об’єкт діалогу, до нього приєднується вікно діалогу і діалог відображається на екрані. Початково діалог містить 2 кнопки “OK” і “Cancel”. Кожна з них має свій обробник, який можна редагувати.
Клас C***Dlg містить функції OnInitDialog() та OnPaint(). В функції OnInitDialog() налаштовується зовнішній вигляд вікна діалогу та можна робити деякі початкові налаштування і присвоєння до моменту відображення діалогу. На момент виклику більшість об’єктів вже створено. Функція OnPaint() здійснює вивід вікна діалогу на екран. Кожен з класів містить карту повідомлень.
При створенні проекту діалогової програми у MS Visual Studio ці класи генеруються автоматично. Особливістю класу діалогу є те, що у нього інкапсулюються об’єкти, що прив’язані до контролів (кнопок, радіо кнопок, полів введеня тощо), меню, та інші об’єкти, що реалізують бізнес логіку програми.
Структура бібліотеки класів MFC
Структура бібліотеки класів MFC відображена на діаграмі класів (див. рис.1). В основі більшості класів бібліотеки MFC лежить базовий клас CObject. Як видно з рис. 1 клас, що забезпечує роботу з діалогами (CDialog), знаходиться в ієрархії класів CObject → CCmdTarget → CWnd. Отже, завдяки спадкуванню, клас діалогу CDialog володіє всією функціональність цих класів. Найціннішим у цій ієрархії є клас CWnd, який має множину методів, що забезпечують керування відображенням діалогу, обмін даними між контролами і змінними до яких вони прив’язані за допомогою механізму DDX/DDV; методи взаємодії з чергою повідомлень, меню, стандартними обробниками деяких подій, таймером. Базовий віконний клас CWnd описаний нижче.
Члени Дані
m_hWnd – містить хендл вікна (HWND), що відповідає вікну.
Функції стану вікна
GetActiveWindow – Повертає активне вікно.
GetFocus – Повертає об’єкт CWnd, що є у фокусі.
GetWindowContextHelpId – Повертає ідентифікатор контексту довідки.
ModifyStyle – Модифікує стиль поточного вікна.
SetWindowContextHelpId – Встановлює ідентифікатор контексту довідки.
Розмір і позиціонування вікна
CloseWindow – Мінімізує вікно.
GetClientRect – Повертає розміри клієнтської області вікна.
GetWindowRect – Повертає екранні координати вікна.
SetWindowPos – Changes Змінює розмір, розташування і порядок дочірніх, виринаючих (pop-up) вікон і вікон верхнього рівня.
SetWindowRgn – Встановлює область вікна.
Функції доступу до вікна
FindWindow – Повертає хендл вікна, яке ідентифікується за допомогою імені і класу вікна
GetDlgCtrlID – Якщо вікно CWnd є дочірнім, то виклик цього методу повертає його ідентифікатор.
GetDlgItem – Повертає контрол, що розташований у вікні діалозгу, якому відповідає ідентифікатор, що передається у метод через параметр.
UpdateData – Встановлює значення у контрол, або читає значення з контролу, який розташований на діалозі.
UpdateDialogControls – Викликаєтсья для оновлення стану контролів на діалозі.
Методи Оновлення/Перемалювання вікна
GetDC – Повертає контекст відображення клієнтської області вікна.
GetWindowDC - Повертає контекст відображення цілого вікна включаючи заголовок вікна, меню і елементи прокрутки (scroll bars).
Invalidate – Перемальовує (оновлює) клієнтську область.
ReleaseDC – Вивільняє контексти клієнтської області і вікна, забезпечуючи доступ іншим засобам.
ShowWindow – Показує/приховує вікно.
Функції перетворення координат
ClientToScreen – Перетворює координати точки або прямокутника з системи координат клієнтської області вікна у систему координат екрану.
MapWindowPoints – Перетворює множину точок з просторо координат поточного вікна у прості координат іншого вікна.
ScreenToClient – Перетворює екранні координати вказаної точки або прямокутника у систему координат клієнтської області вікна.
Текстові функції вікна
GetWindowText – Повертає текст, що міститься у вікні, або заголовок вікна (caption).
SetWindowText – Встановлює текст у вікні або заголовок вікна (caption).
GetFont – Повертає поточний стиль тексту.
SetFont – Встановлює поточний стиль тексту.
Функції взаємодіє з елементами діалогів
GetDlgItemInt – Перетворює текст, що міститься у контрлі на діалозі, у цілочисельне.
GetDlgItemText – Повертає заголовок, або текст, що асоціюється з контролом.
SendDlgItemMessage – Посилає повідомлення контролу на вікні.
Функції по роботі з меню
GetMenu – Повертає вказівник на меню діалогу.
SetMenu – Встановлює вказане меню як меню діалогу.
Функції по роботі з таймером
SetTimer – Встановлює системний таймер, що посилає при спрацюванні повідомлення WM_TIMER.
KillTimer – Усуває системний таймер.
Функції повідомлень
MessageBox – Створює і відображає вікно з вказаним повідомленням.
Фіунції керування повідомленнями вікна
PostMessage – Розміщує повідомлення у черзі повідомлень програми, після чого завершує свою роботу не чекаючи на опрацювання розміщеного повідомлення.
PreTranslateMessage - Використовується CWinApp для фільтрації повідомлень вікнам перед тим як вони надсилаютсья у віконні функції TranslateMessage і DispatchMessage.
SendMessage - Sends a message to the CWnd object and does not return until it has processed the message.
Перевизначаються
DoDataExchange – Використовується механізмом DDX/DDV. Викликається методом UpdateData.
WindowProc – Забезпечує віконну процедуру для даного вікна (Класично – саме віконна процедура здійснює керування опрацюванням повідомлень (визначає який метод яке повідомлення опрацьовує), але у MFC, по замовчуванню, керування опрацюванням повідомлень відбувається через карту повідомлень.
Команда довідки Обробники і Функції
OnHelp – Викликається при натисканні кнопки F1 (Довідка).
Обробники повідомлень ініціалізації
OnInitMenu – Викликається перед активацією меню.
OnInitMenuPopup - Викликається перед активацією виринаючого (pop-up) меню.
Загальні обробники повідомлень
OnClose – Викликається при надходжені сигналу закриття вікна.
OnCreate – Викликається при створені вікна.
OnCtlColor - Викликаєтсья коли поточне вікно є батьківським вікном контрола перед тим, як контрол буде перемальованим.
OnSize – Викликається коли розмір поточного вікна змінився.
Обробники повідомлень операцій введення
OnChar – Викликається коли натиснута несистемна клавіша.
OnLButtonDblClk – Викликається при подвійному натисканні лівої кнопки мишки.
OnLButtonDown - Викликається при натисканні лівої кнопки мишки.
OnLButtonUp - Викликається при відтисканні лівої кнопки мишки.
OnMouseMove – Викливкаєтсья коли курсор мишки перемістився.
OnMouseWheel – Викликається коли користувач прокрутив колесико мишки .
OnTimer – Викливкається при спрацюванні таймеру, що створений методом SetTimer.
Опертаори
operator HWND – Викливається щоб отримати хендл вікна.
ЗАВДАННЯ
Написати віконну діалогову програму, яка записує і читає з файлової бази даних текстову інформацію про об’єкти, що описують предметну область задану варіантом. Програма має відповідати наступним вимогам:
а) Забезпечити перевірку на коректність введення даних за допомогою механізму виключних ситуацій. При спробі введення некоректних даних відобразити на екрані відповідне повідомлення за допомогою методу MessageBox та скасувати операцію.
б) Для введення даних використати елемент керування типу Edit Box, а вміст файлової бази даних відобразити у елементі керування типу List Box. Позначити призначення елементів керування за допомогою групуючи контролів (Group Box).
в) Продублювати функції кнопок запису/читання у меню.
г) Передбачити можливість вибору файлу, з яким відбуватиметься робота у процесі виконання програми за допомогою діалогу вибору файлу.
д) Шляхом спадкування від класу CStdioFile або CFile створити власний клас, який забезпечуватиме буферизований запис даних у файл (Запис даних спочатку здійснюється в програмний буфер. При спробі додати нову порцію даних у повний буфер спочатку має відбуватися запис всіх даних з буферу у файл, очищення буферу і лише тоді додавання цієї порції даних у порожній буфер). Буфер реалізувати за допомогою структури даних з бібліотеки STL визначеній варіантом. Розмір буферу визначається варіантом.
Скомпілювати та відлагодити програму.
Скласти звіт про виконану роботу з приведенням тексту програми та результату її виконання.
Дати відповідь на контрольні запитання.
ПРЕДМЕТНІ ОБЛАСТІ
Варіант
Завдання
1
Базовий клас:
class Device
{
public:
Device(char* fName);
~Device();
virtual bool Open() = 0;
virtual bool Close() = 0;
virtual bool Execute(char* cmd, void* prm) = 0;
virtual bool Status(int ext=0) {return isOpened;}
protected:
char* deviceName;
char* friendlyName;
bool isOpened;
};
Device() – конструктор базового класу. Виділяє пам‘ять під змінну friendlyName та ініціалізує її.
~Device() – деструктор базового класу. Вивільняє пам‘ять віділену під змінні deviceName (!якщо виділено!) та friendlyName. Друкує повідомлення якщо робота з пристроєм не була корректно завершена.
Open() – відкриває пристрій для роботи. Виділяє пам‘ять та ініціалізує змінну deviceName, встановлює змінну isOpened. Друкує повідомлення, про те що пристрій готовий до роботи.
Close() – завершує роботу з пристроєм. Друкує повідомлення, та встановлює змінну isOpened у відповідний стан.
Execute() – виконує команду специфічну для кожного пристрою.
Status() – повертає стан пристрою.
Похідний клас Printer.
Атрибути:
bool canPrint;
char* ptrBuf;
Команди для функції Execute():
“Print” – друкує вмістиме буферу
“Write” – завантажує текст у буфер (prm – розглядати як char*), змінює значення змінної canPrint.
“Clear” – обнулює вмістиме буферу, змінює значення змінної canPrint
+ Перевизначити функцію Status() – коли (ext == 1) повертати значення (isOpened && canPrint).
Визначити конструктор та деструктор (!вивільняти всі ресурси!) класу.
ВАРІАНТИ ЗАВДАННЬ
Варіант
№ предметної області
Структура даних
Розмір буферу
1
1
queue
5
2
2
vector
4
3
3
list
3
4
4
deque
6
5
5
map
4
6
6
multimap
5
7
1
vector
5
8
2
List
4
9
3
deque
3
10
4
Map
5
11
5
multimap
4
12
6
queue
6
13
1
List
2
14
2
deque
3
15
3
Map
4
16
4
multimap
3
17
5
queue
5
18
6
vector
3
19
1
deque
4
20
2
Map
5
21
3
multimap
4
22
4
queue
3
23
5
vector
4
24
6
List
5
25
1
Map
6
26
2
multimap
4
27
3
queue
5
28
4
vector
3
29
5
List
4
30
6
deque
5
Запис у файл здійснюється за таким кодом:
Частина коду програми
void CMyInt::WriteString(CString d,CString f,CString p)
{
if (lst.size()<4)
{
lst.insert(lst.end(), d);
lst.insert(lst.end(), f);
lst.insert(lst.end(), p);
}
else{
CFileDialog OpenDialog(false, "txt", NULL,
OFN_HIDEREADONLY, "Text Files (*.txt)|*.txt||");
if(OpenDialog.DoModal() == IDOK){
char buf[255];
try{
CStdioFile file(OpenDialog.GetPathName(), CFile::modeCreate |
CFile::modeNoTruncate | CFile::modeWrite);
file.SeekToEnd();
deque<CString>::iterator i;//мій метод
for(i=lst.begin(); i != lst.end(); i++){
sprintf_s(buf,"%s\n",(*i).GetBuffer(255));
file.WriteString(buf);}
sprintf_s(buf,"%s\n",d);
file.WriteString(buf);
sprintf_s(buf,"%s\n",f);
file.WriteString(buf);
sprintf_s(buf,"%s\n",p);
file.WriteString(buf);
file.Close();
lst.clear();}
catch (CInvalidArgException* ex)
{return;}
catch (CFileException* ex)
{return;}
catch (...)
{return;}}}}
Читання з фалу здійснюється за таким кодом:
Частина коду програми
void CRGRDlg::OnBnClickedRead()
{CString data;
CString buff[255];
int j = 0;
int i = 0;
CFileDialog dlg(true,"txt",NULL,OFN_FILEMUSTEXIST|OFN_HIDEREADONLY,"Text files (*.txt)|*.txt||");
if(dlg.DoModal() == IDOK){
m_List.DeleteAllItems();
CStdioFile file(dlg.GetPathName(),CFile::modeRead);
file.SeekToBegin();
while(file.ReadString(data)){
buff[j] = data;
j++;}
LVITEM lv;
for(int i = 0; i < j; i+=3){
m_List.InsertItem(i,buff[i]);}
int p = 0;
for(int i = 1; i < j; i+=3){
lv.mask = LVIF_TEXT;
lv.iSubItem = 1;
lv.iItem = p;
lv.pszText = (LPTSTR)(LPCTSTR)buff[i];
m_List.SetItem(&lv);
p++;}
p = 0;
for(int i = 2; i < j; i+=3){
lv.mask = LVIF_TEXT;
lv.iSubItem = 2;
lv.iItem = p;
lv.pszText = (LPTSTR)(LPCTSTR)buff[i];
m_List.SetItem(&lv);
p++;}}
UpdateData(false);}
Успадкування класу CStdioFile а також використання методу deque здійснюється за таким кодом:
Частина коду програми
#include <deque>//мій метод
#include<functional>
#include <iterator>
#pragma once
using namespace std;
class CMyInt : public CStdioFile
{
deque<CString> lst;
char* deviceName;
…
}
Скріншот діалогового вікна програми:
Результат роботи програми:
Висновок: на цій розрахункові роботі я навчився навикам розробки програм з графічними діалоговими інтерфейсами з використанням бібліотеки класів MFC.
І створив власну програму.