- •Овсянник в.Н. Лабораторные работы по курсу «Объектно-ориентированное программирование»
- •1.Интегрированная среда mvs-2010
- •1.1.Методические указания
- •2.Массивушки и подпрограммочки
- •Прочитайте это задание и методические указания до конца, прежде чем терзать клавиатуру, соседа, преподавателя и пр. Сущности
- •Попробуйте сдать работу, предварительно тщательно протестировав ее на предмет отсутствия хомутов
- •2.1.Методические указания
- •3.Поиск экстремумов с ограничениями или «Брачное агенство»
- •Постановка задачи
- •Задание
- •Листинг файла mAgency.Cpp (с главной функцией)
- •Листинг файла Lib.H
- •Листинг файла Lib.Cpp
- •4.Задача «куча камней»
- •4.1.Постановка задачи.
- •4.2.Методические указания.
- •Некоторые примеры разделения камней на две кучи, которые должна решать ваша программа
- •5.Разработка простого класса
- •5.1.Задание
- •5.2.Описание вариантов заданий
- •5.3.Драгоценные методические указания
- •6.Класс вектор
- •6.1.Пример класса tVector
- •6.2.Класс tVector с перегруженными операциями
- •7.Наследование классов
- •7.1.Задание
- •7.2.Методическая помощь
- •7.3.Описание самых легких вариантов заданий
- •7.4.Контроль качества выполненной работы
- •8.Приложение с окном вида
- •9.Абстрактные классы и виртуальные функции
- •9.1.Задание
- •9.2.Методические указания
- •Void PrintClassNamе1(cBasе *pb) // параметр-указатель
- •Void PrintClassNamе2(cBasе &b) // параметр-ссылка
- •Void PrintClassNamе3(cFirst f) // параметр-значение
- •9.3.Варианты заданий
- •10.Разработка класса контейнера
- •10.1.Задание
- •10.2.Описание вариантов заданий
- •10.3.Методические указания
- •12.Перегрузка векторных и матричных операций
- •12.1.Задание
- •12.2.Бесценные методические указания
- •12.3.Некоторые особенности перегрузки операций
- •12.4.Варианты заданий
- •13.Программирование односвязного списка
- •13.1.Задание
- •13.2.Описание вариантов заданий
- •14.Приложение, основанное на модальном диалоговом окне
- •14.1.Нудные методические указания Модальные и немодальные диалоговые окна
- •Ресурсы и элементы управления
- •Сценарий создания приложения
- •Разбор приложения
- •Усовершенствование приложения
- •15.Приложения
- •15.1.Виды сортировок
- •Классификация сортировок
- •Сортировка массивов
- •15.2.Алгоритм сортировки включением
- •Пример сортировки с помощью прямого включения
- •15.3.Сортировка Шелла
- •Список литературы
Разбор приложения
После вызова функции Cdialog::DoModal() управление возвратится вашей программе, только когда пользователь закроет диалоговое окно. Если Вам это ясно, то Вы гений, который постиг тайну модального диалогового окна. Перейдя к работе с немодальными диалоговыми окнами, Вы еще оцените, как просто было программировать модальные диалоговые окна, потому что при вызове DoModal() очень многое остается за кадром. Но вернемся к нашей теме и рассмотрим, «кто кого вызывает»:
CDialog::DoModal() CDiaWinDlg::OnInitDialog() …дополнительная инициализация…
CDialog::OnInitDialog() CWnd::UpdateData(FALSE) CDiaWinDlg::DoDataExchange() пользователь вводит данные…
пользователь нажимает кнопку OK
CDiaWinDlg::OnOK() … дополнительная проверка …
CDialog::OnOK CWnd::UpdateData(TRUE) CDiaWinDlg::DoDataExchange() CDialog::EndDialog(IDOK)
OnInitDialog() и DoDataExchange() — виртуальные функции, переопределенные в классе CDiaWinDlg. Windows вызывает OnlnitDialog() при инициализации диалогового окна, что приводит к вызову виртуальной функции DoDataExchange(), которую сгенерировал для Вас мастер. Взгляните на листинг этой функции, размещенной в Вашем файле DiaWinDlg.cpp. Функция DoDataExchange() и функции DDX_(обмен) и DDV_(проверка достоверности) — «двусторонние». Если функция UpdateData() вызывается с параметром FALSE, то она переносит данные из связанных переменных в элементы управления диалогового окна. Если же она вызывается с параметром TRUE, то передает данные в противоположном направлении: из элементов управления в связанные переменные. DDX_Text переопределяется для подстройки под множество типов данных.
Функция EndDialog() играет главную роль в процедуре завершения диалогового окна. DoModal() возвращает параметр, передаваемый ей функцией EndDialog(). Значение параметра IDOK означает, что пользователь завершил диалог нажатием кнопки ОК или клавиши Enter, a IDCANCEL – что пользователь завершил диалог нажатием кнопки Cancel. Вы можете самостоятельно вызвать EndDialog() при наступлении какого-либо события – пример см. в MSDN.
Совет. Вы можете написать собственные DDX-функции и подключить их к Visual C++. Это бывает весьма полезно, если во всей своей программе Вы пользуетесь уникальным типом данных. Подробнее см. MFC Technical Note #26 в интерактивной справочной системе MSDN (для версии MVS 6.0).
Усовершенствование приложения
Один из законов Мэрфи гласит: «Совершенство достигается к моменту краха». Будем оптимистами и все же попытаемся усовершенствовать нашу программу. Избавим наше приложение от скверной привычки завершать свою работу при, даже случайном, нажатии клавиши Enter (ну, например, вследствие падения головы или какой-либо более важной части тела на клавиатуру).
Шаг 11. Обработка нажатия кнопки ОК.
В нашем приложении виртуальная функция CDialog::OnOK() обрабатывает щелчок кнопки ОК, что запускает процесс обмена данными и процедуру выхода из диалогового окна. Тот же результат дает и клавиша Enter — может быть, это как раз то, чего Вы хотели, а может быть – и нет. Если пользователь нажмет клавишу Enter, скажем, в поле ввода «Фамилия», его немедленно «выбросит» из диалогового окна. Вряд ли это пользователю понравится, если он не мазохист …
Что же происходит? В момент нажатия этой клавиши Windows ищет кнопку, на которой установлен фокус ввода (input focus) — на экране он выглядит как дополнительная пунктирная рамка внутри рамки кнопки при ее нажатии.
Замечание. Советую запустить программу, вызвать окно диалога и внимательно к нему присмотреться: нетрудно заметить, что кнопка ОК имеет более толстые границы, чем другие. Теперь добавьте в окно «ничего не делающую» дополнительную кнопку Button1, попробуйте нажимать клавишу табуляции, выделите кнопку Button1 и нажимайте клавишу Enter – ничего не произойдет. Обратите внимание также на то, что в классе CDiaWinDlg сейчас нет обработчика нажатия кнопки OK, как, впрочем, и кнопки Cancel. Вместе с тем в классе CDialog имеется виртуальная функция OnOK(), как и функция OnCancel().
Если фокус не установлен ни на одну кнопку, Windows ищет указанную программой или в ресурсе кнопку по умолчанию (default pushbutton): у такой кнопки более толстые границы. Если такой кнопки нет, вызывается виртуальная функция ОnОК — даже если кнопка ОК отсутствует.
Клавишу Enter можно «отключить», просто написав ничего не делающую функцию CDiaWinDlg::OnOK() и добавив код завершения в новую функцию, реагирующую на щелчок кнопки ОК. Последовательность действий такова.
1. На вкладке Resource View отыщем идентификатор IDD_DIAWIN_DIALOG нашего окна и щелкнем по нему ЛКМ, вызвав тем самым появление нашего окна в окне графического редактора. Выберем кнопку ОК, щелкнем по ней ПКМ и в появившемся контекстном меню выберем команду Add Event Handler (добавить обработчик события). Появится окно (рис. 9), в поле которого Function Handler Name необходимо предлагаемое по умолчанию имя OnBnClickedOk заменить на OnOK (обратите внимание на регистр символов!) и нажать кнопку Add and Delete. Мастер сгенерирует функцию
void CDiaWinDlg::OnOK()
{
// TODO: Add your control notification handler code here
OnOK();
}
Как видите, мастер не такой уж и мастер: функция вызывает саму себя, что при запуске приложения на выполнение и нажатии клавиши Enter приведет к переполнению стека. Надо в нашем обработчике вызывать (виртуальную) функцию CDialog::OnOK() родительского класса – тогда все будет ОК, т.е. по-прежнему. Однако мы должны на этом этапе сделать нашу функцию просто пустышкой с одним только макросом TRACE:
void CDiaWinDlg::OnOK()
{
TRACE(“Вход в CDiaWinDlg::OnOK()\n”);
}
Если теперь мы запустим приложение на выполнение, то нажатие кнопки ОК или клавиши Enter не будет приводить к закрытию окна, т.е. завершению программы, так как мы устранили вызов функции CDialog::OnOK(). В окне Debug мы должны видеть сообщение о вызове функции CDiaWinDlg::OnOK(). Однако нашей задачей является все же обеспечение такой логики работы приложения, при которой нажатие кнопки ОК будет приводить к завершению работы программы.
2. Вызовите окно свойств для кнопки ОК и замените идентификатор кнопки IDOK на IDC_OK и отмените у нее свойство Default Button, присвоив ему значение False (рис. 10). Теперь нажмите кнопку Control Events в окне Properties и сгенерируйте для нее обработчик события BN_CLICKED. Мастер сгенерирует функцию CDiaWinDlg::OnBnClickedOk(), в которую достаточно добавить одну-единственную строку и вызов макроса TRACE для наглядности:
void CDiaWinDlg::OnBnClickedOk()
{
TRACE("Вход в CDiaWinDlg::OnBnClickedOk()\n");
CDialog::OnOK();
}
Обратите внимание на вызов функции CDialog::OnOK(): эта функция делает полезную работу.
|
Рис. 9. Добавление обработчика события нажатия кнопки ОК
3. Соберите и протестируйте приложение. Попробуйте теперь нажать клавишу Enter. Ничего произойти не должно, но в окне Debug появится вывод макроса TRACE «Вход в CDiaWinDlg::OnOK()». Вместе с тем по щелчку кнопки ОК диалоговое окно должно закрыться.
|
Рис. 10. Изменение свойств кнопки ОК
Шаг 12. Обработка нажатия кнопки Cancel.
Так же как нажатие клавиши Enter приводило к вызову ОnОК(), так и нажатие клавиши Esc инициирует вызов OnCancel(), в результате чего диалоговое окно завершается с кодом возврата IDCANCEL от функции DoModal(). Наша программа не предусматривает особой обработки IDCANCEL, поэтому нажатие клавиши Esc (или щелчок кнопки Close) закрывает диалоговое окно. Вы можете обойти этот процесс, применив функцию-заглушку OnCancel() по аналогии с тем, как это уже делалось для кнопки ОК.
Замечание. Попробуйте изменить какие-нибудь значения в управляющих элементах окна и закрыть его – диалоговое окно – с помощью кнопки ОК и с помощью кнопки Cancel. Понаблюдайте при этом за значениями элементов управления (точнее, связанных с ними переменных-членов) в окне Debug. Есть разница?
Шаг 13. Выбор фона диалогового окна и цвета элементов управления.
Чтобы изменить фон отдельных диалоговых окон или конкретных элементов управления в каком-либо диалоговом окне, придется (в отличие от работы в Delphi) потрудиться. Каждый элемент управления, прежде чем появиться на экране, посылает родительскому диалоговому окну сообщение WM_CTLCOLOR. Такое же сообщение отправляется и самому диалоговому окну. Если написать в производном классе диалогового окна обработчик этого сообщения, можно установить цвет текста и его фон, а также выбрать кисть для заполнения нетекстовой области элемента управления или диалогового окна.
Ниже приведен пример функции OnCtlColor(), задающей желтый фон для всех полей ввода и синий фон с красной штриховкой для диалогового окна. Для цвета фона текста полей ввода, исключительно в качестве иллюстрации, задан зеленый цвет. В результате цветовая гамма диалогового окна получается ужасной, но зато наглядной.
В функции CDiaWinDlg::OnCtlColor() параметр nCtlColor определяет тип элемента управления, а pWnd — конкретный элемент управления. Чтобы установить цвет отдельного элемента управления, нужно преобразовать pWnd в идентификатор дочернего окна и проверить его значение, как это сделано в приведенной ниже функции.
|
Заготовку функции CDiaWinDlg::OnCtlColor() можно создать с помощью все того же окна свойств Properties для нашего диалогового окна, выбрав на вкладке Messages сообщение WM_CTLCOLOR и сгенерировав обработчик этого сообщения. Текст обработчика приведите в соответствие с приведенным выше.
Переменные m_hYellowBrush и m_hRedBrush – это переменные-члены типа HBRUSH (brush – кисть), которые предлагается описать в классе CDiaWinDlg, в секции protected. Эти переменные можно инициализировать в CDiaWinDlg::OnInitDialog(), например, так:
|
Попробуйте собрать приложение и тестировать его. Если Вам не понравится цветовая гамма – измените!
Замечание. Диалоговое окно не помещает сообщение WM_CTLCOLOR в очередь сообщений (message queue); вместо этого окно, чтобы немедленно отправить сообщение, вызывает Win32-функцию SendMessage(). Благодаря этому обработчик сообщения может вернуть параметр, в данном случае описатель кисти. Это не MFC-объект типа CBrush, a Win32 HBRUSH. Создать кисть можно, вызвав Win32-функции CreateSolidBrush(), CreateHatchBrush(), CreatePatternBrush() и др.
В функции CDiaWinDlg::OnCtlColor() можно получить информацию о конкретном элементе управления несколькими способами, например, путем анализа значения указателя на элемент управления:
if(*pWnd==objBio)
{
pDC->SetBkColor(RGB(255, 0, 0)); // цвет фона текста биографии
pDC->SetTextColor(RGB(255,192,128)); // цвет фона текста биографии
TRACE("IDC_BIO\n");
return m_hYellowBrush; // кисть элемента управления
// или return CreateSolidBrush(RGB(150,150,255));
}
Шаг 14. Сохранение результатов диалога в текстовом файле. Доработайте программу таким образом, чтобы введенные пользователем данные сохранялись в текстовом файле по нажатию кнопки «Сохранить», которую Вы добавите в диалоговое окно. Для этой благородной цели вы можете воспользоваться подсказками, приведенными в подразделе «Запись текстовых файлов с использованием класса CFile» файла VC_Lect.doc. В этом же файле вы найдете подсказки, как добавить в свою программу диалог по выбору имени файла (класс CFileDialog).
Коварно-контрольные вопросы:
Как вызвать системное меню диалогового окна, какие команды в нем есть?
Вызовите окно «О программе» диалогового окна, а также покажите в программе код, который вызывает это окно.
Какие Вы знаете способы задания заголовка окна (в сценарии – «Кадры решают все!»)?
Какие комбинированные списки (ComboBox) позволяют только выбирать одно из имеющихся значений, а какие позволяют также и вводить собственные значения? Какое свойство комбинированного списка ответственно за такое поведение элемента управления?
Зачем нужна функция ToAnsi и что это за функция: библиотечная или собственная?
Чем полезен макрос TRACE, чем он отличается от просмотра значений переменных с помощью средств отладчика?
Вызов какой функции приводит к появлению диалогового окна на экране?
Для чего предназначен макрос RGB, чем его можно было бы заменить?
Для чего предназначена функция Format класса CString?
