Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > CWnd-derived контрол и DDX_Control


Автор: 0x07L 5.8.2006, 20:28
Делаю элемент управления, производный от CWnd. Как его создать в диалоговом окне с помощью мастера? Делаю так:

--- бросаю на форму "Custom Control"
--- создаю, как обычно, свой класс, производный от CWnd
--- в классе диалогового окна добавляю член-объект моего класса
--- перегружаю функцию DoDataExchange и вставляю туда соответствующий DDX_Control.

Проблема в том, что диалоговое окно не создается. Даже OnInitDialog не вызывается.
То же самое происходит, если просто кинуть на форму "Custom Control" и не трогать его.

Видимо, надо еще что-то сделать. Что?

Могу привести тестовую программку.

Заранее спасибо.

Автор: 0x07L 5.8.2006, 21:36
Да, опять я чего-то перемудрил. И "Custom Control" оказался не тем, о чем я думал... В общем, переформулирую вопрос: как сделать так, чтобы мой элемент управления можно было создавать с помощью мастера? Я понимаю, что, скорее всего, это осуществить не получится.

Автор: Earnest 8.8.2006, 09:48
Именно. Чтобы создать свой элемент с помощью редактора ресурсов, нужно, чтобы был подходящий исходный. Если такового нет - только через Create. Custom Control - тоже можно, но по-моему, это неудобно и громоздко.
Я обычно делаю так. Кладу на форму в нужно месте статик (рамку) нужного размера с нужным идентификатором и некоторыми стилями. Затем у меня есть функция, которая создает на месте этого статика нужное мне окно с тем же ид-ром в том же z-порядке, а ненужный статик - удаляет. Вот ее код:
(Функция определена в базовом классе, от которого все диалоги наследуются)

Код

// поместить заданный (pChild) контрол на месте другого (nID), с тем же z-order;
// если pChild еще не создан - создать с тем же ID

bool CWiseDialogBase::Replace(UINT nID,CWnd* pChild)
{
   CWnd* pParent = Wnd();
   ASSERT(pChild && IsWindow(*pParent));
   ASSERT(!IsWindow(*pChild) || pChild->GetParent() == pParent);

   // ищем место для нового поля
   CWnd* pSite = pParent->GetDlgItem(nID);
   if (!pSite) { ASSERT(0); return false; }

   CRect rPos; pSite->GetWindowRect(rPos);
   pParent->ScreenToClient(rPos);

   const CWnd* pPrev = pSite->GetNextWindow(GW_HWNDPREV);
   if (pPrev==0) pPrev = &CWnd::wndTop;
   
   DWORD dwStyle = pSite->GetStyle() & (WS_GROUP|WS_TABSTOP|WS_VISIBLE);

   pSite->DestroyWindow();

   if (!IsWindow(*pChild))
   {
       // предполагается, что окно умеет себя создавать (знает свой класс и т.д.)
       if (!pChild->Create(0,0,dwStyle|WS_CHILD,CRect(0,0,0,0),pParent,nID))
           return false;
   }

   pChild->SetWindowPos(pPrev,rPos.left,rPos.top,rPos.Width(),rPos.Height(),SWP_NOACTIVATE);
   return true;
}


Пользоваться - очень просто: в классе-диалоге объявляем переменную нужного типа, скажем CMyClass m_wndMy;
Потом в OnInitDialog вызываем Replace (IDC, &m_wndMy);
Все. Стили WS_GROUP,WS_TABSTOP,WS_VISIBLE копируются (к сожалению, из статика больше не выжмешь). 
Важное замечание: поскольку Create вызывается с нулевым стилем, нужно в PreCreateWindow подставить нужный класс, если то, что MFC использует по умолчанию не подходит.

Автор: 0x07L 8.8.2006, 10:30
Спасибо!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)