Практикум прикладного программирования на MFC и C++ в среде VS.NET

Диалоговые окна MFC

Разбить на страницы
Показывать лекцию целиком
Файлы к данной лабораторной работе, Вы можете скачать здесь.

При работе с большинством приложений возникают ситуации, когда приложение запрашивает от пользователя некоторую информацию. В большинстве случаев для запроса открывается новое окно. Такие окна называются диалоговыми. Диалоговые окна обычно содержат несколько элементов управления и текст с пояснениями о запрашиваемой информации. В них нет такой обширной пустой рабочей области, как в редакторах.

Цель работы

  • Более гибко использовать диалоговые окна
  • Вызывать другие диалоговые окна и получать введенную в них пользователем информацию, а затем использовать ее в главном окне приложения
  • Использовать стандартные диалоговые окна и конструируемые диалоги
  • Использование существующих (системных) диалоговых окон

    В библиотеке MFC (как и в других подобных библиотеках) заготовлены некоторые виды типовых диалоговых окон для взаимодействия с пользователем:

  • Окна сообщений
  • Общие и стандартные диалоги
  • Окна сообщений

    Простые диалоговые окна сообщений реализуются двумя функциями

  • MessageBox() - является членом класса CWnd, поэтому доступна только для потомков этого класса. Это означает, что ее можно вызывать только из оконного класса или класса элемента управления. Имеет три параметра, которые можно передавать по порядку один, два или три
  • AfxMessageBox() - применяется тогда, когда нужно открыть окно сообщения из класса, не являющегося потомком CWnd. Имеет два параметра. Ее можно вызывать и из класса-потомка CWnd
  • Назначение параметров по порядку:

  • Текст сообщения, размещаемый в клиентской области окна
  • Текст заголовка окна сообщения (необязательный, а у функции AfxMessageBox() - отсутствует вообще)
  • Определяет кнопки и пиктограммы, которые размещаются в окне сообщения (необязательный). Если этот параметр необходим, то должен быть указан и второй параметр, пусть даже в виде пустой строки. Для комбинированного параметра применяется операция побитового ИЛИ для идентификаторов кнопок и пиктограмм
  • Сочетание кнопок и пиктограмм, определяемых третьим параметром (у функции AfxMessageBox() - вторым), предопределено, поэтому если необходимо что-то иное, придется создать свое диалоговое окно, похожее на стандартное. Ниже приведены все возможные значения третьего параметра

    Идентификаторы комбинации кнопок в третьем параметре функции MessageBox()
    Идентификатор Кнопки
    MB_ABORTRETRYIGNORE Три кнопки: Abort (Прервать), Retry (Повторить), Ignore (Пропустить)
    MB_OK Кнопка OK
    MB_OKCANCEL Две кнопки: OK, Cancel (Отмена)
    MB_RETRYCANCEL Две кнопки: Retry (Повторить), Cancel (Отмена)
    MB_YESNO Две кнопки: Yes (Да), No (Нет)
    MB_YESNOCANCEL Три кнопки: Yes (Да), No (Нет), Cancel (Отмена)
    MB_CANCELTRYCONTINUE Три кнопки: Cancel (Отмена), Try Again (Повторить попытку), Continue (Продолжить)
    Идентификаторы пиктограмм в третьем параметре функции MessageBox()
    Идентификатор Пиктограммы
    MB_ICONINFORMATION Информационное сообщение
    MB_ICONQUESTION Вопросительный знак
    MB_ICONSTOP Знак остановки
    MB_ICONEXCLAMATION Восклицательный знак

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

    Идентификаторы результатов, возвращаемый функцией MessageBox()
    Идентификатор Кнопка, которую выбрал пользователь
    IDABORT Abort (Прервать)
    IDRETRY Retry (Повторить)
    IDIGNORE Ignore (Пропустить)
    IDYES Yes (Да)
    IDNO No (Нет)
    IDOK OK
    IDCANCEL Cancel (Отмена)
    IDTRYAGAIN Try Again (Повторить попытку)
    IDCONTINUE Continue (Продолжить)

    Создание заготовки приложения

  • Создайте новый проект C++ на основе MFC и назовите его Dialogs

    Ни в коем случае не называйте проекты русскими именами, поскольку оболочка использует имя проекта при автоматической генерации имен файлов проекта и классов. Компилятор из текстов на русском принимает только комментарии и строковые константы.

  • Укажите мастеру, что проект будет диалоговым приложением
  • Остальные настройки мастера оставьте по умолчанию
  • Установите для ресурсов русский язык
  • Измените заголовок формы на "свою фамилию" + " Lab7 - Диалоги"
  • Создайте макет диалогового окна, показанный на рисунке. Для этого воспользуйтесь таблицей свойств элементов управления, приведенной ниже
  • Для выравнивания элементов диалога включите и пользуйтесь панелью инструментов "Dialog Editor" оболочки

    При выравнивании группы элементов отметьте, что первый из выделенных элементов группы является опорным: все остальные элементы подравниваются под него. Точное перемещение элементов выполняйте стрелками клавиатуры. Для быстрого просмотра результатов визуального проектирования пользуйтесь кнопкой Test Dialog панели инструментов Dialog Editor оболочки.

  • Определите порядок перехода по клавише табуляции между элементами управления
  • Обеспечьте выход по кнопке Таблица настройки мастера создания каркаса приложения Свойство проекта Значение Вкладка Application Type Application Type Dialog Based Resource language: Английский (США) Project style: MFC standard Use of MFC: Use MFC in a shared DLL Вкладка Advanced Features Все сбросить! Вкладка User Interface Features Main frame styles: System menu Dialog title: Dialogs
    Таблица свойств главной диалоговой формы Dialogs
    Элемент управления Свойство Значение
    Главная форма Caption Студент Иванов. Lab7 - Диалоги
    Font(Size) MS Sans Serif(10)
    Maximize Box True
    Minimize Box True
    Button ID IDC_B_YESNOCANCEL
    Caption Да, Нет, Отмена
    Button ID IDC_B_ABORTRETRYIGNORE
    Caption Прервать, Повторить, Пропустить
    Button ID IDC_B_FILEOPEN
    Button Caption Диалог File Open
    ID IDC_B_CUSTOMDIALOG
    Caption Сконструированный диалог
    Button ID IDC_B_WHICHOPTION
    Caption Какая опция?
    Disabled True
    Static Text Caption Результаты диалога:
    Right Align Text True
    Edit Control ID IDC_E_RESULT
    Multiline True
    Auto VScroll True
    Horizontal Scroll True
    Button ID IDC_B_EXIT
    Caption Выход
  • Нажмите на пиктограмму
  • Создание переменных элементов управления (Edit Control и Button "Какая опция?"), а также обработчиков первых двух кнопок

  • Создайте и свяжите с полем редактирования и кнопкой "Какая опция?" две переменные
    Переменные элементов управления
    ID (Объект связывания) Name (Имя) Type ( Тип) Category ( Категория) Accass ( Доступ) Назначение
    IDC_E_RESULT m_strResult Value CString public Для хранения значений поля редактирования
    IDC_B_WHICHOPTION m_cWhichOption Control CButton Public Для управления блокированием кнопки
  • Создайте обработчик для щелчка на первой кнопке "Да, Нет, Отмена"
    Обработчик для щелчка по первой кнопке "Да, Нет, Отмена"
    void CDialogsDlg::OnBnClickedBYesnocancel()
    {
    	int iResults; // Для возвращаемого значения MessageBox()
    	
    	// Спросить пользователя
    	iResults = MessageBox(
    		"Щелкните по кнопке\nДа, Нет, Отмена"// В области клиента (символ новой строки)
    	   ,"Диалог \"Да, Нет, Отмена\"" // Заголовок окна (экраны)
    	   ,MB_YESNOCANCEL | MB_ICONINFORMATION // Комбинации кнопок и пиктограмм
    	   ); 	
    	
    	// Определить, по какой кнопке щелкнул пользователь
    	switch(iResults){ // переключатель
    		case IDYES:
    			m_strResult = "Да! Да! Да!";
    			break;
    		case IDNO:
    			m_strResult = "Нет, нет, нет, нет, нет.";
    			break;
    		case IDCANCEL:
    			m_strResult = "Жаль, что \"Отмена\"";
    		// break здесь необязательно, все равно последний
    	}
    	
    	// Выдать на экран
    	UpdateData(FALSE);
    }
  • По аналогии создайте обработчик для щелчка по второй кнопке "Прервать, Повторить, Пропустить", используя идентификатор комбинации кнопок MB_ABORTRETRYIGNORE и идентификатор пиктограмм MB_ICONEXCLAMATION
  • Общие (стандартные) диалоги

    В библиотеки MFC предусмотрено несколько классов C++, предназначенных для поддержки общих (стандартных) диалогов

    Классы стандартных диалогов
    Класс Тип диалога
    CFileDialog Выбор файла для чтения или записи
    CFontDialog Выбор шрифта
    CColorDialog Выбор цвета
    CPageSetupDialog Установка параметров страницы для печати
    CPrintDialog Печать
    CFindReplaceDialog Поиск и замена

    Все эти диалоговые окна используются одинаково, хотя отдельные свойства и функции класса отличаются в зависимости от назначения диалога.

    Для использования конкретного диалога нужно выполнить следующее

  • Объявить переменную типа заданного класса (создать объект на стеке). Иногда лучше создать указатель на экземпляр класса, а затем запросить у операционной системы память на куче оператором new, своевременно освободив ее оператором delete после закрытия диалога и выборки из него необходимой информации
  • Перед отображением диалога установить все его необходимые свойства
  • Для отображения диалога вызвать метод DoModal() класса. Класс CFindReplaceDialog создает немодальное окно, поэтому для него вместо метода DoModal() нужно вызывать метод Create()
  • Получить возвращаемое методом DoModal() значение, чтобы определить на какой кнопке щелкнул пользователь - на OK или Cancel
  • Если пользователь щелкнул на кнопке OK, то прочитать все необходимые для дальнейшей работы приложения свойства, которые могли быть установлены пользователем в окне диалога. Для этого имеются методы доступа к свойствам класса, которые имеет смыcл применять для чтения только после того, как завершиться выбор пользователя нажатием кнопки OK
  • Любое диалоговое окно может отображаться в двух режимах:

  • Модальном ( modal ) - всякое иное взаимодействие пользователя с приложением приостанавливается до закрытия диалога. Модальные диалоговые окна применяются тогда, когда без завершения забора информации от пользователя продолжение работы приложения будет неопределенным. Пример - типовые окна сообщений
  • Немодальном ( modeless ) - пользователь может переключиться на основное окно приложения, не завершив диалог. Пример - окно "Find and Replace" (Найти и Заменить)
  • Класс CFileDialog

    Класс CFileDialog реализует содание двух типов диалогов, который зависит от того, с каким аргументом для конструктора класса создается экземпляр - окно диалога:

    "	CFileDialog openFile(TRUE);  // создается окно Open File 
    "	    
    "	CFileDialog saveFile(FALSE); // создается окно Save File

    Конструктору можно передать несколько аргументов, задав тем самым расширения отображаемых файлов (фильтры), маршрут, начальное имя файла и начальный путь по умолчанию. Все эти аргументы конструктора имеют значения по умолчанию, так что не обязательно указывать явно ни один из них.

    Основные методы доступа класса CFileDialog
    Функция Описание
    GetPathName() Возвращает полный путь выбранного файла
    GetFileName() Возвращает имя выбранного файла
    GetFileExt() Вовращает расширение выбранного файла
    GetFileTitle() Возвращает имя выбранного фвйла без расширения (например, если был выбран файл "MyFile.txt", то вернется "MyFile"

    Примечание. Все перечисленные в таблице методы не могут вызываться до тех пор, пока не будет вызван метод DoModal() и пока он не вернет значение IDOK. Иначе в свойствах может храниться кодовый мусор.

    Класс CFontDialog

    Класс CFontDialog инкапсулирует встроенный в Windows стандартный диалог выбора шрифта. В таблице приводятся основные методы-члены класса CFontDialog.

    Основные методы доступа класса CFontDialog
    Функция Описание
    GetFaceName() Возвращает имя выбранного шрифта.
    GetStyleName() Возвращает начертание выбранного шрифта (вид шрифта, тип шрифта). К одному типу шрифта может относиться несколько различных шрифтов.
    GetSize() Возвращает размер, указанный для выбранного шрифта.
    GetColor() Возвращает цвет, указанный для выбранного шрифта.
    GetWeight() Возвращает вес, указанный для выбранного шрифта.
    IsStrikeOut() Возвращает логическое значение, позволяющее определить, был ли выбран атрибут "зачеркнутый" ( strike out ) для выбранного шрифта.
    IsUnderline() Возвращает логическое значение, позволяющее определить, был ли выбран атрибут "подчеркнутый" ( underline ) для выбранного шрифта.
    IsBold() Возвращает логическое значение, позволяющее определить, был ли выбран атрибут "полужирный" ( bold ) для выбранного шрифта.
    IsItalic() Возвращает логическое значение, позволяющее определить, был ли выбран атрибут "курсив" ( italic ) для выбранного шрифта.

    Класс CColorDialog

    Класс CColorDialog инкапсулирует стандартный диалог выбора цвета, используемый во многих Windows -приложениях для получения значений координат модели цвета RGB (RedGreenBlue) , которые затем можно передать любому методу интерфейса графических устройств GDI (Graphic Device Interface) , требующему код цвета. В таблице приводятся основные методы-члены класса CColorDialog

    Основные методы доступа класса CColorDialog
    Функция Описание
    GetColor() Возвращает выбранный цвет.
    GetSavedCustomColor() Возвращает массив созданных пользователем цветов.
    SetCurrentColor() Устанавливает текущий цвет. Вызывать данный метод следует перед вызовом метода DoModal().

    Класс CPageSetupDialog

    Класс CPageSetupDialog инкапсулирует диалог Page Setup (параметры страницы), который используется для настройки вывода на печать.Этот диалог позволяет выбрать принтер, размер и поля печатаемой страницы. В таблице приводятся основные методы-члены класса CPageSetupDialog

    Основные методы доступа класса CPageSetupDialog
    Функция Описание
    CreatePrinterDC() Возвращает контекст устройства, используемого для печати
    GetDeviceName() Возвращает имя выбранного принтера
    GetDevMode() Возвращает структуру, содержащую информацию о выбранном принтере и его возможностях (цветной или черно-белый)
    GetMargins() Этому методу в качестве аргументов передаются два указателя - либо на класс CRect, либо на структуру RECT, - а он заносит в класс или структуру размеры полей и области печати
    GetPaperSize() Возвращает класс CSize, который определяет текущий размер бумаги
    GetDriveName() Возвращает имя драйвера выбранного принтера
    GetPortName() Возвращает имя выбранного порта вывода

    Класс CPrintDialog

    Класс CPrintDialog инкапсулирует стандартный диалог Print. Он содержит большинство методов класса CPageSetupDialog, за исключением методов GetMargins() и GetPaperSize(). Прочие важные функции класса CPrintDialog приведены в таблице

    Прочие важные методы доступа класса CPrintDialog
    Функция Описание
    GetCopies() Возвращает количество печатаемых копий
    GetFromPage() Возвращает номер начальной страницы (в случае, если был задан диапазон номеров печатаемых страниц)
    GetToPage() Возвращает номер конечной страницы (в случае, если был задан диапазон номеров печатаемых страниц)
    GetPrinterDC() Возвращает дескриптор контекста устройства для указанного принтера
    PrintAll() Возвращает логическое значение, позволяющее определить, нужно ли печатать все страницы текущего документа
    PrintCollate() Возвращает логическое значение, позволяющее определить, желает ли пользователь, чтобы страницы были разобраны по копиям
    PrintRange() Возвращает логическое значение, позволяющее определить, задан ли диапазон номеров печатаемых страниц
    PrintSelection() Возвращает логическое значение, позволяющее определить, нужно ли печатать только выбранные элементы или страницы целиком

    В отличие от методов класса CPageSetupDialog, метод CreatePrinterDC() можно вызывать без предварительного вызова метода DoModal(). Отображать этот диалог перед печатью необязательно, но класс CPrintDialog можно использовать для получения информации о принтере и контексте устройства.

    Класс CFindReplaceDialog

    Класс CFindReplaceDialog инкапсулирует стандартный диалог поиска и замены. В отличии от других стандартных диалогов, это окно немодальное, поэтому для отображения данного диалога нужно вызывать вместо метода DoModal() метод Create(). Метод Create() может принимать пять параметров, два первых из которых обязательны:

  • Первый параметр - это логическое значение, указывающее, предназначается ли диалог только для поиска ( TRUE ) или для поиска и замены ( FALSE )
  • Второй параметр - строка, которую нужно искать
  • Третий параметр - строка замены
  • Четвертый параметр - направление поиска. По умолчанию задано направление "вперед" (обозначается константой FR_DOWN ). Направление "назад" устанавливается значением 0
  • Пятый параметр - указатель на родительское окно приложения
  • Принципы работы с классом CFindReplaceDialog более сложные, чем с другими классами стандартных диалогов. Мы их здесь рассматривать не будем. В таблице приводятся основные методы-члены класса CFindReplaceDialog

    Основные методы доступа класса CFindReplaceDialog
    Функция Описание
    FindNext() Возвращает логическое значение, указывающее, нужно ли найти следующее вхождение искомой строки
    GetFindString() Возвращает введенную пользователем строку для поиска
    GetReplaceString() Возвращает введенную пользователем строку для замены
    IsTerminating() Возвращает логическое значение, позволяющее определить, решил ли пользователь закрыть этот диалог
    MatchCase() Возвращает логическое значение, которое указывает, нужно ли в поиске строки учитывать регистр
    MatchWholeWord() Возвращает логическое значение, которое указывает, нужно ли искать слово только целиком
    ReplaceAll() Возвращает логическое значение, которое указывает, нужно ли заменить все вхождения искомой строки
    ReplaceCurrent() Возвращает логическое значение, которое указывает, нужно ли заменить текущее найденное вхождение искомой строки
    SearchDown() Возвращает логическое значение, которое указывает, нужно ли выполнить поиск вперед от текущей позиции

    Подключение стандартного диалога File Open к приложению

  • Создайте обработчик для кнопки "Диалог File Open"
  • Заполните его кодом
    Обработчик для щелчка по кнопке "Диалог File Open"
    void CDialogsDlg::OnBnClickedBFileopen()
    {
    	CFileDialog openFile(TRUE); // Создать диалог
    	if(openFile.DoModal() == IDOK){ // Отобразить и получить результат
    		m_strResult = openFile.GetFileName(); // Сохранить имя файла
    		UpdateData(FALSE); // Передать на экран
    	}
    }
  • Добавление собственного диалогового окна

    Добавим собственное диалоговое окно, которое будет предлагать пользователю поле редактирования, группу радиокнопок. Когда пользователь щелкнет на кнопке OK, введенный им текст отобразится в главном окне приложения. Для этого нужно будет выполнить следующие действия:

  • Добавить новое диалоговое окно к ресурсам приложения
  • Создать дизайн диалогового окна, разместив в нем необходимые элементы
  • Содать для управления ресурсом класс на базе класса CDialog
  • Связать переменные с элементами управления диалога
  • Создание макета диалогового окна

  • Выберите вкладку
  • Выделите в нем пиктограмму
  • В панели Resource View выделите сгенерированный ресурс с дежурным именем IDD_DIALOG1 и через панель свойств присвойте ресурсу осмысленный идентификатор IDD_MESSAGEDLG. Не удаляйте кнопки OK и Cancel
  • Отредактируйте ресурс диалогового окна в соответствии с таблицей свойств
    Таблица свойств диалогового ресурса IDD_MESSAGEDLG
    Элемент управления Свойство Значение
    Форма Caption Диалог с сообщениями и опциями
    Font(Size) MS Sans Serif(10)
    Maximize Box False
    Minimize Box False
    Static Text Caption Введите сообщение:
    Right Align Text True
    Edit Control ID IDC_EMESSAGE
    Multiline True
    Auto VScroll True
    Horizontal Scroll True
    Group Box Caption Выбор опции
    Radio Button ID IDC_ROPTION1
    Caption Опция 1
    Group True
    Radio Button ID IDC_ROPTION2
    Caption Опция 2
    Group False
    Radio Button ID IDC_ROPTION3
    Caption Опция 3
    Group False
    Radio Button ID IDC_ROPTION4
    Caption Опция 4
    Group False
  • При редактировании диалогового ресурса периодически проверяйте дизайн кнопкой Test Dialog панели инструментов Dialog Editor. Размеры элементов управления контролируйте через панель состояния дизайнера. Для выравнивания элементов пользуйтесь инструментами на панели инструментов или опциями меню Format оболочки.

    Окончательный вариант макета приведен на рисунке

    Отметьте, что для согласованной работы радиокнопок мы для первого переключателя установили свойство Group в состояние True. В остальных же переключателях оставили его значение по умолчанию False. Это приведет к тому, что следующие по порядку их создания радиокнопки будут объединены в группу. Новая группа начнется с нового следующего по порядку создания радиопереключателя со свойством True (но у нас только одна группа). Порядок следования радиопереключателей можно посмотреть через опцию Edit/Resource Symbols (или через контекстное меню в панели Resource View, щелкнув на узле Dialogs.rc ) в окне Resource Symbols

    Отредактировать порядок радиопереключателей можно в файле Resource.h, открыв его на редактирование через панель Solution Explorer (не рекомендуется!!!)

    В этом файле оболочка формирует именованные константы

    Именованные константы в файле Resource.h
    //{{NO_DEPENDENCIES}}
    // Microsoft Visual C++ generated include file.
    // Used by Dialogs.rc
    //
    #define IDD_DIALOGS_DIALOG              102
    #define IDR_MAINFRAME                   128
    #define IDD_MESSAGEDLG                  131
    #define IDC_B_YESNOCANCEL               1000
    #define IDC_B_ABORTRETRYIGNORE          1001
    #define IDC_B_CUSTOMDIALOG              1002
    #define IDC_B_WHICHOPTION               1003
    #define IDC_E_RESULT                    1004
    #define IDC_EMESSAGE                    1005
    #define IDC_B_FILEOPEN                  1006
    #define IDC_ROPTION1                    1006
    #define IDC_B_EXIT                      1007
    #define IDC_ROPTION2                    1007
    #define IDC_ROPTION3                    1008
    #define IDC_RADIO4                      1009
    #define IDC_ROPTION4                    1009
    ............................................

    Создание управляющего класса

    Для управления диалоговым ресурсом создайте класс на основе базового класса CDialog. Для этого:

  • Выберите только что сконструированное окно приложения в режиме дизайна и через контекстное меню (или главное меню Project ) выполните опцию Add Class

    Запустится мастер добавления класса, который нужно настроить в соответствии с рисунком

  • Убедитесь, что в поле Base class выбран CDialog

    После создания класса его код должен быть размещен в двух новых файлах MsgDlg.h и MsgDlg.cpp. Убедитесь в этом через панель Solution Explorer. Удобнее при создании новых классов размещать их в отдельных файлах. Мастер Add Class создал производный класс-потомок на основании базового класса CDialog, поддерживающего диалоговые окна

    Объявление производного класса CMsgDlg, наследника CDialog (код файла MsgDlg.h)
    #pragma once
    
    	
    // CMsgDlg dialog
    	
    class CMsgDlg : public CDialog
    {
    	DECLARE_DYNAMIC(CMsgDlg)
    	
    public:
    	CMsgDlg(CWnd* pParent = NULL);   // standard constructor
    	virtual ~CMsgDlg();
    	
    // Dialog Data
    	enum { IDD = IDD_MESSAGEDLG };
    	
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    	
    	DECLARE_MESSAGE_MAP()
    };
  • Добавьте две ассоциированные переменные к элементам управления. Для этого выделите в панели Переменные элементов управления диалога CMsgDlg ID (Объект связывания) Name (Имя) Type ( Тип) Category ( Категория) Accass ( Доступ) Назначение IDC_EMESSAGE m_strMessage Value CString public Для хранения значений поля редактирования IDC_ROPTION1 m_iOption Value int public Для распознавания выбранной радиокнопки
  • Мастер добавит в приложение код

    Файл MsgDlg.h
    class CMsgDlg : public CDialog
    {
    ................................................
    public:
    	// Для хранения значений поля редактирования
    	CString m_strMessage;
    	// Для распознавания выбранной радиокнопки 
    	int m_iOption;
    };
    Файл MsgDlg.cpp
    CMsgDlg::CMsgDlg(CWnd* pParent /*=NULL*/)
    	: CDialog(CMsgDlg::IDD, pParent)
    	, m_strMessage(_T(""))
    	, m_iOption(0)
    {
    }
    	
    void CMsgDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EMESSAGE, m_strMessage);
    	DDX_Radio(pDX, IDC_ROPTION1, m_iOption);
    }

    Для переключателя с установленным свойством Group мы назначили ассоциированную целочисленную переменную m_iOption. Значение этой переменной зависит от того, какой из переключателей группы будет выбран пользователем. При выборе первого переключателя "Опция 1" эта переменная принимает значение 0, при выборе второго - значение 1, и т.д. , поскольку в C++ нумерация элементов массива или группы начинается с нуля.

    Подключение собственного диалога к приложению

    Мы сконструировали собственный диалог, который теперь можно использовать точно также, как и стандартный диалог, а именно:

  • Объявить экземпляр класса CMsgDlg
  • Вызвать метод DoModal() экземпляра и сохранить возвращаемое им значение
  • Прочитать значения введенных ранее переменных m_strMessage и m_iOption
  • Огорчиться на себя за то, что мы нарушили главный принцип ООП (объектно-ориентированное программирование) - инкапсуляцию данных, и быстренько исправить этот огрех, переобъявив переменные как private и добавив функции доступа к этим переменным
  • Решим эту задачу в соответствии со следующими пошаговыми инструкциями

    Подключение диалога с прямым доступом к данным-членам класса CMsgDlg из класса-клиента CDialogsMsg

  • Добавьте в объявление класса-клиента переменную-экземпляр созданного нами класса CMsgDlg в соответствии с настройкой мастера, приведенной ниже. Для этого выделите в панели Class View класс CDialogsDlg и через контекстное меню откройте мастер

    Мастер добавит код

    Объявление в классе CDialogsDlg переменной-экземпляра класса CMsgDlg
    class CDialogsDlg : public CDialog
    {
    ..............................................
    private:
    	// Экземпляр класса нашего диалогового окна
    	CMsgDlg m_dMsgDlg;
    };
  • Добавьте в класс-клиент CDialogsMsg директиву препроцессора (предварительного компилятора) для подключения к нему объявления класса-сервиса CMsgDlg. Для этого через панель Solution Explorer откройте на редактирование файл DialogsMsg.h и в самом начале файла, перед объявлением класса CDialogsDlg, подключите заголовочный файл с описанием класса CMsgDlg, как показано ниже

    Подключение файла с объявлением класса-сервиса CMsgDlg 
    перед объявлением класса-клиента CDialogsDlg в файле DialogsDlg.h
    // DialogsDlg.h : header file
    //
    	
    #pragma once // Страж включения
    #include "afxwin.h"
    	
    #include "MsgDlg.h"
    // CDialogsDlg dialog
    class CDialogsDlg : public CDialog
    {
    .....................................
    };

    Обратите внимание, что в каждом заголовочном файле, созданном оболочкой, она в самом начале файла размещает директиву препроцессора "#pragma once", которую называют стражем включения. Это связано с тем, что включение файла может быть размещено во многих местах приложения, а препроцессор должен включить в приложение только первый встретившийся экземпляр кода. Эта директива и поднимает флаг у препроцессора, заставляя его игнорировать повторные включения одного и того же кода. В реализациях других производителей компиляторов можно встретить иной прием

    #ifndef ИМЯ_ВКЛЮЧАЕМОГО_ФАЙЛА
      #define ИМЯ_ВКЛЮЧАЕМОГО_ФАЙЛА
      
      	код включаемого файла
      
      #endif
  • Добавьте обработчик к кнопке "Сконструированный диалог", запускающий на выполнение окно нашего диалога

    Обработчик кнопки "Сконструированный диалог" запуска диалога
    // Обработчик кнопки "Сконструированный диалог"
    void CDialogsDlg::OnBnClickedBCustomdialog()
    {
    	// Запросить информацию через диалог
    	if(m_dMsgDlg.DoModal() == IDOK){
    		m_strResult = m_dMsgDlg.m_strMessage;// Напрямую, т.к. public
    		// разблокировать кнопку "Какая опция?"
    		m_cWhichOption.EnableWindow(TRUE);
    	}
    	else
    		m_strResult = "Ввод информации отменен!";
    	
    	// Передать на экран новое значение поля редактирования
    	UpdateData(FALSE);
    }
  • Добавьте обработчик к кнопке "Какая опция?"
    Обработчик кнопки "Какая опция?"
    // Обработчик кнопки "Какая опция?"
    void CDialogsDlg::OnBnClickedBWhichoption()
    {
    	// Какая радиокнопка включена
    	switch(m_dMsgDlg.m_iOption){
    		case 0:
    			m_strResult = "Была выбрана первая опция";
    			break;
    		case 1:
    			m_strResult = "Была выбрана вторая опция";
    			break;
    		case 2:
    			m_strResult = "Была выбрана третья опция";
    			break;
    		case 3:
    			m_strResult = "Была выбрана четвертая опция";
    			break;
    		default:
    			m_strResult = "Опция не выбрана!";
    	}
    	
    	// Передать на экран новое значение поля редактирования
    	UpdateData(FALSE);
    }
  • Запустите приложение и убедитесь в его работоспособности
  • Подключение диалога с доступом к данным-членам класса CMsgDlg из класса-клиента CDialogsMsg через функции доступа

  • Измените в объявлении класса CMsgDlg данные-члены m_strMessage и m_iOption как private
  • Добавьте к классу CMsgDlg методы доступа public, возвращающие значения этих переменных:
  • CString GetMessage() {return m_strMessage;}
  • int GetOption() {return m_iOption;}
  • Замените в последних двух обработчиках класса CDialogsMsg прямые вызовы переменных m_strMessage и m_iOption через вызовы функций доступа
  • Изменение конфигурации проекта для его автономной работы

  • Постройте окончательный вариант приложения в режиме Release и убедитесь, что размер исполнимого файла составляет примерно 15K
  • Это малый размер для такой задачи и объясняется это тем, что при создании приложения мы настроили мастер на использование библиотек DLL

    Таблица настройки мастера создания каркаса приложения
    Use of MFC: Use MFC in a shared DLL

    Такое приложение не будет работать на компьютере, где нет этих библиотек. Поэтому следует построить автономное приложение, включающее в себя весь необходимый код. Для этого:

  • Выполните опцию Project/Dialogs Properties для нашего проекта Dialogs

    Появится окно, в котором установите режим

    Изменение режима в таблице свойcтв приложения
    Use of MFC: Use MFC in a Static Library
  • Перестройте приложение и определите размер исполнимого файла
  • Исполнимый файл приложения увеличился примерно до 155K. Такой файл будет работать на любом компьютере с операционной системой Windows.

    Страницы:
    Файлы к данной лабораторной работе, Вы можете скачать здесь.

    При работе с большинством приложений возникают ситуации, когда приложение запрашивает от пользователя некоторую информацию. В большинстве случаев для запроса открывается новое окно. Такие окна называются диалоговыми. Диалоговые окна обычно содержат несколько элементов управления и текст с пояснениями о запрашиваемой информации. В них нет такой обширной пустой рабочей области, как в редакторах.

    Цель работы

  • Более гибко использовать диалоговые окна
  • Вызывать другие диалоговые окна и получать введенную в них пользователем информацию, а затем использовать ее в главном окне приложения
  • Использовать стандартные диалоговые окна и конструируемые диалоги
  • Использование существующих (системных) диалоговых окон

    В библиотеке MFC (как и в других подобных библиотеках) заготовлены некоторые виды типовых диалоговых окон для взаимодействия с пользователем:

  • Окна сообщений
  • Общие и стандартные диалоги
  • Окна сообщений

    Простые диалоговые окна сообщений реализуются двумя функциями

  • MessageBox() - является членом класса CWnd, поэтому доступна только для потомков этого класса. Это означает, что ее можно вызывать только из оконного класса или класса элемента управления. Имеет три параметра, которые можно передавать по порядку один, два или три
  • AfxMessageBox() - применяется тогда, когда нужно открыть окно сообщения из класса, не являющегося потомком CWnd. Имеет два параметра. Ее можно вызывать и из класса-потомка CWnd
  • Назначение параметров по порядку:

  • Текст сообщения, размещаемый в клиентской области окна
  • Текст заголовка окна сообщения (необязательный, а у функции AfxMessageBox() - отсутствует вообще)
  • Определяет кнопки и пиктограммы, которые размещаются в окне сообщения (необязательный). Если этот параметр необходим, то должен быть указан и второй параметр, пусть даже в виде пустой строки. Для комбинированного параметра применяется операция побитового ИЛИ для идентификаторов кнопок и пиктограмм
  • Сочетание кнопок и пиктограмм, определяемых третьим параметром (у функции AfxMessageBox() - вторым), предопределено, поэтому если необходимо что-то иное, придется создать свое диалоговое окно, похожее на стандартное. Ниже приведены все возможные значения третьего параметра

    Идентификаторы комбинации кнопок в третьем параметре функции MessageBox()
    Идентификатор Кнопки
    MB_ABORTRETRYIGNORE Три кнопки: Abort (Прервать), Retry (Повторить), Ignore (Пропустить)
    MB_OK Кнопка OK
    MB_OKCANCEL Две кнопки: OK, Cancel (Отмена)
    MB_RETRYCANCEL Две кнопки: Retry (Повторить), Cancel (Отмена)
    MB_YESNO Две кнопки: Yes (Да), No (Нет)
    MB_YESNOCANCEL Три кнопки: Yes (Да), No (Нет), Cancel (Отмена)
    MB_CANCELTRYCONTINUE Три кнопки: Cancel (Отмена), Try Again (Повторить попытку), Continue (Продолжить)
    Идентификаторы пиктограмм в третьем параметре функции MessageBox()
    Идентификатор Пиктограммы
    MB_ICONINFORMATION Информационное сообщение
    MB_ICONQUESTION Вопросительный знак
    MB_ICONSTOP Знак остановки
    MB_ICONEXCLAMATION Восклицательный знак

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

    Идентификаторы результатов, возвращаемый функцией MessageBox()
    Идентификатор Кнопка, которую выбрал пользователь
    IDABORT Abort (Прервать)
    IDRETRY Retry (Повторить)
    IDIGNORE Ignore (Пропустить)
    IDYES Yes (Да)
    IDNO No (Нет)
    IDOK OK
    IDCANCEL Cancel (Отмена)
    IDTRYAGAIN Try Again (Повторить попытку)
    IDCONTINUE Continue (Продолжить)

    Создание заготовки приложения

  • Создайте новый проект C++ на основе MFC и назовите его Dialogs

    Ни в коем случае не называйте проекты русскими именами, поскольку оболочка использует имя проекта при автоматической генерации имен файлов проекта и классов. Компилятор из текстов на русском принимает только комментарии и строковые константы.

  • Укажите мастеру, что проект будет диалоговым приложением
  • Остальные настройки мастера оставьте по умолчанию
  • Установите для ресурсов русский язык
  • Измените заголовок формы на "свою фамилию" + " Lab7 - Диалоги"
  • Создайте макет диалогового окна, показанный на рисунке. Для этого воспользуйтесь таблицей свойств элементов управления, приведенной ниже
  • Для выравнивания элементов диалога включите и пользуйтесь панелью инструментов "Dialog Editor" оболочки

    При выравнивании группы элементов отметьте, что первый из выделенных элементов группы является опорным: все остальные элементы подравниваются под него. Точное перемещение элементов выполняйте стрелками клавиатуры. Для быстрого просмотра результатов визуального проектирования пользуйтесь кнопкой Test Dialog панели инструментов Dialog Editor оболочки.

  • Определите порядок перехода по клавише табуляции между элементами управления
  • Обеспечьте выход по кнопке Таблица настройки мастера создания каркаса приложения Свойство проекта Значение Вкладка Application Type Application Type Dialog Based Resource language: Английский (США) Project style: MFC standard Use of MFC: Use MFC in a shared DLL Вкладка Advanced Features Все сбросить! Вкладка User Interface Features Main frame styles: System menu Dialog title: Dialogs
    Таблица свойств главной диалоговой формы Dialogs
    Элемент управления Свойство Значение
    Главная форма Caption Студент Иванов. Lab7 - Диалоги
    Font(Size) MS Sans Serif(10)
    Maximize Box True
    Minimize Box True
    Button ID IDC_B_YESNOCANCEL
    Caption Да, Нет, Отмена
    Button ID IDC_B_ABORTRETRYIGNORE
    Caption Прервать, Повторить, Пропустить
    Button ID IDC_B_FILEOPEN
    Button Caption Диалог File Open
    ID IDC_B_CUSTOMDIALOG
    Caption Сконструированный диалог
    Button ID IDC_B_WHICHOPTION
    Caption Какая опция?
    Disabled True
    Static Text Caption Результаты диалога:
    Right Align Text True
    Edit Control ID IDC_E_RESULT
    Multiline True
    Auto VScroll True
    Horizontal Scroll True
    Button ID IDC_B_EXIT
    Caption Выход
  • Нажмите на пиктограмму
  • Создание переменных элементов управления (Edit Control и Button "Какая опция?"), а также обработчиков первых двух кнопок

  • Создайте и свяжите с полем редактирования и кнопкой "Какая опция?" две переменные
    Переменные элементов управления
    ID (Объект связывания) Name (Имя) Type ( Тип) Category ( Категория) Accass ( Доступ) Назначение
    IDC_E_RESULT m_strResult Value CString public Для хранения значений поля редактирования
    IDC_B_WHICHOPTION m_cWhichOption Control CButton Public Для управления блокированием кнопки
  • Создайте обработчик для щелчка на первой кнопке "Да, Нет, Отмена"
    Обработчик для щелчка по первой кнопке "Да, Нет, Отмена"
    void CDialogsDlg::OnBnClickedBYesnocancel()
    {
    	int iResults; // Для возвращаемого значения MessageBox()
    	
    	// Спросить пользователя
    	iResults = MessageBox(
    		"Щелкните по кнопке\nДа, Нет, Отмена"// В области клиента (символ новой строки)
    	   ,"Диалог \"Да, Нет, Отмена\"" // Заголовок окна (экраны)
    	   ,MB_YESNOCANCEL | MB_ICONINFORMATION // Комбинации кнопок и пиктограмм
    	   ); 	
    	
    	// Определить, по какой кнопке щелкнул пользователь
    	switch(iResults){ // переключатель
    		case IDYES:
    			m_strResult = "Да! Да! Да!";
    			break;
    		case IDNO:
    			m_strResult = "Нет, нет, нет, нет, нет.";
    			break;
    		case IDCANCEL:
    			m_strResult = "Жаль, что \"Отмена\"";
    		// break здесь необязательно, все равно последний
    	}
    	
    	// Выдать на экран
    	UpdateData(FALSE);
    }
  • По аналогии создайте обработчик для щелчка по второй кнопке "Прервать, Повторить, Пропустить", используя идентификатор комбинации кнопок MB_ABORTRETRYIGNORE и идентификатор пиктограмм MB_ICONEXCLAMATION
  • Общие (стандартные) диалоги

    В библиотеки MFC предусмотрено несколько классов C++, предназначенных для поддержки общих (стандартных) диалогов

    Классы стандартных диалогов
    Класс Тип диалога
    CFileDialog Выбор файла для чтения или записи
    CFontDialog Выбор шрифта
    CColorDialog Выбор цвета
    CPageSetupDialog Установка параметров страницы для печати
    CPrintDialog Печать
    CFindReplaceDialog Поиск и замена

    Все эти диалоговые окна используются одинаково, хотя отдельные свойства и функции класса отличаются в зависимости от назначения диалога.

    Для использования конкретного диалога нужно выполнить следующее

  • Объявить переменную типа заданного класса (создать объект на стеке). Иногда лучше создать указатель на экземпляр класса, а затем запросить у операционной системы память на куче оператором new, своевременно освободив ее оператором delete после закрытия диалога и выборки из него необходимой информации
  • Перед отображением диалога установить все его необходимые свойства
  • Для отображения диалога вызвать метод DoModal() класса. Класс CFindReplaceDialog создает немодальное окно, поэтому для него вместо метода DoModal() нужно вызывать метод Create()
  • Получить возвращаемое методом DoModal() значение, чтобы определить на какой кнопке щелкнул пользователь - на OK или Cancel
  • Если пользователь щелкнул на кнопке OK, то прочитать все необходимые для дальнейшей работы приложения свойства, которые могли быть установлены пользователем в окне диалога. Для этого имеются методы доступа к свойствам класса, которые имеет смыcл применять для чтения только после того, как завершиться выбор пользователя нажатием кнопки OK
  • Любое диалоговое окно может отображаться в двух режимах:

  • Модальном ( modal ) - всякое иное взаимодействие пользователя с приложением приостанавливается до закрытия диалога. Модальные диалоговые окна применяются тогда, когда без завершения забора информации от пользователя продолжение работы приложения будет неопределенным. Пример - типовые окна сообщений
  • Немодальном ( modeless ) - пользователь может переключиться на основное окно приложения, не завершив диалог. Пример - окно "Find and Replace" (Найти и Заменить)
  • Класс CFileDialog

    Класс CFileDialog реализует содание двух типов диалогов, который зависит от того, с каким аргументом для конструктора класса создается экземпляр - окно диалога:

    "	CFileDialog openFile(TRUE);  // создается окно Open File 
    "	    
    "	CFileDialog saveFile(FALSE); // создается окно Save File

    Конструктору можно передать несколько аргументов, задав тем самым расширения отображаемых файлов (фильтры), маршрут, начальное имя файла и начальный путь по умолчанию. Все эти аргументы конструктора имеют значения по умолчанию, так что не обязательно указывать явно ни один из них.

    Основные методы доступа класса CFileDialog
    Функция Описание
    GetPathName() Возвращает полный путь выбранного файла
    GetFileName() Возвращает имя выбранного файла
    GetFileExt() Вовращает расширение выбранного файла
    GetFileTitle() Возвращает имя выбранного фвйла без расширения (например, если был выбран файл "MyFile.txt", то вернется "MyFile"

    Примечание. Все перечисленные в таблице методы не могут вызываться до тех пор, пока не будет вызван метод DoModal() и пока он не вернет значение IDOK. Иначе в свойствах может храниться кодовый мусор.

    Класс CFontDialog

    Класс CFontDialog инкапсулирует встроенный в Windows стандартный диалог выбора шрифта. В таблице приводятся основные методы-члены класса CFontDialog.

    Основные методы доступа класса CFontDialog
    Функция Описание
    GetFaceName() Возвращает имя выбранного шрифта.
    GetStyleName() Возвращает начертание выбранного шрифта (вид шрифта, тип шрифта). К одному типу шрифта может относиться несколько различных шрифтов.
    GetSize() Возвращает размер, указанный для выбранного шрифта.
    GetColor() Возвращает цвет, указанный для выбранного шрифта.
    GetWeight() Возвращает вес, указанный для выбранного шрифта.
    IsStrikeOut() Возвращает логическое значение, позволяющее определить, был ли выбран атрибут "зачеркнутый" ( strike out ) для выбранного шрифта.
    IsUnderline() Возвращает логическое значение, позволяющее определить, был ли выбран атрибут "подчеркнутый" ( underline ) для выбранного шрифта.
    IsBold() Возвращает логическое значение, позволяющее определить, был ли выбран атрибут "полужирный" ( bold ) для выбранного шрифта.
    IsItalic() Возвращает логическое значение, позволяющее определить, был ли выбран атрибут "курсив" ( italic ) для выбранного шрифта.

    Класс CColorDialog

    Класс CColorDialog инкапсулирует стандартный диалог выбора цвета, используемый во многих Windows -приложениях для получения значений координат модели цвета RGB (RedGreenBlue) , которые затем можно передать любому методу интерфейса графических устройств GDI (Graphic Device Interface) , требующему код цвета. В таблице приводятся основные методы-члены класса CColorDialog

    Основные методы доступа класса CColorDialog
    Функция Описание
    GetColor() Возвращает выбранный цвет.
    GetSavedCustomColor() Возвращает массив созданных пользователем цветов.
    SetCurrentColor() Устанавливает текущий цвет. Вызывать данный метод следует перед вызовом метода DoModal().

    Класс CPageSetupDialog

    Класс CPageSetupDialog инкапсулирует диалог Page Setup (параметры страницы), который используется для настройки вывода на печать.Этот диалог позволяет выбрать принтер, размер и поля печатаемой страницы. В таблице приводятся основные методы-члены класса CPageSetupDialog

    Основные методы доступа класса CPageSetupDialog
    Функция Описание
    CreatePrinterDC() Возвращает контекст устройства, используемого для печати
    GetDeviceName() Возвращает имя выбранного принтера
    GetDevMode() Возвращает структуру, содержащую информацию о выбранном принтере и его возможностях (цветной или черно-белый)
    GetMargins() Этому методу в качестве аргументов передаются два указателя - либо на класс CRect, либо на структуру RECT, - а он заносит в класс или структуру размеры полей и области печати
    GetPaperSize() Возвращает класс CSize, который определяет текущий размер бумаги
    GetDriveName() Возвращает имя драйвера выбранного принтера
    GetPortName() Возвращает имя выбранного порта вывода

    Класс CPrintDialog

    Класс CPrintDialog инкапсулирует стандартный диалог Print. Он содержит большинство методов класса CPageSetupDialog, за исключением методов GetMargins() и GetPaperSize(). Прочие важные функции класса CPrintDialog приведены в таблице

    Прочие важные методы доступа класса CPrintDialog
    Функция Описание
    GetCopies() Возвращает количество печатаемых копий
    GetFromPage() Возвращает номер начальной страницы (в случае, если был задан диапазон номеров печатаемых страниц)
    GetToPage() Возвращает номер конечной страницы (в случае, если был задан диапазон номеров печатаемых страниц)
    GetPrinterDC() Возвращает дескриптор контекста устройства для указанного принтера
    PrintAll() Возвращает логическое значение, позволяющее определить, нужно ли печатать все страницы текущего документа
    PrintCollate() Возвращает логическое значение, позволяющее определить, желает ли пользователь, чтобы страницы были разобраны по копиям
    PrintRange() Возвращает логическое значение, позволяющее определить, задан ли диапазон номеров печатаемых страниц
    PrintSelection() Возвращает логическое значение, позволяющее определить, нужно ли печатать только выбранные элементы или страницы целиком

    В отличие от методов класса CPageSetupDialog, метод CreatePrinterDC() можно вызывать без предварительного вызова метода DoModal(). Отображать этот диалог перед печатью необязательно, но класс CPrintDialog можно использовать для получения информации о принтере и контексте устройства.

    Класс CFindReplaceDialog

    Класс CFindReplaceDialog инкапсулирует стандартный диалог поиска и замены. В отличии от других стандартных диалогов, это окно немодальное, поэтому для отображения данного диалога нужно вызывать вместо метода DoModal() метод Create(). Метод Create() может принимать пять параметров, два первых из которых обязательны:

  • Первый параметр - это логическое значение, указывающее, предназначается ли диалог только для поиска ( TRUE ) или для поиска и замены ( FALSE )
  • Второй параметр - строка, которую нужно искать
  • Третий параметр - строка замены
  • Четвертый параметр - направление поиска. По умолчанию задано направление "вперед" (обозначается константой FR_DOWN ). Направление "назад" устанавливается значением 0
  • Пятый параметр - указатель на родительское окно приложения
  • Принципы работы с классом CFindReplaceDialog более сложные, чем с другими классами стандартных диалогов. Мы их здесь рассматривать не будем. В таблице приводятся основные методы-члены класса CFindReplaceDialog

    Основные методы доступа класса CFindReplaceDialog
    Функция Описание
    FindNext() Возвращает логическое значение, указывающее, нужно ли найти следующее вхождение искомой строки
    GetFindString() Возвращает введенную пользователем строку для поиска
    GetReplaceString() Возвращает введенную пользователем строку для замены
    IsTerminating() Возвращает логическое значение, позволяющее определить, решил ли пользователь закрыть этот диалог
    MatchCase() Возвращает логическое значение, которое указывает, нужно ли в поиске строки учитывать регистр
    MatchWholeWord() Возвращает логическое значение, которое указывает, нужно ли искать слово только целиком
    ReplaceAll() Возвращает логическое значение, которое указывает, нужно ли заменить все вхождения искомой строки
    ReplaceCurrent() Возвращает логическое значение, которое указывает, нужно ли заменить текущее найденное вхождение искомой строки
    SearchDown() Возвращает логическое значение, которое указывает, нужно ли выполнить поиск вперед от текущей позиции

    Подключение стандартного диалога File Open к приложению

  • Создайте обработчик для кнопки "Диалог File Open"
  • Заполните его кодом
    Обработчик для щелчка по кнопке "Диалог File Open"
    void CDialogsDlg::OnBnClickedBFileopen()
    {
    	CFileDialog openFile(TRUE); // Создать диалог
    	if(openFile.DoModal() == IDOK){ // Отобразить и получить результат
    		m_strResult = openFile.GetFileName(); // Сохранить имя файла
    		UpdateData(FALSE); // Передать на экран
    	}
    }
  • Добавление собственного диалогового окна

    Добавим собственное диалоговое окно, которое будет предлагать пользователю поле редактирования, группу радиокнопок. Когда пользователь щелкнет на кнопке OK, введенный им текст отобразится в главном окне приложения. Для этого нужно будет выполнить следующие действия:

  • Добавить новое диалоговое окно к ресурсам приложения
  • Создать дизайн диалогового окна, разместив в нем необходимые элементы
  • Содать для управления ресурсом класс на базе класса CDialog
  • Связать переменные с элементами управления диалога
  • Создание макета диалогового окна

  • Выберите вкладку
  • Выделите в нем пиктограмму
  • В панели Resource View выделите сгенерированный ресурс с дежурным именем IDD_DIALOG1 и через панель свойств присвойте ресурсу осмысленный идентификатор IDD_MESSAGEDLG. Не удаляйте кнопки OK и Cancel
  • Отредактируйте ресурс диалогового окна в соответствии с таблицей свойств
    Таблица свойств диалогового ресурса IDD_MESSAGEDLG
    Элемент управления Свойство Значение
    Форма Caption Диалог с сообщениями и опциями
    Font(Size) MS Sans Serif(10)
    Maximize Box False
    Minimize Box False
    Static Text Caption Введите сообщение:
    Right Align Text True
    Edit Control ID IDC_EMESSAGE
    Multiline True
    Auto VScroll True
    Horizontal Scroll True
    Group Box Caption Выбор опции
    Radio Button ID IDC_ROPTION1
    Caption Опция 1
    Group True
    Radio Button ID IDC_ROPTION2
    Caption Опция 2
    Group False
    Radio Button ID IDC_ROPTION3
    Caption Опция 3
    Group False
    Radio Button ID IDC_ROPTION4
    Caption Опция 4
    Group False
  • При редактировании диалогового ресурса периодически проверяйте дизайн кнопкой Test Dialog панели инструментов Dialog Editor. Размеры элементов управления контролируйте через панель состояния дизайнера. Для выравнивания элементов пользуйтесь инструментами на панели инструментов или опциями меню Format оболочки.

    Окончательный вариант макета приведен на рисунке

    Отметьте, что для согласованной работы радиокнопок мы для первого переключателя установили свойство Group в состояние True. В остальных же переключателях оставили его значение по умолчанию False. Это приведет к тому, что следующие по порядку их создания радиокнопки будут объединены в группу. Новая группа начнется с нового следующего по порядку создания радиопереключателя со свойством True (но у нас только одна группа). Порядок следования радиопереключателей можно посмотреть через опцию Edit/Resource Symbols (или через контекстное меню в панели Resource View, щелкнув на узле Dialogs.rc ) в окне Resource Symbols

    Отредактировать порядок радиопереключателей можно в файле Resource.h, открыв его на редактирование через панель Solution Explorer (не рекомендуется!!!)

    В этом файле оболочка формирует именованные константы

    Именованные константы в файле Resource.h
    //{{NO_DEPENDENCIES}}
    // Microsoft Visual C++ generated include file.
    // Used by Dialogs.rc
    //
    #define IDD_DIALOGS_DIALOG              102
    #define IDR_MAINFRAME                   128
    #define IDD_MESSAGEDLG                  131
    #define IDC_B_YESNOCANCEL               1000
    #define IDC_B_ABORTRETRYIGNORE          1001
    #define IDC_B_CUSTOMDIALOG              1002
    #define IDC_B_WHICHOPTION               1003
    #define IDC_E_RESULT                    1004
    #define IDC_EMESSAGE                    1005
    #define IDC_B_FILEOPEN                  1006
    #define IDC_ROPTION1                    1006
    #define IDC_B_EXIT                      1007
    #define IDC_ROPTION2                    1007
    #define IDC_ROPTION3                    1008
    #define IDC_RADIO4                      1009
    #define IDC_ROPTION4                    1009
    ............................................

    Создание управляющего класса

    Для управления диалоговым ресурсом создайте класс на основе базового класса CDialog. Для этого:

  • Выберите только что сконструированное окно приложения в режиме дизайна и через контекстное меню (или главное меню Project ) выполните опцию Add Class

    Запустится мастер добавления класса, который нужно настроить в соответствии с рисунком

  • Убедитесь, что в поле Base class выбран CDialog

    После создания класса его код должен быть размещен в двух новых файлах MsgDlg.h и MsgDlg.cpp. Убедитесь в этом через панель Solution Explorer. Удобнее при создании новых классов размещать их в отдельных файлах. Мастер Add Class создал производный класс-потомок на основании базового класса CDialog, поддерживающего диалоговые окна

    Объявление производного класса CMsgDlg, наследника CDialog (код файла MsgDlg.h)
    #pragma once
    
    	
    // CMsgDlg dialog
    	
    class CMsgDlg : public CDialog
    {
    	DECLARE_DYNAMIC(CMsgDlg)
    	
    public:
    	CMsgDlg(CWnd* pParent = NULL);   // standard constructor
    	virtual ~CMsgDlg();
    	
    // Dialog Data
    	enum { IDD = IDD_MESSAGEDLG };
    	
    protected:
    	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    	
    	DECLARE_MESSAGE_MAP()
    };
  • Добавьте две ассоциированные переменные к элементам управления. Для этого выделите в панели Переменные элементов управления диалога CMsgDlg ID (Объект связывания) Name (Имя) Type ( Тип) Category ( Категория) Accass ( Доступ) Назначение IDC_EMESSAGE m_strMessage Value CString public Для хранения значений поля редактирования IDC_ROPTION1 m_iOption Value int public Для распознавания выбранной радиокнопки
  • Мастер добавит в приложение код

    Файл MsgDlg.h
    class CMsgDlg : public CDialog
    {
    ................................................
    public:
    	// Для хранения значений поля редактирования
    	CString m_strMessage;
    	// Для распознавания выбранной радиокнопки 
    	int m_iOption;
    };
    Файл MsgDlg.cpp
    CMsgDlg::CMsgDlg(CWnd* pParent /*=NULL*/)
    	: CDialog(CMsgDlg::IDD, pParent)
    	, m_strMessage(_T(""))
    	, m_iOption(0)
    {
    }
    	
    void CMsgDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EMESSAGE, m_strMessage);
    	DDX_Radio(pDX, IDC_ROPTION1, m_iOption);
    }

    Для переключателя с установленным свойством Group мы назначили ассоциированную целочисленную переменную m_iOption. Значение этой переменной зависит от того, какой из переключателей группы будет выбран пользователем. При выборе первого переключателя "Опция 1" эта переменная принимает значение 0, при выборе второго - значение 1, и т.д. , поскольку в C++ нумерация элементов массива или группы начинается с нуля.

    Подключение собственного диалога к приложению

    Мы сконструировали собственный диалог, который теперь можно использовать точно также, как и стандартный диалог, а именно:

  • Объявить экземпляр класса CMsgDlg
  • Вызвать метод DoModal() экземпляра и сохранить возвращаемое им значение
  • Прочитать значения введенных ранее переменных m_strMessage и m_iOption
  • Огорчиться на себя за то, что мы нарушили главный принцип ООП (объектно-ориентированное программирование) - инкапсуляцию данных, и быстренько исправить этот огрех, переобъявив переменные как private и добавив функции доступа к этим переменным
  • Решим эту задачу в соответствии со следующими пошаговыми инструкциями

    Подключение диалога с прямым доступом к данным-членам класса CMsgDlg из класса-клиента CDialogsMsg

  • Добавьте в объявление класса-клиента переменную-экземпляр созданного нами класса CMsgDlg в соответствии с настройкой мастера, приведенной ниже. Для этого выделите в панели Class View класс CDialogsDlg и через контекстное меню откройте мастер

    Мастер добавит код

    Объявление в классе CDialogsDlg переменной-экземпляра класса CMsgDlg
    class CDialogsDlg : public CDialog
    {
    ..............................................
    private:
    	// Экземпляр класса нашего диалогового окна
    	CMsgDlg m_dMsgDlg;
    };
  • Добавьте в класс-клиент CDialogsMsg директиву препроцессора (предварительного компилятора) для подключения к нему объявления класса-сервиса CMsgDlg. Для этого через панель Solution Explorer откройте на редактирование файл DialogsMsg.h и в самом начале файла, перед объявлением класса CDialogsDlg, подключите заголовочный файл с описанием класса CMsgDlg, как показано ниже

    Подключение файла с объявлением класса-сервиса CMsgDlg 
    перед объявлением класса-клиента CDialogsDlg в файле DialogsDlg.h
    // DialogsDlg.h : header file
    //
    	
    #pragma once // Страж включения
    #include "afxwin.h"
    	
    #include "MsgDlg.h"
    // CDialogsDlg dialog
    class CDialogsDlg : public CDialog
    {
    .....................................
    };

    Обратите внимание, что в каждом заголовочном файле, созданном оболочкой, она в самом начале файла размещает директиву препроцессора "#pragma once", которую называют стражем включения. Это связано с тем, что включение файла может быть размещено во многих местах приложения, а препроцессор должен включить в приложение только первый встретившийся экземпляр кода. Эта директива и поднимает флаг у препроцессора, заставляя его игнорировать повторные включения одного и того же кода. В реализациях других производителей компиляторов можно встретить иной прием

    #ifndef ИМЯ_ВКЛЮЧАЕМОГО_ФАЙЛА
      #define ИМЯ_ВКЛЮЧАЕМОГО_ФАЙЛА
      
      	код включаемого файла
      
      #endif
  • Добавьте обработчик к кнопке "Сконструированный диалог", запускающий на выполнение окно нашего диалога

    Обработчик кнопки "Сконструированный диалог" запуска диалога
    // Обработчик кнопки "Сконструированный диалог"
    void CDialogsDlg::OnBnClickedBCustomdialog()
    {
    	// Запросить информацию через диалог
    	if(m_dMsgDlg.DoModal() == IDOK){
    		m_strResult = m_dMsgDlg.m_strMessage;// Напрямую, т.к. public
    		// разблокировать кнопку "Какая опция?"
    		m_cWhichOption.EnableWindow(TRUE);
    	}
    	else
    		m_strResult = "Ввод информации отменен!";
    	
    	// Передать на экран новое значение поля редактирования
    	UpdateData(FALSE);
    }
  • Добавьте обработчик к кнопке "Какая опция?"
    Обработчик кнопки "Какая опция?"
    // Обработчик кнопки "Какая опция?"
    void CDialogsDlg::OnBnClickedBWhichoption()
    {
    	// Какая радиокнопка включена
    	switch(m_dMsgDlg.m_iOption){
    		case 0:
    			m_strResult = "Была выбрана первая опция";
    			break;
    		case 1:
    			m_strResult = "Была выбрана вторая опция";
    			break;
    		case 2:
    			m_strResult = "Была выбрана третья опция";
    			break;
    		case 3:
    			m_strResult = "Была выбрана четвертая опция";
    			break;
    		default:
    			m_strResult = "Опция не выбрана!";
    	}
    	
    	// Передать на экран новое значение поля редактирования
    	UpdateData(FALSE);
    }
  • Запустите приложение и убедитесь в его работоспособности
  • Подключение диалога с доступом к данным-членам класса CMsgDlg из класса-клиента CDialogsMsg через функции доступа

  • Измените в объявлении класса CMsgDlg данные-члены m_strMessage и m_iOption как private
  • Добавьте к классу CMsgDlg методы доступа public, возвращающие значения этих переменных:
  • CString GetMessage() {return m_strMessage;}
  • int GetOption() {return m_iOption;}
  • Замените в последних двух обработчиках класса CDialogsMsg прямые вызовы переменных m_strMessage и m_iOption через вызовы функций доступа
  • Изменение конфигурации проекта для его автономной работы

  • Постройте окончательный вариант приложения в режиме Release и убедитесь, что размер исполнимого файла составляет примерно 15K
  • Это малый размер для такой задачи и объясняется это тем, что при создании приложения мы настроили мастер на использование библиотек DLL

    Таблица настройки мастера создания каркаса приложения
    Use of MFC: Use MFC in a shared DLL

    Такое приложение не будет работать на компьютере, где нет этих библиотек. Поэтому следует построить автономное приложение, включающее в себя весь необходимый код. Для этого:

  • Выполните опцию Project/Dialogs Properties для нашего проекта Dialogs

    Появится окно, в котором установите режим

    Изменение режима в таблице свойcтв приложения
    Use of MFC: Use MFC in a Static Library
  • Перестройте приложение и определите размер исполнимого файла
  • Исполнимый файл приложения увеличился примерно до 155K. Такой файл будет работать на любом компьютере с операционной системой Windows.

    Вернуться к учебному плану