Створення і відображення немодальних діалогових вікон

Як тільки екземпляр класу немодального діалогового вікна буде створений, він викликає функцію Create, що створює і відображає діалогове вікно. Як можна відмітити нижче, функція Create має дві переобтяжені версії.

 

BOOL Create(LPCTSTR IpszTemplateName, CWnd* pParentWnd = NULL);

BOOL Create(UINT nIDTemplate

CWnd* pParentWnd = NULL);

 

Дві переобтяжені версії функції Create відповідають двом переобтяженим версіям конструктора CDialog, що створює екземпляр модального діалогового вікна. Причина цілком логічна. Коли додаток створює і відображає модальне діалогове вікно, робота зухвалої функції блокується (blocked) аж до завершення роботи функції DoModal. Отже, створення і відображення діалогового вікна фактично здійснюється усередині тієї ж самої функції. Але відображення немодального діалогового вікна відбувається асихронно (asynchronous), тобто коли зухвала функція викличе функцію Create і немодальне діалогове вікно відобразиться на екрані, функція Create відразу завершить свою роботу. Отже, зухвала функція також, найвірогідніше, встигне завершити свою роботу, тоді як діалогове вікно все ще буде видиме. Проблема полягає в наступному: якби об'єкт класу CDialog був створений в стеку, то при виході з області видимості (out of scope) він був би видалений. В результаті, через декілька мілісекунд після відображення діалогове вікно зникне, оскільки деструкція знищить його. Тому цілком звичайною практикою в додатках стало створення об'єкту класу, похідного від CDialog, в одній функції, збереження покажчика на цей об'єкт діалогового вікна і виклик його функції Create в іншій функції. Як це зробити на практиці, будете продемонстровано на прикладі додатку в справжньому розділі.

Зазвичай виклик функції Create приводить до негайного відображення немодального діалогового вікна, але це відбувається не завжди. Якщо в шаблоні діалогового вікна властивості visible (стиль WS__VISIBLE) немодального діалогового вікна привласнено значення False, то, фактично, вікно буде створено, але видимим на екрані воно не стане. Отже, щоб уникнути подібної ситуації і гарантовано відобразити немодальне діалогове вікно (навіть якщо його властивість visible встановлена в стан False), функцію ShowWindow слід викликати із значенням SW_NORMAL.

 

dig.Create(IDD_MY_MODELESS_DIALOG);

dig.ShowWindow(SW_NORMAL);

 

Як відомо, для модального діалогового вікна визначати ресурс шаблону діалогового вікна зазвичай не потрібний. Це пов'язано з тим, що при використанні майстра ClassWizard для створення на підставі шаблону класу, похідного від CDialog, їм буде автоматично створений код, передавальний при зверненні до конструктора CDialog ідентифікатор шаблону Діалогового вікна. Тут відразу дві переваги. По-перше, це ще одне завдання, про виконання якої можна не хвилюватися, створюючи код додатку, і по-друге, це позбавляє розробника від вірогідних помилок в коді створення екземпляра діалогового вікна. По тих Же самих причинах достатні багато розробників, використовуючи немодальні діалогові вікна визначають успадковану функцію Create як захищену (protected) або закриту (private) і створюють свою власну, переобтяжену версію цієї функції, що не приймає параметрів. Переобтяжена версія викликає успадковану, передаючи їй коректний ідентифікатор. Цей підхід використаний і в демонстраційному застосуванні.

І ще одна особливість немодальних діалогових вікон, про яку має сенс згадати. Повернувшись до батьківського вікна, користувач цілком може зробити спробу викликати немодальне діалогове вікно ще раз. Існують два способи вирішення цієї проблеми. Перший з них має на увазі відключення елементу призначеного для користувача інтерфейсу (VI) що дозволяє викликати немодальне діалогове вікно (якщо воно вже відображене на екрані) Наприклад, якщо в меню View (Вигляд) присутній пункт Find (Знайти), що дозволяє відобразити діалогове вікно пошуку, то фрагмент коди обробника даної команди призначеного для користувача інтерфейсу (COMMANDUI), що відключає цей пункт меню до тих пір, поки не буде закрито діалогове вікно пошуку, може виглядати таким чином:

 

void CMyView::OnUpdateEditFind(CCmdUI *pCmdUI)

{

pCmdUI->Enable(!m_pDlg->GetSafeHwnd();

}

 

У цій функції використовується клас уявлення (батьківського вікна немодального діалогового вікна), в якому визначена змінна-член, що містить покажчик на немодальне діалогове вікно (m_pDlg). Як вже було сказано, після виконання функції Create і до тих пір, поки діалогове вікно не буде закрито, клас діалогового вікна міститиме цілком допустиме значення дескриптора HWND. Щоб використовувати цей дескриптор або просто з'ясувати, чи активне ще дане діалогове вікно, досить викликати функцію GetSafeHwnd цього класу, що дозволяє легко маніпулювати станом елементів управління (пунктом меню в даному випадку) на підставі наявності або відсутності вікна.

Але авторові особисто цей підхід не подобається, він вважає за краще просто передавати фокус вже відкритому діалоговому вікну, якщо користувач знову вибирає цей пункт:

 

void CMyView::OnEditFind () {

ASSERT(m_pDlg); if (m_pDlg)

{'

if (!ra_pDlg->GetSafeHwnd()) {

m_pDlg->Create(IDD_FIND, this); m_pDlg->ShowWindow(SW_SHOW); }

else {

m_pDlg->SetFocu.s() ;

}

}