Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
лабораторная , сем 2, ЯП.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
1.05 Mб
Скачать

Задание на лабораторную работу

В лабораторной работе необходимо создать приложение, которое вводит информацию о студенте (фамилию, имя, год рождения) через диалоговое окно и накапливает ее в преобразованном виде (фамилия, имя, возраст) в массиве, который отображается в управляющем элементе Список (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( &ltime );

errno_t err = ctime_s( buf, 26, &ltime );

// struct tm

tm newtime;

_localtime64_s( &newtime, &ltime );

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. Добавим диалоги в приложение. Вспомним последовательность действий, необходимых сделать для этого.

  1. Определение шаблона окна в редакторе диалоговых окон.

  2. Определение диалоговой процедуры.

  3. Вызов функции создания диалогового окна из окна, в котором этот диалог создается (вызов из родительского окна )

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

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

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(""));

Запустите проект и проверьте работу приложения.