Создание диалогового окна и работа с ним требует выполнение следующей последовательности действий:
· Определение шаблона окна в редакторе диалоговых окон.
· Определение диалоговой процедуры.
Диалоговая процедура должна иметь спецификатор CALLBACK, так как она вызывается операционной системой. Имя можен быть произвольным, но сложилась традиция завершать это имя префиксом DlgProc. Функция принимает тот же набор параметров, что и оконная процедура. Однако есть отличия:
Оконная процедура возвращает значение типа LRESULT, а диалоговая - BOOL;
Если оконная процедура не обрабатывает какое-то сообщение, то она вызывает DefWindowProc. Если диалоговая процедура не обрабатывает какое-то обращение, то она возвращает FALSE. Если же сообщение ею обрабатывается, то она возвращает TRUE.
Диалоговая процедура не обрабатывает сообщения WM_CREATE. Вместо этого она выполняет инициализацию при обработке специального сообщения WM_INITDIALOG.
Диалоговая процедура не обрабатывает сообщение WM_PAINT, так как все функции в ней реализуются элементами управления.
Первым сообщением, которое получает и обрабатывает диалоговая процедура, является WM_INITDIALOG. Если после обработки этого сообщения процедура возвращает TRUE, то Windows помещает фокус ввода на первое окно элемента управления, которое имеет стиль WS_TABSTOP. Можно установить фокус ввода на любой элемент управления функцией SetFocus, но тогда диалоговая процедура должна вернуть значение FALSE.
HWND SetFocus(HWND hWnd // Дескриптор элемента упраления, в котрором устанавливается фокус, // получают функцией GetDlgItem (смотри выше));
В блоке сообщения WM_INITDIALOG можно инициализировать любой из элементов управления, если в этом есть необходимость.
Основным сообщением, обрабатываемым в диалоговой процедуре является сообщение WM_COMMAND. Если источником сообщения является элемент управления, младшее слово параметра wParam содержит идентификатор элемента управления, старшее слово параметра wParam содержит код уведомления, а параметр lParam – дескриптор элемента управления.
Обработав сообщения WM_COMMAND диалоговая процедура должна вызвать функцию
BOOL EndDialog(
HWND hDlg, // дескриптор диалогового окна INT_PTR nResult // значение возвращаемое из функции (TRUE или FALSE));
· Вызов функции создания диалогового окна из окна, в котором этот диалог создается (вызов из родительского окна)
Функция создания окна диалога
INT_PTR DialogBox(HINSTANCE hInstance, // дескриптор экземпляра приложения LPCTSTR lpTemplate, // идентификатор шаблона диалога, преобразованный с помощью макроса // MAKEINTRESOURCE к типу LPCTSTR HWND hWndParent, // дескриптор родительского окна для окна диалога DLGPROC lpDialogFunc //имя диалоговой процедуры);
Если окна диалога не было создано, по каким то причинам, то функция возвращает 0.
· Организация обмена данными между диалоговой процедурой и функцией, вызывающей окно. Обмен осуществляется через глобальные объекты, так как параметры процедуры строго регламентированы.
Функция читает символьный текст из элемента управления
UINT GetDlgItemText(HWND hDlg, // дескриптор диалогового окна int nIDDlgItem, // идентификатор элемента управления, ассоциируемый с извлекаемым текстом LPTSTR lpString, // буфер, куда записывается извлекаемый текст int nMaxCount // максимальное количество символов, копируемых в буфер lpString);
Функция записывает символьный текст в элемент управления
BOOL SetDlgItemText(HWND hDlg, // дескриптор диалогового окна int nIDDlgItem, // идентификатор элемента управления, ассоциируемый с помещаемым текстом LPCTSTR lpString // буфер, откуда берется текст для размещения в элемент управления);
Функция читает символьное изображение десятичного числа из элемента управления и преобразует его к целочисленному значению
UINT GetDlgItemInt(HWND hDlg, // дескриптор диалогового окна int nIDDlgItem, // идентификатор элемента управления, ассоциируемый с извлекаемым текстом BOOL * lpTranslated, // записывается признак успешности преобразования BOOL bSigned // если параметр TRUE, то учитывается знак минус при преобразовании и возвращается //значение типа int. При этом пробел между минусом и первой цифрой не допускается);
Функция записывает символьное изображение целого десятичного числа в элемент управления
BOOL SetDlgItemInt(HWND hDlg, // дескриптор диалогового окна int nIDDlgItem, // идентификатор элемента управления, ассоциируемый с помещаемым текстом UINT uValue, // целое, которое преобразуется к строке BOOL bSigned // если параметр TRUE, то учитывается знак минус при преобразовании. // При этом пробел между минусом и первой цифрой не допускается);
Задание на лабораторную работу
1. Создайте не пустой проект Win32 Project с именем – ваша_ фамилия2.
Откройте файл ваша_ фамилия2.срр и рассмотрите как при обработке сообщения WM_COMMAND, с параметром wParam, равным IDM_ABOUT, вызывается функция создания диалогового окна About
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
Проанализируйте параметры вызываемой функции DialogBox и рассмотрите функцию обратного вызова (Обработчик сообщений для окна "О программе") с именем About.
Запустите проект. Рассмотрите диалоговое окно. Познакомьтесь, как выглядят файлы Resource.h и ваша_ фамилия2.rc.
- Внесение картинки в диалоговое окно.
Измените диалоговое окно About. Вызовите окно Ресурсов, в папке Dialog щелкните по строке IDD_ABOUTBOX, открыв таким образом редактор диалоговых окон. Справа должна появиться панель Панель элементов редактора диалоговых окон. Эта панель содержит кнопки для создания элементов управления всех типов, которые можно добавлять в диалоговое окно. Рассмотрите их.
Если по каким-либо причинам панель инструментов не появится, ее можно вызвать через подменю Панель элементов меню Вид.
Измените внешний вид диалогового окна. Удалите текст и значок. Увеличьте размер окна.
Добавим новый рисунок, размером примерно 64 х 90 пиксел, в окно из файла logoMTUSI.bmp, который необходимо разместить в папку вашего проекта, а затем включить его в состав ресурсов проекта. В окне Ресурсов щелкните правой кнопкой. В сплывающем окне выберите подменю Добавить ресурс…, затем выделите пункт Bitmap, нажмите кнопку Импорт, выберите файл logoMTUSI.bmp. В окне Свойств измените предлагаемый по умолчанию идентификатор в окне свойств изображения на IDB_LOGOMTUSI.
Подготовительная работа завершена, теперь можно размещать рисунок на форме диалога.Откройте редактор диалога для диалога IDD_ABOUTBOX. На Панели элементов редактора диалоговых окон щелкните мышью по кнопке Picture Control. Повторите щелчок в том месте формы диалога, куда хотите разместить картинку.
Двойным щелчком мышью на элементе управления PictureControl (он должен быть активным) вызовите диалоговое окно Своства для этого элемента. Введите в окно элемента его идентификатор IDC_LOGO. В поле свойств Тип выберите значение Точечный рисунок. Выбор этого значения откроет поле Изображение, в котором можно найти только один идентификатор IDB_LOGOMTUSI, так как других растровых образов в файле описания ресурсов пока что нет. Выберите этот идентификатор.
В нижней панели главного меню в левом углу найдите кнопку Проверить диалоговое окно и отожмите ее. Эта кнопка дает возможность увидеть, как выглядит не форма вашего диалога, а реальное отображение этого диалога при выполнении.
3. Добавление элементов управления Надпись (Text).
В окне диалога разместите четыре надписи:
Лабораторная работа № 2 |
Тема: Изучение диалоговых окон |
Студент группы номер_группы фамилия |
2012-2013 уч.год |
Первую и четвертую надпись выровнять по центру, вторую и третью по левому краю. Первую строку сделать в рамке. Во второй строке применить табуляцию.
На панели Панели элементов щелкните мышью по кнопке Static Text и повторите щелчок на форме диалога в том месте, где будет располагаться первая строка. Растяните мышью прямоугольник элемента Static так, чтобы его размеры вместили нужный текст. Вызовите окно свойств элемента управления двойным щелчком. Редактор диалога присвоил идентификатор по умолчанию этому элементу управления IDC_STATIC, а так как в ходе выполнения приложения не будут изменяться атрибуты этого элемента, то его не стоит изменять, добавим только 1, сделаем его IDC_STATIC_1.
В поле Caption должно содержать текстовую строку, которая будет отображаться в прямоугольнике элемента Static Text. Этот текст можете ввести либо непосредственно в прямоугольник, либо в поле Подпись. Введите первую строку текста. В строке, если нужно, могут использоваться управляющие символы табуляции(\t) и перевода строки (\n). Задайте выравнивание относительно прямоугольника в поле Выравнивание текста (по умолчанию установлен Left). С помощью полей Граница и Статическая граница можно установить рамку вокруг элемента управления. Оцените вид диалога с помощью кнопки Проверить диалоговое окно.
Сформируйте оставшиеся строки. Оцените вид диалога с помощью кнопки Проверить диалоговое окно.
Запустите проект. Рассмотрите диалоговое окно. Рассмотрите, как изменились файлы Resource.h и ваша_ фамилия2.rc.
4. В этой части задания необходимо создать диалоговое окно, через которое пользователь сможет вводить фамилию, имя, год рождения студента. Полученную информацию нужно преобразовать в строку: фамилия + первая буква имени + точка, вычислить возраст студента на текущий год и вывести строку и возраст в клиентское окно.
Откройте редактор меню и добавьте на уровень 0 вашего меню
Имя пункта | Тип пункта | Идентификатор | Позиция |
Ввод информации о студенте | команда | ID_GET |
В окне Ресурсов, в папке Dialog добавьте Добавить ресурс…, Dialog, Создать.
Проектирование шаблона диалога начинается с установки его свойств. Измените стандартный идентификатор диалогового окна на идентификатор IDD_GET, назначьте диалоговому окну заголовок: Ввод информации о студенте.
Для элементов управления установите следующие атрибуты:
Элемент | 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 | - | По умолчанию |
5. Для диалогово окна с идентификатором IDD_GET необходимо создать функцию обратного вызова, обрабатывающую сообщения от этого окна, дав ей имя, например GetDataDlgProc.
(Создавая такую функцию, обычно копируют функцию обратного вызова диалогового окна About и изменяют ее, меняя ее имя, и добавляя нужные элементы.)
Функция с именем GetDataDlgProc должна выглядеть так:
BOOL CALLBACK GetDataDlgProc (HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
// с помощью функции SetFocus здесь нужно установить фокус ввода
// на элемент управления с идентификатором IDC_GET_FAM
return FALSE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
// Здесь необходимо организовать чтение информации из элементов
// управления –вызвать функцию, которая будет это осуществлять
EndDialog(hDlg,TRUE);
return TRUE;
case IDCANCEL:
// Здесь обработку данных, указывающую на то, что ввод
// не осуществлялся
// установки признака пустой не введенной информации
EndDialog(hDlg, FALSE);
return TRUE;
}
break;
}
return FALSE;
}
В файле ваша_ фамилия2.h создайте две структуры, описывающие шаблон входной информации и информации на выходе:
#include "resource.h"
#include <time.h>
#define LENFAM 20
#define LENIMIA 15
#define LENFAMI 25
struct StudBeg { TCHAR fam[LENFAM]; // фамилия студента
TCHAR imia[LENIMIA]; // его имя
UINT godRojd; // его год рождения
};
struct StudEnd { TCHAR famI[LENFAMI];// фамилия студента с инициалом
// имени, после которого стоит точка
UINT let; // возраст
};
Добавьте в проект вашего приложения новый файл с расширением.срр и запишите в него функции, организующие ввод информации, ее обработку и вывод информации о студенте
В файл не забудьте подключить файлы:
#include "stdafx.h"
#include " ваша_ фамилия2. h"
Чтение информации из элементов управления диалогового окна осуществите с помощью функции GetStud
Разберитесь как функция GetStud получает информацию из элементов управления и как осуществляется контроль правильности ввода этой информации.
StudBeg GetStud (HWND hDlg)
{ StudBeg studBeg;
TCHAR buf[100]=TEXT("");
BOOL lpFam=TRUE,lpImia=TRUE,lpGod;
GetDlgItemText(hDlg,IDC_GET_FAM,studBeg.fam,20);
if(*studBeg.fam == 0)
{
wcscpy(buf, L" ошибка ввода фамилии!");
lpFam=FALSE;
}
GetDlgItemText(hDlg,IDC_GET_IMIA,studBeg.imia,12);
if(*studBeg.imia == 0)
{
wcscpy(buf+wcslen(buf), L" ошибка ввода имени!");
lpImia=FALSE;
}
studBeg.godRojd = GetDlgItemInt(hDlg,IDC_GET_GOD,&lpGod,FALSE);
if (lpGod ==FALSE||studBeg.godRojd <1970)
wcscpy(buf+wcslen(buf), L" ошибка ввода года!");
if (lpGod == FALSE||
studBeg.godRojd < 1970||
lpFam == FALSE||
lpImia == FALSE)
{
MessageBox(hDlg,buf, TEXT("Сообщение об ошибке ввода"), MB_OK);
// установки признака пустой не введенной информации
*studBeg.fam=0;
*studBeg.imia = 0;
studBeg.godRojd = 0;
}
return studBeg;
}
Определите глобальный объект StudBeg studBeg={ TEXT(""), TEXT(""),0}; и организуйте в функции обратного вызова главного окна обработку сообщения WM_COMMAND от пункта меню с идентификатором ID_GET вызовом функции
DialogBox(hInst, MAKEINTRESOURCE(IDD_GET), hWnd, GetDataDlgProc);
Доработайте функцию обратного вызова GetDataDlgProc, организовав вызов нужных функци при поступлении сообщений от диалогового окна ввода.
Проверьте работу этого диалогового окна.
5. Создайте функцию, которая будет преобразовывать введенную информацию.
Подключите файл <time.h>, в котором находятся прототипы стандартных фукци, которые позволят в функции получить системную текущую дату и обработать ее
StudEnd obrabotkaInfo(const StudBeg& studBeg)
{
StudEnd studEnd={TEXT(" ",0)};
// получить текущую дату - текущий год newtime.tm_year+1900
// смотрите в Help пример применения функции _localtime64_s
char buf[26];
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;
// запись информации о студенте в новом виде
if(let > 0 && studBeg.godRojd >=1970)
{swprintf(studEnd.famI,23,L"%s %c.",studBeg.fam,*studBeg.imia);
studEnd.let=let;
}
return studEnd;
}
6. Вывод информации можно сделать непосредственно в клиентское окно. Для этого создайте функцию PutStud и осуществите ее вызов из блока case WM_PAINT
Функцию PutStud разместите в том же файле, где размещена функция obrabotkaInfo.
void PutStud (HDC hDc)
{
StudEnd studEnd = obrabotkaInfo(studBeg);
if(studEnd.let)
{
int x=50,y=50;
int tabstop[]={-130, 200, 250};
TCHAR buf[100];
// Собираем информацию из studEnd в одну строку
swprintf(buf,100,L"фамилия:\t%s\tвозраст:\t%d",
studEnd.famI,studEnd.let);
int len=wcslen(buf);
// Эта функция рисует строку в клиентском окне
TabbedTextOut(hDc,x,y,buf,len,3, tabstop, x);
}
}
НЕ ЗАБУДЬТЕ ПРОПИСАТЬ ПРОТОТИПЫ ВСЕХ ВЫЗЫВАЕМЫХ ФУНКЦИЙ.
Проверьте работу приложения.
7. Вывод информации можно осуществлять и в диалоговое окно. Сделайте и такой вывод.
Добавьте в меню следующие пункты.
Пункт главного меню (0-й уровень)
Имя пункта | Тип пункта | Идентификатор | Позиция |
Ввод - вывод | подменю | - |
Пункты подменю «Ввод - вывод» (1-й уровень)
Имя пункта | Тип пункта | Идентификатор |
Ввод информации о студенте | команда | ID_GET |
Вывод информации о студенте | команда | ID_PUT |
Создайте диалоговое окно.
В окне Resource View, в папке Dialog добавьте Add Resource, Dialog, New. Проектирование шаблона диалога начинается с установки его свойств.Установите идентификатор диалогового окна IDD_PUT, заголовок: Вывод информации о студенте.
Для элементов управления установите следующие атрибуты:
Элемент | ID | Заголовок | Свойства |
Static text | IDC_STATIC | Фамилия | По умолчанию |
Static text | IDC_STATIC | Возраст | По умолчанию |
Edit control | IDC_PUT_FAM | - | Read-only |
Edit control | IDC_PUT_LET | - | Read-only |
Удалите кнопку Cancel, оставив кнопку OK.
Создайте диалоговую процедуру с именем PutDataDlgProc
BOOL CALLBACK PutDataDlgProc (HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
// здесь необходимо вызвать функцию, инициалицирующую окно // диалога выходными данными
// (записывающую в окно выходную информацию)
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
EndDialog(hDlg,TRUE);
return TRUE;
case IDCANCEL:
// не смотря на то, что кнопки Cancel нет,
// это сообщение обрабатывается при нажатии кнопки
// закрытия диалогового окна
EndDialog(hDlg, FALSE);
return TRUE;
}
break;
}
return FALSE;
}
Функцию PutStudDlg пропишите в тот файл, где размещена функция obrabotkaInfo и вызовите в диалоговой процедуре PutDataDlgProc.
void PutStudDlg (HWND hDlg)
{
StudEnd studEnd = obrabotkaInfo(studBeg);
if(studEnd.let)
{ SetDlgItemText(hDlg,IDC_PUT_FAM,studEnd.famI);
SetDlgItemInt(hDlg,IDC_PUT_LET,studEnd.let,FALSE);
}
}
Саму диалоговую процедуру PutDataDlgProc вызовите в процедуре обратного вызова WndProc в блоке обработки сообщения WM_COMMAND, case ID_PUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_PUT), hWnd, PutDataDlgProc);
НЕ ЗАБУДЬТЕ ПРОПИСАТЬ ПРОТОТИПЫ ВСЕХ ВЫЗЫВАЕМЫХ ФУНКЦИЙ!
Проверьте работу приложения.
При защите общей части этой лабораторной работы вы должны продемонстрировать преподавателю практические навыки работы в графическом редакторе, умение читать и понимать созданное вами приложение и уметь отвечать на теоретические вопросы, список которых приводится ниже.
1. Какой заголовок имеет диалоговая процедура?
2. Какие основные отличия оконной процедуры главного окна от диалоговой процедуры?
3. Дайте понятие модального диалогового окна.
4. Какие окна называются немодальные?
5. С помощью какой функции можно получить дескриптор элемента управления?
6. Перечислите последовательность действий программиста по созданию диалога в приложении?
7. При вызове какой функции устанавливается соответствие между диалоговым окном и его диалоговой процедурой? Перечислите параметры этой функции.
8. Как осуществляется обмен данными между диалоговой процедурой и функцией, организующей вызов этого окна?
9. Какими функциями можно прочитать и записать текстовую информацию в элемент управления диалогового окна?
10. Какими функциями можно прочитать и записать целую числовую информацию в элемент управления диалогового окна?
11. Какими функциями можно прочитать и записать действительную числовую информацию в элемент управления диалогового окна?
12. Как определяются статические объекты?
13. Какова область видимости статического объекта и его время жизни?
14. Как и когда происходит инициализация статических объектов?
15. Какие объекты следует определять как статические?