Недокументированные возможности класса CMainFrame
Изучая пример приложения DOCKTOOL, поставляемого вместе с Microsoft Visual C++, мы обнаружили, что для отображения и удаления с экрана панелей управления используется метод OnBarCheck.
Метод вызывается из таблицы сообщений класса главного окна приложения CMainFrame. Для этого используется макрокоманда ON_COMMAND_EX. В случае прихода командных сообщений от строк меню, отвечающих за показ на экране панелей управления, вызывается метод OnBarCheck и ему в качестве параметра передается идентификатор соответствующей строки меню:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
// Другие макрокоманды таблицы сообщений
ON_COMMAND_EX(IDW_BROWSE_BAR, OnBarCheck)
ON_COMMAND_EX(IDW_DEBUG_BAR, OnBarCheck)
ON_COMMAND_EX(IDW_EDIT_BAR, OnBarCheck)
END_MESSAGE_MAP()
Таким образом, когда пользователь выбирает из меню View приложения строку с именем панели управления, выдается командное сообщение с идентификатором, соответствующим строке меню и самой панели управления (идентификаторы панелей управления идентичны идентификаторам соответствующих строк меню View). Командное сообщение обрабатывается таблицей сообщений класса CMainFrame. Для его обработки вызывается метод OnBarCheck, которому в качестве параметра передается идентификатор панели управления.
Если вы решите поискать описание метода OnBarCheck в справочной системе Microsoft Visual C++, вас ждет разочарование. Ни в класс CFrameWnd, ни в один из его базовых классов метод OnBarCheck не входит. Когда вы вернетесь к исходным текстам самого приложения, в них вы также не обнаружите определение этого метода.
Мы проявили настойчивость и смогли обнаружить метод OnBarCheck только в исходных текстах библиотеки классов MFC. Оказывается, несмотря на отсутствие описания метода OnBarCheck в документации библиотеки MFC, этот метод входит в хорошо известный вам класс CFrameWnd.
В файле Afxwin.h, в котором объявлен класс CFrameWnd, вы можете найти объявления входящих в него методов OnUpdateControlBarMenu и OnBarCheck:
class CFrameWnd : public CWnd
{
// ...
// Command Handlers
public:
afx_msg void OnUpdateControlBarMenu(CCmdUI* pCmdUI);
afx_msg BOOL OnBarCheck(UINT nID);
}
Определения исходных текстов методов OnUpdateControlBarMenu и OnBarCheck содержатся в файле Winfrm.cpp.
В файле Winfrm.cpp также можно найти обращения к методам OnUpdateControlBarMenu и OnBarCheck в таблице сообщений класса CFrameWnd. Приведем соответствующий фрагмент этой таблицы:
BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)
// turning on and off standard frame gadgetry
ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR,
OnUpdateControlBarMenu)
ON_COMMAND_EX(ID_VIEW_STATUS_BAR, OnBarCheck)
ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR,
OnUpdateControlBarMenu)
ON_COMMAND_EX(ID_VIEW_TOOLBAR, OnBarCheck)
END_MESSAGE_MAP()
Две пары макрокоманд ON_UPDATE_COMMAND_UI и ON_COMMAND_EX вызывают методы OnUpdateControlBarMenu и OnBarCheck для обработки командных сообщений с идентификаторами ID_VIEW_STATUS_BAR и ID_VIEW_TOOLBAR. Командные сообщения с такими идентификаторами поступают при выборе строк Toolbar и Status Bar меню View.
Меню View, содержащее строки Toolbar и Status Bar, вставляется во все приложения с оконным интерфейсом, которые созданы с использованием средств MFC AppWizard.
Рассмотрим теперь сами методы OnBarCheck и OnUpdateControlBarMenu. Метод OnBarCheck класса CFrameWnd определен следующим образом:
//////////////////////////////////////////////////////////////
// Метод OnBarCheck класса CFrameWnd
BOOL CFrameWnd::OnBarCheck(UINT nID)
{
ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);
CControlBar* pBar = GetControlBar(nID);
if (pBar != NULL)
{
ShowControlBar(pBar,
(pBar->GetStyle() & WS_VISIBLE) == 0, FALSE);
return TRUE;
}
return FALSE;
}
Отладочная версия метода OnBarCheck класса CFrameWnd проверяет соответствие идентификаторов ID_VIEW_STATUS_BAR, AFX_IDW_STATUS_BAR и ID_VIEW_TOOLBAR, AFX_IDW_TOOLBAR. Отметим, что эти идентификаторы определены в файле Afxres.h следующим образом:
#define AFX_IDW_TOOLBAR 0xE800
#define AFX_IDW_STATUS_BAR 0xE801
#define ID_VIEW_TOOLBAR 0xE800
#define ID_VIEW_STATUS_BAR 0xE801
Метод GetControlBar класса CFrameWnd определяет указатель на объект класса CControlBar, который представляет панель управления или панель состояния с идентификатором nID. Идентификаторы строк меню ID_VIEW_TOOLBAR и ID_VIEW_STATUS_BAR соответствуют стандартным идентификаторам панели управления AFX_IDW_TOOLBAR и панели состояния AFX_IDW_STATUS_BAR.
При выборе из меню View строки Toolbar передается командное сообщение ID_VIEW_TOOLBAR, а при выборе строки Status bar - сообщение ID_VIEW_STATUS_BAR. Во время обработки этих сообщений, вызов метода GetControlBar определит объект класса CControlBar, соответствующий либо панели управления AFX_IDW_TOOLBAR, либо панели состояния AFX_IDW_STATUS_BAR.
Затем метод ShowControlBar отображает или закрывает соответствующую панель. Если панель была открыта, метод ShowControlBar скрывает ее и наоборот.
Аналогичным образом устроен метод OnUpdateControlBarMenu класса CFrameWnd, который обрабатывает команды обновления (по умолчанию, он обрабатывает команды обновления от строк Toolbar и Status bar меню View).
Метод OnUpdateControlBarMenu проверяет, отображается ли на экране панель управления или панель состояния с идентификатором, соответствующим идентификатору команды обновления. Если панель отображается, то строка меню отмечается символом Ö:
//////////////////////////////////////////////////////////////
// Метод OnUpdateControlBarMenu класса CFrameWnd
void CFrameWnd::OnUpdateControlBarMenu(CCmdUI* pCmdUI)
{
ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);
CControlBar* pBar = GetControlBar(pCmdUI->m_nID);
if (pBar != NULL)
{
pCmdUI->SetCheck((pBar->GetStyle() & WS_VISIBLE) != 0);
return;
}
pCmdUI->ContinueRouting();
}
В конце метода OnUpdateControlBarMenu класса CFrameWnd вызывается метод ContinueRouting класса CCmdUI, который направляет команду обновления для дальнейшей обработки другим классам MFC (см. раздел “Обработка командных сообщений”).