15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Сабклассинг (SubClass) MDIClient в MFC

В MFC, окно MDICLIENT хранится в public переменной HWND (m_hwndMDIClient) класса CMDIFrameWnd. CMDIFrameWnd является базовым классом для CMainFrame в сгенерированном визардом MDI приложении.

Для сабклассинга окна MDICLIENT необходимо проделать три шага :

  1. Воспользуйтесь визардом, чтобы наследовать класс от CWnd и назовите его CMDIClientWnd.
  2. В CMDIClientWnd добавьте функцию GetSuperWndProcAddr().
  3. Для сабклассинга окна MDICLIENT используйте CMDIClientWnd.

Как только будет сделан сабклассинг окна MDICLIENT, обработчики сообщений и другие функции можно будет располагать в классе CMDIClientWnd.

Ниже, каждый шаг расписан подробнее:

  1. Воспользуйтесь визардом, чтобы наследовать класс от CWnd и назовите его CMDIClientWnd.

    Подробнее об этом можно узнать в документации по ClassWizard, в разделе "Adding a New Class".

  2. В CMDIClientWnd добавьте функцию GetSuperWndProcAddr().

    ВНИМАНИЕ: Данный шаг необходим только если Вы используете 16-битную версию Visual C++, а не 32-битную. 32-битная версия Visual C++ уже включает эту функцию.

    Как только класс создан, добавьте следующий прототип в заголовочный файл:
          public:
              WNDPROC* GetSuperWndProcAddr(); 

    А также добавьте следующую функцию в файл .CPP:

          WNDPROC* CMDIClientWnd::GetSuperWndProcAddr() {
              static WNDPROC NEAR pfnSuper = NULL;
              return &pfnSuper;
          } 


  3. Используйте CMDIClientWnd для сабклассинга окна MDICLIENT в классе CMDIFrameWnd class (обычно CMainFrame).

    В класс CMainFrame добавьте public переменную типа CMDIClientWnd назвав её m_wndMDIClient. Затем измените OnCreate для CMainFrame как показано ниже:
          int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
          {
              if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
              return -1;
    
              if (!m_wndMDIClient.SubclassWindow (m_hWndMDIClient)) { // Добавить
                  TRACE ("Failed to subclass MDI client window\n");   // Добавить
                  return (-1);                                        // Добавить
              }                                                       // Добавить
          ...
          } 



После выполнения всех трёх шагов, Вы можете использовать ClassWizard, чтобы добавить обработчики сообщений в CMDIClientWnd подобно коду, который показан ниже и который меняет фоновый цвет MDICLIENT.

BOOL CMDIClientWnd::OnEraseBkgnd(CDC* pDC)
{
  // Устанавливаем цвет кисти, соответствующий цвету фона
  CBrush backBrush(RGB(255, 128, 128));

  // Записываем старую кисть
  CBrush* pOldBrush = pDC->SelectObject(&backBrush);

  CRect rect;
  pDC->GetClipBox(&rect);     // Стираем нужную область
  pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),
      PATCOPY);
  pDC->SelectObject(pOldBrush);
  return TRUE;
}