
- •1 Курс, 1 семестр
- •230105 Программное обеспечение вычислительной техники и автоматизированных систем
- •График выполнения лабораторных работ 2 семестр
- •Рубежный контроль курсового проекта ( 50 баллов)
- •Блок-схемы алгоритмов и откорректированные после выполнения тексты только тех функций, которые реализуют приложения индивидуальных заданий.
- •Общие требования к разрабатываемым текстам приложений, выполняемых в лабораторных работах и в курсовой работе
- •Лабораторная работа №1
- •Теоретический материал Ресурсы Windows – приложения
- •Вызов редактора меню
- •Задание на лабораторную работу
- •Лабораторная работа №2
- •Теоретический материал
- •Создание и обработка диалогового окна
- •Задание на лабораторную работу
- •Индивидуальные задания к лабораторной работе № 2
- •Задание на лабораторную работу
- •Варианты индивидуальных заданий
- •Лабораторная работа №3
- •Задание на лабораторную работу
- •Варианты индивидуальных заданий
- •Лабораторная работа №4
- •Теоретический материал
- •Задание на лабораторную работу
- •Лабораторная работа №5
- •Задание на лабораторную работу
- •Варианты индивидуальных заданий
Задание на лабораторную работу
В лабораторной работе необходимо создать приложение, которое вводит информацию о студенте (фамилию, имя, год рождения) через диалоговое окно и накапливает ее в преобразованном виде (фамилия, имя, возраст) в массиве, который отображается в управляющем элементе Список (List Box) диалогового окна. Работа с информацией в массиве строк (вставка, просмотр, удаление) осуществляется стандартными процедурами управляющего элемента Список (List Box).
1. Создайте не пустой проект Win32 Project с именем – ваша_фамилия _4.
2. В файле ваша_фамилия _4.h создайте два новых типа (две структуры), описывающие шаблон входной информации и информации на выходе:
#define NF 30
#define NI 20
#define NL 5
struct StudBeg { TCHAR fam[NF]; // фамилия студента
TCHAR imia[NI]; // его имя
UINT godRojd; // его год рождения
};
struct StudEnd { TCHAR fam[NF]; // фамилия студента
TCHAR imia[NI]; // его имя
TCHAR let[NL]; // возраст
};
Определите константу NLINE значение которой равно размеру объекта типа StudEnd - сумме NF+NI+NL
#define NLINE (NF+NI+NL)
и создайте новый тип (объединение), используя ключевое слово union.
Объединение – это частный случай структуры. Отличается от структуры тем, что, в отличии от структуры, все его поля данных начинаются с одного адреса (занимают одну и ту же память). Размер объекта такого типа равен размеру самого длинного элемента union.
union Union { StudEnd studEnd;
TCHAR str[NLINE ];
};
Использование такого типа позволит в приложении к одной и той же памяти объекта типа Union обращаться либо как к элементам структуры studEnd, либо как строке str.
3. Создайте в проекте файл ваша_фамилия _4_ОБРАБОТКА.cpp и поместите в него две функции.
Первая функция с заголовком void Clear(Union& u) должна получать по ссылке объект u типа Union и заполнять пробелами все символы строки u.str , кроме символов с индексами NF-1 и NF+NI-1. В эти символы строки необходимо записать символ ‘║’, который будет разделительным символом в строке для визуального деления на колонки строки управляющего элемента Список (List Box). Графическое изображение этого символа в текстовом редакторе можно получить путем набора кода 186 на правой цифровой клавиатуре при нажатой клавише Alt, или преобразовав число 9553 (значение кода UNICODE этого символа) к типу wchar_t . Строка u.str должна иметь символ конца!
void Clear(Union& u)
{ int MaxLenU=sizeof(u)/sizeof(TCHAR);
TCHAR probel=TEXT(' ');
for(int i=0; i<MaxLenU; ++i)
if(i==NF-1||i==(NF+NI-1))
u.str[i]=TCHAR(9553);// '║' код этого символа в , но его
// можно нарисовать на экране, набрав Alt/186
else
u.str[i]=probel;
u.str[MaxLenU-1]=0;
}
Вторая функция Union obrabotkaInfo(const StudBeg& studBeg), получив через объект по ссылке начальную информацию о студенте, должна вычислить его возраст.
Union obrabotkaInfo(const StudBeg& studBeg)
{
// получить текущую дату - текущий год newtime.tm_year+1900
// смотрите в Help пример применения функции _localtime64_s
char buf[230];
time_t ltime;
time( <ime );
errno_t err = ctime_s( buf, 26, <ime );
// struct tm
tm newtime;
_localtime64_s( &newtime, <ime );
int let=0;
// вычисление возраста относительно текущего года
if(studBeg.godRojd)
let = (newtime.tm_year+1900) - studBeg.godRojd;
Union u;
// запись информации о студенте склеивается в строку u.str
if(let > 0 && studBeg.godRojd >=1980)
{Clear(u);
int lenF = wcslen(studBeg.fam),lenI=wcslen(studBeg.imia);
wcsncpy(u.str,studBeg.fam,lenF);
wcsncpy(u.str+NF,studBeg.imia,lenI);
swprintf(u.str+NF+NI,TEXT("%-3d"),let);
// целое let приводится к типу TCHAR* в функции swprintf
}
return u;
}
Локальный объект u типа Union обработан функцией Clear, а затем результирующая информация о студенте копируется в строку u.str так, чтобы фамилия, имя и возраст попали в область каждого из данных u.studEnd.fam, u.studEnd.imia, u.studEnd.let( при этом каждая из указанных строк не имеет соответственно признаков конца в середине строки u.str). Это было достигнуто при копировании информации функцияей wcsncpy.
Функция возвращает через возвращаемое значение значение типа Union из локального объекта u.
Прототипы функций Clear и obrabotkaInfo не забудьте поместить в файл ваша_фамилия _4.h Подключите файл <time.h>.
4. Откройте редактор меню и добавьте на уровень 0 вашего меню
Имя пункта |
Тип пункта |
Идентификатор |
Позиция |
Просмотр информации о студенте |
команда |
IDM_VIEW |
2 |
В окне Окно Ресурсов (Resource View), в папке Dialog добавьте Добавить ресурс …(Add Resource), Dialog, Создать (New). В этом окне будет организован просмотр накапливаемой в массиве строк информации о студентах.
Увеличьте ширину первоначальной формы диалога примерно вдвое. Проектирование шаблона диалога начинается с установки его свойств. Их можно оставить такими, какие предлагаются по умолчанию. Лучше присвоить свое имя, например установите идентификатор диалогового окна IDD_VIEW, надпись сделайте: Информация о студентах.
Добавьте в окно диалога, кроме уже присутствующих кнопок OK и Cancel, следующие элементы управления с атрибутами:
Элемент |
ID |
Заголовок |
Свойства |
Group Box |
IDC_STATIC |
- |
По умолчанию |
Static text |
IDC_STATIC |
Фамилия |
По умолчанию |
Static text |
IDC_STATIC |
Имя |
По умолчанию |
Static text |
IDC_STATIC |
Возраст |
По умолчанию |
List Box |
IDC_LIST1 |
- |
По умолчанию |
Button |
IDC_REC_ADD |
Добавить запись |
По умолчанию |
Button |
IDC_REC_DELETE |
Удалить запись |
По умолчанию |
Ширину окна списка, возможно, придется менять на этапе тестирования приложения, для того, чтобы в окне списка полностью видеть все три поля каждой записи (поле Фамилии, поле Имя, поле Возраст.
5. Диалоговое окно IDD_VIEW кнопкой Добавить запись должно вызывать диалоговое окно, через которое будет вводиться информация о студентах. Создадим его шаблон.
В окне Окно Ресурсов (Resource View), в папке Dialog добавьте Добавить ресурс …(Add Resource), Dialog, Создать (New).
Установите идентификатор диалогового окна IDD_ADD_REC, заголовок: Ввод информации о студенте.
Для элементов управления установите следующие атрибуты:
Элемент |
ID |
Заголовок |
Свойства |
Static text |
IDC_STATIC |
Фамилия |
По умолчанию |
Static text |
IDC_STATIC |
Имя |
По умолчанию |
Static text |
IDC_STATIC |
Год рождения |
По умолчанию |
Edit control |
IDC_GET_FAM |
- |
По умолчанию |
Edit control |
IDC_GET_IMIA |
- |
По умолчанию |
Edit control |
IDC_GET_GOD |
- |
По умолчанию |
6. Добавим диалоги в приложение. Вспомним последовательность действий, необходимых сделать для этого.
Определение шаблона окна в редакторе диалоговых окон.
Определение диалоговой процедуры.
Вызов функции создания диалогового окна из окна, в котором этот диалог создается (вызов из родительского окна )
Организация обмена данными между диалоговой процедурой и функцией, вызывающей окно. Обмен осуществляется через глобальные объекты, так как параметры процедуры строго регламентированы.
Первый шаг из этой последовательности уже проделан – построены шаблоны двух диалоговых окон, окна для ввода и окна для вывода .
7. Создадим диалоговую оконную процедуру с именем ViewDlgProc для окна с идентификатором IDD_VIEW. Каждый раз при построении новой диалоговой оконной процедуры берите за основу диалоговую процедуру окна ABOUT, меняйте в этой копии имя функции и добавляйте обработку тех сообщений, которые будет обрабатывать эта процедура.
Функция ViewDlgProc должна обрабатывать два сообщения WM_INITDIALOG и WM_COMMAND. Источником сообщения WM_COMMAND являются четыре элемента управления – кнопки Добавить запись (IDC_REC_ADD), Удалить запись(IDC_REC_DELETE), OK (IDOK), Отмена (IDCANCEL), идентификаторы которых будут находиться в младшем слове параметра wParam. То есть, вы должны создать такую функцию:
BOOL CALLBACK ViewDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
// Сюда вставим код обработки
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_REC_ADD:
// Сюда вставим код обработки
break;
case IDC_REC_DELETE:
// Сюда вставим код обработки
break;
case IDOK:
EndDialog(hDlg,TRUE );
return TRUE ;
case IDCANCEL:
EndDialog(hDlg, FALSE);
return TRUE;
}
}
return FALSE;
}
Определите в файле ваша_фамилия _4.h новую константу, которая будет определять максимальное количество элементов в массиве, состоящем из элементов типа Union.
#define MAX 100
В этом массиве будет храниться информация о студентах. Определите в оконной процедуре ViewDlgProc следующие объекты:
static Union masU[MAX];
static int nU = 0;
static HWND hListBox;
Union itemU;
Задумайтесь и объясните себе и преподавателю, почему объекты masU, nU, hListBox следует определить как static?
В блоке обработки сообщения WM_INITDIALOG сделайте инициализацию списка hListBox элементами массива masU (первоначально какое значение имеет объект nU?):
hListBox = GetDlgItem(hDlg,IDC_LIST1);
for (int i = 0; i < nU && i < MAX; ++i)
SendMessage(hListBox,LB_ADDSTRING,0,(LPARAM)masU[i].str);
В блоке обработки сообщения WM_COMMAND, case IDOK организуйте обратные действия – информацию из списка hListBox скопируйте в массив masU, предварительно определив количество копируемых строк из списка:
nU = SendMessage(hListBox,LB_GETCOUNT,0,0);
for(int i=0; i<nU && i < MAX; ++i)
SendMessage(hListBox,LB_GETTEXT,i,(LPARAM)masU[i].str);
Таким образом, открывая диалоговое окно, приложение будет копировать информацию из массива в в список, закрывая диалоговое окно по кнопке ОК, приложение будет обновлять информацию в массиве.
Разберитесь в параметрах функции SendMessage.
8. Для диалогового окна с идентификатором IDD_ADD_REC разработайте оконную процедуру с именем с именем GetDataDlgProc.
Чтение информации из диалогового окна осуществите с помощью функции GetStud
(эти функции разработаны вами в лабораторной работе №4).
9. Вернитесь к оконной процедуре ViewDlgProc и в блоке обработки сообщения WM_COMMAND, case IDC_REC_ADD вызовите диалоговое окно IDD_ADD_REC. Если вызов окна закончился нажатием кнопки ОК, обработайте полученную информацию функцией obrabotkaInfo и добавьте новую информацию в список.
BOOL dlgYes = DialogBox((HINSTANCE)GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_ADD_REC),
hDlg,GetDataDlgProc);
if(dlgYes)
{itemU = obrabotkaInfo(studBeg);
SendMessage (hListBox,LB_ADDSTRING,0,(LPARAM)itemU.str);
}
Запустите проект и проверьте работу приложения.
10. В окне управляющего элемента Список разделительный символ ‘|’для визуального деления на колонки строки при вводе информации в разных строках оказался зрительно на разном расстоянии от края окна, хотя в выводимой строке эти символы находятся на одних и тех же знакоместах. Это произошло от того, что в назначаемом по умолчанию шрифте разные буквы имеют разную ширину и нам не удалось достигнуть желаемого результата – обеспечить правильные границы столбцов.
Изменим ситуацию, установив новый моноширинный шрифт Courier в момент инициализации диалогового окна IDD_VIEW. В его оконной процедуре ViewDlgProc определите объект
static LOGFONT lf;
Добавьте в блок обработки сообщения WM_COMMAND, case WM_INITDIALOG следующую последовательность инструкций:
lf.lfHeight = 16;
lstrcpy((LPWSTR)&lf.lfFaceName,L"Courier");
HFONT hFont1 = CreateFontIndirect(&lf);
SendMessage(hListBox, WM_SETFONT, (WPARAM)hFont1, TRUE);
Запустите проект и проверьте работу приложения. При необходимости расширьте окно элемента Список.
11. Организуйте обработку сообщения от управляющего элемента IDC_REC_DELETE в блоке обработки сообщения WM_COMMAND оконной процедуры ViewDlgProc. Для этого необходимо осуществить контроль того, выделена ли строка на удаление, и если да, то удалить ее, в противном случае предложить осуществить ее выделение:
int curItem = SendMessage(hListBox, LB_GETCURSEL, 0, 0);
if (curItem != LB_ERR )
SendMessage(hListBox, LB_DELETESTRING, curItem, 0);
else
{MessageBox(hDlg,
L"сначала надо выделить элемент списка",
L"ОШИБКА",
MB_OK);
break;
}
Запустите проект и проверьте работу приложения.
12. Измените форму вывода выходной информации в диалоговое окно IDD_VIEW. Сделайте копию вашего проекта в другую папку и эту копию измените. В новом варианте в окне элемента Список будем показывать только фамилию студента, а остальную информацию о студенте – его имя и возраст покажем в дополнительных окнах. В дополнительных окнах будет показываться информация для выделенной в окне элемента Список фамилии студента.
Откройте редактор диалога и уменьшите ширину окна элемента Список так, чтобы туда вмещалась только фамилия.
Добавьте в шаблон диалогового окна следующие элементы управления с атрибутами:
Элемент |
ID |
Заголовок |
Свойства |
Static text |
IDC_STATIC |
Имя |
По умолчанию |
Static text |
IDC_STATIC |
Возраст |
По умолчанию |
Edit control |
IDC_ IMIA |
- |
Установить дополнительно флажок Read-only |
Edit control |
IDC_LET |
- |
Установить дополнительно флажок Read-only |
13. Создайте в файл ваша_фамилия_на_латинице_ОБРАБОТКА.cpp две функции
TCHAR* getImia(TCHAR* buf,Union u) и TCHAR* getLet (TCHAR* buf,Union u), которые в строке buf создают строку - копию имени и возраста с признаком конца строки, копируя эту информацию из полученного через параметры значения Union.
TCHAR* getImia(TCHAR* buf,Union u) { wmemcpy(buf,u.studEnd.imia,NI); buf[NI-1]=0; return buf; } |
TCHAR* getLet(TCHAR* buf,Union u) { wmemcpy(buf,u.studEnd.let,NL); buf[NI-1]=0; return buf; }
|
14. Определите в оконной процедуре ViewDlgProc объект TCHAR buf[NLINE];
Добавьте в блок обработки сообщения WM_COMMAND обработку обработку уведомления LBN_SELCHANGE (текущий выбор строки в списке был изменен) от управляющего элемента Список case IDC_LIST1. Это уведомление содержит старшее слово параметра wParam:
case IDC_LIST1:
switch(HIWORD(wParam))
{
case LBN_SELCHANGE:
{
int curItem = SendMessage(hListBox,LB_GETCURSEL,0,0);
SendMessage(hListBox,LB_GETTEXT,curItem,(LPARAM)itemU.str);
SetDlgItemText(hDlg,IDC_LET, getLet ( buf,itemU));
SetDlgItemText(hDlg,IDC_IMIA,getImia( buf,itemU));
return TRUE;
}
}
break;
Запустите проект и проверьте работу приложения.
15. Протестируйте работу приложения для режима удаления информации о студенте. Обратите внимание на нежелательный эффект – информация о студенте удалена (выделение в окне списка отсутствует), а в окнах Имя и Возраст осталась информация удаленного студента. Чтобы избавиться от этого, почистите эти окна, добавив в блок обработки сообщения WM_COMMAND, case IDC_REC_DELETE:
SetDlgItemText(hDlg,IDC_LET, TEXT(""));
SetDlgItemText(hDlg,IDC_IMIA,TEXT(""));
Запустите проект и проверьте работу приложения.