Особенность работы с немодальным диалогом заключается в том, что надо затратить дополнительные усилия для корректного завершения его работы. Чтобы закрыть немодальный диалог, документация требует переопределить две виртуальные функции в классе диалога: обработчик закрытия диалога OnCancel и функцию PostNcDestroy. Существуют подробные рекомендации для завершения немодального диалога. Внутри вашей версии виртуальной функции OnCancel следует уничтожить окно диалога (DestroyWindow), а внутри другой виртуальной функции PostNcDestroy рекомендуется уничтожать объект диалогового класса (delete this;). С немодальным диалогом принято работать динамически (on heap frame), а не статически (on stack frame), как с модальным. Когда уничтожается окно Windows, то последним сообщением, которое ему посылается, является WM_NCDESTROY. Обработчик по умолчанию, то есть родительская версия cwnd: :OnNcDestroy, открепляет (detach) описатель окна HWND от объекта класса C++ и вызывает виртуальную функцию PostNcDestroy.
Некоторые классы переопределяют ее для того, чтобы произвести освобождение своих объектов в области heap (динамическая память). При неудаче в процессе создания окна происходит вызов функции cwnd::PostNcDestroy, которая ничего не делает, но дает возможность виртуальным двойникам корректно освободить динамическую память. Мы тоже будем работать с диалогом динамически (on heap frame). В классе документа будет храниться адрес объекта с Pol у Dig, который должен корректно следить за стадиями создания и уничтожения диалога. Я намеренно не переопределял PostNCDestroy, чтобы показать альтернативный способ, допустимый в частных случаях. Так как наш диалог завершается командой Close с идентификатором IDOK, то, введя обработчик этой команды, мы можем с помощью родительской версии уничтожить Windows-окно, а затем освободить память, занимаемую объектом собственного класса:
void CPolyDlg::OnClickedOk(void)
{
//=== Запоминаем факт отсутствия диалога в документе
m_pDoc->m_pPolyDlg = 0;
//====== Родительская версия вызовет DestroyWindow
CDialog::OnOK();
//====== Мы освобождаем память
delete this;
}
Вызов диалога производится в ответ на команду Edit > Poly Color, которая уже присутствует в меню IDR_DrawTYPE. Введите в класс CTreeDoc обработчик этой команды и наполните его кодами, как показано ниже:
void CTreeDoc::OnEditPolycolor(void)
{
//====== Если диалог отсутствует
if (!m_pPolyDlg)
{
//====== Создаем его в две ступени
m_pPolyDlg = new CPolyDlg(this);
m_pPolyDlg->Create(IDD_POLYCOLOR) ;
}
else
//===== Иначе делаем активным его окно
m_pPolyDlg->SetActiveWindow();
}
Здесь использован указатель на объект диалогового класса, который необходимо ввести в число public-данных класса CTreeDoc (CPolyDlg *m_pPolyDlg;) и обнулить в конструкторе документа (m_pPolyDlg = 0;). Сделайте это, а также введите в файл реализации класса CTreeDoc вспомогательную функцию UpdateDrawView:
void CTreeDoc::UpdateDrawView()
{
//====== Добываем адрес нужного представления
CDrawView *pView = dynamic_cast<CDrawView*>
(GetView(SCDrawView::classCDrawView));
//====== и просим его перерисоваться с учетом изменений
if (pView)
pView->Invalidate();
}