Метод OnCreate класса CMultiMenuWindow
Метод OnCreate класса CMultiMenuWindow сначала вызывает метод OnCreate базового класса CFrameWnd, чтобы создать главное окно приложения:
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
Затем мы создаем панель состояния, указывая в качестве ее родительского окна главное окно приложения. Для этого мы вызываем метод Create объекта m_wndStatusBar, представляющего панель состояния, передавая ему в качестве параметра значение this. В данном случае это означает, что окно приложения является родительским окном для панели состояния:
if(!m_wndStatusBar.Create(this))
{
// Ошибка при создании панели состояния
TRACE0("Failed to create status bar\n");
return -1;
}
После того, как панель состояния создана, отображаем на ней единственный индикатор, вызывая метод SetIndicators. В качестве первого параметра передаем методу SetIndicators идентификатор этого единственного индикатора панели состояния, записанный в переменной indicator. Второй параметр метода SetIndicators, равен единице. Он определяет, что индикатор в панели состояния будет только один:
if(!m_wndStatusBar.SetIndicators(&indicator,1))
{
// Ошибка при установке индикатора
TRACE0("Failed to set indicators\n");
return -1;
}
Более подробно о принципах устройства панелей состояния мы расскажем в отдельном разделе, который носит название “Панель состояния”.
Метод OnCreate класса CSplashWnd
Метод OnCreate класса вызывается при создании окна CSplashWnd, когда через таблицу сообщений проходит сообщение WM_CREATE. Реализация метода OnCreate класса CSplashWnd сначала вызывает метод OnCreate базового класса CWnd, который собственно и создает окно:
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
Далее вызывается метод CenterWindow, который выполняет центровку окна на экране:
CenterWindow();
Метод CenterWindow определен в классе CWnd следующим образом:
void CenterWindow(CWnd* pAlternateOwner = NULL);
Если вызвать метод CenterWindow без указания параметров, или указать в качестве параметра значение NULL, то дочернее окно будет отцентровано относительно своего родительского окна, а всплывающее окно - относительно его владельца. Воспользовавшись параметром pAlternateOwner, вы можете указать другие окна относительно которых надо выполнить центровку.
Затем метод OnCreate создает таймер, посылающий окну CSplashWnd сообщения с идентификатором 1 каждые 750 миллисекунд:
SetTimer(1, 750, NULL);
Метод SetTimer определен в классе CWnd и имеет три параметра. Параметр nIDEvent задает идентификатор, который будет выступать в качестве идентификатора сообщений WM_TIMER от таймера. Таймер будет вырабатывать сообщения с периодом, приведенным во втором параметре метода - nElapse:
UINT SetTimer(
UINT nIDEvent,
UINT nElapse,
void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD)
);
Если третий параметр lpfnTimer равен NULL, то сообщения от таймера передаются окну для которого вызван метод SetTimer. Именно так используется метод SetTimer компонентом Splash Screen. Все сообщения таймера поступают окну CSplashWnd и обрабатываются в его таблице сообщений.
В качестве параметра lpfnTimer можно указать имя функции обратного вызова, которая будет обрабатывать сообщения WM_TIMER вместо таблицы сообщений окна. Более подробно об использовании таймера и, в частности, о функции обратного вызова таймера читайте в 11 томе серии “Библиотека системного программиста”.
Метод SetTimer возвращает в случае успешного создания таймера его идентификатор - ненулевое значение. Если таймер не создан, метод возвращает нулевое значение.
Метод OnCreate класса CStateWindow
Метод OnCreate класса CStateWindow сначала вызывает метод OnCreate базового класса CFrameWnd:
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
Затем мы создаем панель состояния, указывая в качестве ее родительского окна главное окно приложения:
if(!m_wndStatusBar.Create(this))
{
// Ошибка при создании панели состояния
TRACE0("Failed to create status bar\n");
return -1;
}
После того, как панель состояния создана, вызываем метод SetIndicators, чтобы установить индикаторы:
if(!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
// Ошибка при установке индикаторов
TRACE0("Failed to set indicators\n");
return -1;
}
Массив, содержащий идентификаторы индикаторов indicators определен в приложении следующим образом:
static UINT indicators[] =
{
ID_SEPARATOR, // Самый первый индикатор
ID_INDICATOR_OVR, // Индикатор OVR
ID_INDICATOR_PROGRESS, // Резервирование места для
// progress bar
ID_INDICATOR_CAPS, // Индикатор клавиши <Caps Lock>
ID_INDICATOR_NUM, // Индикатор клавиши <Num Lock>
ID_INDICATOR_SCRL, // Индикатор клавиши <Scroll Lock>
ID_INDICATOR_TEXT, // Индикатор TEXT/PIC
ID_INDICATOR_ADD, // Индикатор ADD/SUB (начальное
// состояние START)
};
Порядок идентификаторов в массиве indicators соответствует порядку в котором индикаторы будут отображаться в панели состояния. Размер всех индикаторов, кроме первого, выбирается автоматически, так чтобы текст индикатора полностью в нем поместился. Текст индикатора, который отображается в нем по умолчанию, берется из соответствующих строковых ресурсов приложения. Так, например, в последнем индикаторе панели состояния, который имеет идентификатор ID_INDICATOR_ADD будет отображаться строка START, имеющая тот же идентификатор и определенная в ресурсах приложения следующим образом:
STRINGTABLE DISCARDABLE
BEGIN
ID_INDICATOR_ADD "START"
END
Все индикаторы панели состояния, кроме индикатора ID_INDICATOR_PROGRESS, отображаются стандартным образом. Стиль индикатора ID_INDICATOR_PROGRESS устанавливается отдельно:
m_wndStatusBar.SetPaneInfo(
m_wndStatusBar.CommandToIndex(ID_INDICATOR_PROGRESS),
ID_INDICATOR_PROGRESS,
SBPS_DISABLED | // текст не отображается
SBPS_NOBORDERS, // рамка вокруг индикатора отсутствует
150 ); // ширина индикатора 150 пикселов
Метод SetPaneInfo запрещает отображение текста внутри индикатора и убирает выделяющую рамку. Кроме того, метод SetPaneInfo устанавливает размер индикатора 150 пикселов.
Метод OnDisable класса CMultiMenuWindow
Когда пользователь выбирает из меню Menu строку Disable или нажимает комбинацию клавиш <Ctrl+D>, приложению поступает командное сообщение, которое имеет идентификатор ID_MENU_DISABLE. Для обработки этого сообщения вызывается метод OnDisable класса CMultiMenuWindow. Этот метод изменяет состояние флагов bEnable и nCheck.
Значение флага bEnable изменяется с TRUE на FALSE и наоборот, а значение флага bEnable с 1 на 0 и наоборот:
bEnable = !bEnable;
nCheck = (nCheck == 1) ? 0 : 1;
Сам метод OnDisable не меняет состояния строк меню приложения, но изменение флагов bEnable и nCheck фиксируется обработчиком команд обновления меню.
Так, флаг bEnable управляет блокировкой строки Process меню Mission (для полного варианта меню) и строки Process меню File (для укороченного варианта меню). Флаг bEnable проверяется методом OnUpdateProcess, который является обработчиком команд обновления от этих строк меню.
Флаг nCheck управляет отображением символа Ö около строки Disable меню Menu. Флаг nCheck проверяется методом OnUpdateDisable, который является обработчиком команд обновления от этой строки меню.
Метод OnDraw класса CMultiView
Метод OnDraw первоначально определен в классе CView как виртуальный и вызывается, когда приложение должно перерисовать документ в окне просмотра. MFC AppWizard переопределяет для вас метод OnDraw класса CView следующим образом:
void CMultiView::OnDraw(CDC* pDC)
{
CMultiDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO:
}
Первые две строки метода OnDraw получают указатель pDoc на документ, связанный с данным окном просмотра.
Метод OnGetRecordset класса CDaterView
Метод OnGetRecordset класса CDaterView возвращает указатель m_pSet на запись базы данных:
//////////////////////////////////////////////////////////////
// Метод OnGetRecordset класса CDaterView
CRecordset* CDaterView::OnGetRecordset()
{
return m_pSet;
}
Метод OnInitialUpdate класса CDaterView
Метод OnInitialUpdate класса окна просмотра CDaterView первоначально определен в базовом классе CView. Этот метод вызывается MFC перед отображением окна просмотра на экране:
//////////////////////////////////////////////////////////////
// Метод OnInitialUpdate класса CDaterView
void CDaterView::OnInitialUpdate()
{
m_pSet = &GetDocument()->m_daterSet;
CRecordView::OnInitialUpdate();
}
В момент вызова метода OnInitialUpdate окно просмотра уже связано с объектом документа приложения, поэтому можно использовать метод GetDocument.
В нашем случае метод GetDocument используется, чтобы записать в переменную m_pSet (входящую в класс CDaterView) укзатель на объект m_daterSet класса CDaterSet, представляющий записи базы данных и входящий в класс документа приложения - класс CDaterDoc.
Затем вызывается метод OnInitialUpdate базового класса CRecordView.
Метод OnMenuDirectADD_SUB класса CStateWindow
Когда пользователь выбирает из меню Work строки Direct set ADD и Direct set SUB, в класс окна поступают командные сообщения с идентификаторами ID_WORK_DIRECT_ADD и ID_WORK_DIRECT_SUB. Для их обработки вызывается метод OnMenuDirectADD_SUB:
ON_COMMAND_EX(ID_WORK_DIRECT_ADD, OnMenuDirectADD_SUB)
ON_COMMAND_EX(ID_WORK_DIRECT_SUB, OnMenuDirectADD_SUB)
В качестве параметра nID методу OnMenuDirectADD_SUB передается соответствующий идентификатор:
BOOL CStateWindow::OnMenuDirectADD_SUB(UINT nID)
{
}
Порядок индикаторов в панели состояния не меняется, например, индикатор с идентификатором ID_INDICATOR_ADD, всегда будет иметь в нашем приложении индекс 7. Однако чтобы продемонстрировать метод CommandToIndex и сделать метод OnMenuDirectADD_SUB более независимым от расположения индикаторов, мы определяем индекс индикатора ID_INDICATOR_ADD:
int nIndex = m_wndStatusBar.CommandToIndex(ID_INDICATOR_ADD);
Следующим шагом мы устанавливаем нормальный режим отображения индикатора ID_INDICATOR_ADD. Для этого вызываем метод SetPaneStyle, указав ему индекс индикатора и атрибут SBPS_NORMAL:
m_wndStatusBar.SetPaneStyle(nIndex, SBPS_NORMAL);
Затем определяем, какое командное сообщение послужило причиной вызова метода OnMenuDirectADD_SUB. Если метод вызван для обработки командного сообщения от строки Direct set ADD меню Work, отображаем в индикаторе текст ADD:
if(nID == ID_WORK_DIRECT_ADD)
{
// Выводим текст ADD
m_wndStatusBar.SetPaneText(nIndex, "ADD");
}
Если метод OnMenuDirectADD_SUB вызван для обработки командного сообщения от строки Direct set SUB меню Work, изменяем внешний вид индикатора и отображаем в нем текст SUB:
else if(nID == ID_WORK_DIRECT_SUB)
{
// Изменяем внешний вид индикатора
m_wndStatusBar.SetPaneStyle(nIndex, SBPS_POPOUT);
// Выводим текст SUB
m_wndStatusBar.SetPaneText(nIndex, "SUB");
}
Для вывода текста в индикаторе ID_INDICATOR_ADD в методе OnMenuDirectADD_SUB мы используем метод SetPaneText класса CStatusBar. Метод SetPaneText не меняет размера индикатора. Поэтому, если вы желаете отобразить текст большей длины, надо увеличить размер индикатора с помощью метода SetPaneInfo.
Метод OnMenuDirectADD_SUB класса CStateWindow вызывается для обработки командного сообщения с идентификатором ID_WORK_DISABLE_ADDSUB, передаваемым при выборе из меню Work строки Disable ADD SUB.
Метод OnMenuDisableADD_SUB определяет индекс индикатора ID_INDICATOR_ADD, а затем блокирует его.
Чтобы узнать индекс индикатора ID_INDICATOR_ADD, мы вызываем метод CommandToIndex:
int nIndex = m_wndStatusBar.CommandToIndex(ID_INDICATOR_ADD);
Для блокировки индикатора вызываем метод SetPaneStyle, которому указываем индекс индикатора и атрибут SBPS_DISABLED:
m_wndStatusBar.SetPaneStyle(nIndex, SBPS_DISABLED);
Метод OnMenuExit класса CMultiMenuWindow
Пользователь может завершить приложение, выбрав из меню File строку Exit. В этом случае приложению передается командное сообщение с идентификатором ID_FILE_EXIT. Соответствующая макрокоманда ON_COMMAND из таблицы сообщений класса CStateWindow вызывает для обработки этого сообщения метод OnMenuExit:
ON_COMMAND(ID_WORK_EXIT, OnMenuExit)
Метод OnMenuExit завершает работу приложения, для чего вызывает метод DestroyWindow, определенный в классе CWnd, для главного окна приложения:
void CMultiMenuWindow::OnExit()
{
// Завершаем приложение
DestroyWindow();
return;
}
Метод OnMenuExit класса CStateWindow
Пользователь может завершить приложение, выбрав из меню Work строку Exit. В этом случае приложению передается командное сообщение с идентификатором ID_WORK_EXIT. Соответствующая макрокоманда ON_COMMAND из таблицы сообщений класса CStateWindow вызывает для обработки этого сообщения метод OnMenuExit:
ON_COMMAND(ID_WORK_EXIT, OnMenuExit)
Метод OnMenuExit завершает работу приложения, для чего вызывает метод DestroyWindow, определенный в классе CWnd для главного окна приложения:
DestroyWindow();
Метод OnMenuProcessBar класса CStateWindow
Когда пользователь выбирает из меню Work строку Process, на месте индикатора ID_INDICATOR_PROGRESS создается линейный индикатор progress bar, плавно меняющий свое состояние. Обработка командного сообщения от строки Process меню Work осуществляется методом OnMenuProcessBar класса CStateWindow.
Метод OnMenuProcessBar определяет координаты индикатора ID_INDICATOR_PROGRESS и записывает их во временную переменную rectProgress:
RECT rectProgress;
m_wndStatusBar.GetItemRect(
m_wndStatusBar.CommandToIndex(ID_INDICATOR_PROGRESS),
&rectProgress);
Затем на месте этого индикатора создается линейный индикатор progress bar. Орган управления progress bar представлен объектом ctrlProgressBar класса CProgressCtrl:
CProgressCtrl ctrlProgressBar;
Непосредственно для создания progress bar используется метод Create класса CProgressCtrl. В качестве параметров этому методу указываются атрибуты WS_CHILD и WS_VISIBLE, координаты rectProgress, объект m_wndStatusBar и идентификатор 1:
if(!ctrlProgressBar.Create(WS_CHILD | WS_VISIBLE,
rectProgress, &m_wndStatusBar, 1))
{
// Ошибка при создании progress bar
TRACE0("Failed to create progress bar\n");
return;
}
После создания полосы progress bar устанавливаем границы (от 0 до 100), в которых можно менять его значение:
ctrlProgressBar.SetRange(0, 100);
Выбираем шаг приращения для progress bar, равный единице:
ctrlProgressBar.SetStep(1);
Затем начинаем в цикле изменять значение линейного индикатора progress bar. Чтобы замедлить ход заполнения линейного индикатора, делаем короткую задержку, вызывая функцию Sleep:
for(int i=0;i<100;i++)
{
Sleep(10); ctrlProgressBar.StepIt();
}
Когда линейный индикатор progress bar окажется заполнен, вызываем метод SetWindowText, который отображает сообщение Process completed в самом первом индикаторе панели состояния:
m_wndStatusBar.SetWindowText("Process completed");
После завершения метода OnMenuProcessBar объект ctrlProgressBar, представляющий линейный индикатор progress bar, уничтожается и одновременно его изображение исчезает с панели состояния.
Метод OnPaint класса CSplashWnd
Метод OnPaint класса CSplashWnd вызывается для обработки сообщений WM_PAINT, когда надо перерисовать изображение в окне. Компонент Splash Screen использует этот метод, чтобы вывести изображение bitmap в окне заставки:
void CSplashWnd::OnPaint()
{
CPaintDC dc(this);
CDC dcImage;
if (!dcImage.CreateCompatibleDC(&dc))
return;
BITMAP bm;
m_bitmap.GetBitmap(&bm);
// Paint the image.
CBitmap* pOldBitmap = dcImage.SelectObject(&m_bitmap);
dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight,
&dcImage, 0, 0, SRCCOPY);
dcImage.SelectObject(pOldBitmap);
}
Метод OnTimer класса CSplashWnd
Метод OnTimer класса CSplashWnd вызывается для обработки сообщений от таймера, созданного в методе OnCreate. Этот метод вызывается всего один раз. При обработке первого сообщения от таймера он закрывает окно CSplashWnd и вместе с ним прекращает работу таймер.
Для того чтобы закрыть окно заставки, используется метод HideSplashScreen, определенный в классе CSplashWnd:
HideSplashScreen();
Метод OnUpdateConstruct класса CMultiMenuWindow
Команда обновления от строки Construction меню Mission передается для обработки методу OnUpdateConstruct класса CMultiMenuWindow. Этот метод устанавливает или снимаем отметку · со строки Construction в зависимости от значения флага bRadio:
pCmdUI->SetRadio(bRadio);
Метод OnUpdateDisable класса CMultiMenuWindow
Команда обновления от строки Disable меню Menu передается для обработки методу OnUpdateDisable класса CMultiMenuWindow. Этот метод устанавливает или снимаем отметку Ö со строки Disable, в зависимости от значения флага nCheck:
pCmdUI->SetCheck(nCheck);
Метод OnUpdateProcess класса CMultiMenuWindow
Команды обновления от строк Process меню File и Mission передаются для обработки методу OnUpdateProcess класса CMultiMenuWindow. Этот метод блокирует или снимает блокировку со строки Process в зависимости от значения флага bEnable:
pCmdUI->Enable(bEnable);
Метод PostNcDestroy класса CSplashWnd
Метод PostNcDestroy класса CSplashWnd вызывается уже после того как окно заставки закрыто и используется дл того, чтобы удалить объект класса CSplashWnd, представляющий это окно в нашем приложении:
delete this;
Метод PreCreateWindow класса CChildFrame
Метод PreCreateWindow вызывается перед созданием дочернего окна MDI. Вы можете использовать его, чтобы переопределить стили этого окна:
BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO:
return CMDIChildWnd::PreCreateWindow(cs);
}
Метод PreCreateWindow класса CDaterDoc
Метод OnNewDocument вызывается, когда надо создать новый документ для приложения. Метод OnNewDocument приложения Dater вызывает метод OnNewDocument базового класса CDocument:
BOOL CDaterDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO:
return TRUE;
}
Метод PreCreateWindow класса CDaterView
Метод PreCreateWindow вызывает метод PreCreateWindow базового класса CRecordView и выполняет обработку по умолчанию:
BOOL CDaterView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO:
return CRecordView::PreCreateWindow(cs);
}
Метод PreCreateWindow класса CMainFrame
Метод PreCreateWindow вызывается перед созданием окна и позволяет изменить его характеристики. В нашем приложении метод PreCreateWindow не используется и просто выполняет обрработку по умолчанию:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO:
return CMDIFrameWnd::PreCreateWindow(cs);
}
Метод PreCreateWindow вызывает метод PreCreateWindow базового класса CFrameWnd и выполняет обработку по умолчанию.
Метод PreCreateWindow класса CMultiView
Виртуальный метод PreCreateWindow определен в классе CWnd. Он вызывается непосредственно перед созданием окна, связанного с объектом класса. MFC AppWizard переопределяет этот метод следующим образом:
BOOL CMultiView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO:
return CView::PreCreateWindow(cs);
}
Метод PreTranslateAppMessage класса CSplashWnd
Класс CSplashWnd имеет свою таблицу сообщений. Так как в классе CSplashWnd переопределен метод PreTranslateAppMessage, то он вызывается для каждого сообщения, поступающего в это окно перед его обработкой.
В самом начале метод PreTranslateAppMessage проверяет, существует ли окно заставки. Если нет, то дополнительная обработка сообщений не выполняется:
if (c_pSplashWnd == NULL)
return FALSE;
Когда окно заставки уже создано, метод PreTranslateAppMessage определяет тип сообщения. Если сообщение поступило от мыши или клавиатуры, то для окна заставки, представленного объектом c_pSplashWnd, вызывается метод HideSplashScreen, который его закрывает не дожидаясь первого сообщения от таймера. Метод PreTranslateAppMessage в этом случае возвращает значение TRUE и обработка сообщения завершается:
if (pMsg->message == WM_KEYDOWN
pMsg->message == WM_SYSKEYDOWN
pMsg->message == WM_LBUTTONDOWN
pMsg->message == WM_RBUTTONDOWN
pMsg->message == WM_MBUTTONDOWN
pMsg->message == WM_NCLBUTTONDOWN
pMsg->message == WM_NCRBUTTONDOWN
pMsg->message == WM_NCMBUTTONDOWN)
{
c_pSplashWnd->HideSplashScreen();
return TRUE; // message handled here
}
Если поступило какое-либо другое сообщение, метод PreTranslateAppMessage возвращает значение FALSE и оно передается далее для дальнейшей обработки:
return FALSE;
Метод PreTranslateMessage класса CMultiApp
Виртуальный метод PreTranslateMessage, переопределенный в главном классе приложения CMultiApp, первоначально определен в базовом классе CWinApp. Метод PreTranslateMessage вызывается из цикла обработки сообщений перед тем как очередное сообщение будет распределено по назначению при помощи функций TranslateMessage и DispatchMessage. В качестве параметра pMsg, передается указатель на структуру типа MSG, которая представляет очередное сообщение, полученное в цикле обработки сообщений из очереди:
virtual BOOL PreTranslateMessage(MSG* pMsg);
Таким образом метод PreTranslateMessage позволяет выполнить дополнительную обработку сообщений или даже полностью изъять их из обработки (отфильтровать).
Переопределив метод PreTranslateMessage вы должны возвращать нулевое значение, если данное сообщение должно быть обработано обычным образом или ненулевое значение, если метод PreTranslateMessage сам выполняет обработку сообщения и оно не должно передаваться приложению для дальнейшей обработки.
Во время вставки в проект компонента Splash Screen в метод PreTranslateMessage главного класса приложения добавляется вызов метода PreTranslateAppMessage класса CSplashWnd.
Если метод PreTranslateAppMessage класса CSplashWnd возвращает значение TRUE, тогда метод PreTranslateAppMessage класса CMultiApp также сразу завершается и возвращает значение TRUE. Сообщения, обработанные классом CSplashWnd более не передаются приложению для дальнейшей обработки.
Если метод PreTranslateAppMessage класса CSplashWnd возвращает значение FALSE, тогда вызывается метод PreTranslateMessage базового класса CWinApp.
Заметим, что по умолчанию метод PreTranslateMessage класса CWinApp выполняет некоторую дополнительную обработку сообщений, например выделяет сообщения от клавиатуры, соответствующие комбинациям клавиш, определенным в таблице акселераторов и преобразует их в командные сообщения. Более подробно о таблице акселераторов вы можете прочитать в разделе “Таблица акселераторов” главы “Меню, панели управления и панели состояния”, а также в 13 томе серии “Библиотека системного программиста”:
BOOL CMultiApp::PreTranslateMessage(MSG* pMsg)
{
// CG: The following lines were added by the Splash Screen
// component.
if(CSplashWnd::PreTranslateAppMessage(pMsg))
return TRUE;
return CWinApp::PreTranslateMessage(pMsg);
}
В случае, если сообщение передается для обработки методу PreTranslateMessage базового класса CWinApp - CWinApp::PreTranslateMessage, метод PreTranslateMessage класса CMultiApp возвращает результат работы этого метода.
Метод PreTranslateMessage класса CMultiView
Кроме добавления новой макрокоманды к таблице сообщений класса CMultiView и соответствующего метода-обработчика OnContextMenu, компонент Pop-up Menu добавляет метод PreTranslateMessage к классу CMultiView.
В него записывается программный код, который обнаруживает нажатие комбинации клавиш <Shift+F10> или специальной клавиши на клавиатуре с дополнительными клавишами Windows 95 и напрямую вызывает метод OnContextMenu:
//////////////////////////////////////////////////////////////
// Метод PreTranslateMessage класса CMultiView
BOOL CMultiView::PreTranslateMessage(MSG* pMsg)
{
// CG: Следующий блок добавлен компонентом Pop-up Menu
{
// Если нажата комбинация клавиш <Shift+F10>
if((((pMsg->message == WM_KEYDOWN
pMsg->message == WM_SYSKEYDOWN) &&
(pMsg->wParam == VK_F10) &&
(GetKeyState(VK_SHIFT) & ~1)) != 0)
// it's Shift+F10 OR Natural keyboard key
(pMsg->message == WM_CONTEXTMENU))
{
// Определяем экранные координаты клиентской части окна
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);
// Записываем в объект point класса CPoint координаты
// левого верхнего угла клиентской части окна, добавляя
// к нему смещения в 5 пикселов по горизонтали и вертикали
CPoint point = rect.TopLeft();
point.Offset(5, 5);
// Отображаем контекстное меню в позиции point
OnContextMenu(NULL, point);
// Возвращаем значение TRUE, так как сообщение обработано
return TRUE;
}
}
// Вызываем метод PreTranslateMessage базового класса CView
return CView::PreTranslateMessage(pMsg);
}
Метод SetBarStyle класса CControlBar
Во время создания панели управления вы можете указать ее характеристики через параметр dwStyle метода Create. Если вам потребовалось изменить эти характеристики уже во время работы приложения - используйте метод SetBarStyle. Метод SetBarStyle определен в классе CControlBar, который является базовым для класса CToolBar:
void SetBarStyle(DWORD dwStyle);
Параметр dwStyle задает новые характеристики панели управления. В качестве этого параметра можно использовать комбинацию флагов, представленных в следующей таблице.
Флаг | Описание | ||
CBRS_ALIGN_TOP | Панель управления можно пристыковать к верхней границе окна | ||
CBRS_ALIGN_BOTTOM | Панель управления можно пристыковать к нижней границе окна | ||
CBRS_ALIGN_LEFT | Панель управления можно пристыковать к левой границе окна | ||
CBRS_ALIGN_RIGHT | Панель управления можно пристыковать к правой границе окна | ||
CBRS_ALIGN_ANY | Панель управления можно пристыковать к любой границе окна | ||
CBRS_TOOLTIPS | Для кнопок панели управления отображаются их краткие описания в окнах tool tips | ||
CBRS_FLYBY | Панель состояния отображает краткое описание выбранной кнопки |
Метод SetCheck
Виртуальный метод SetCheck можно использовать для изменения состояния строки меню и кнопок панели управления:
virtual void SetCheck(int nCheck = 1);
Если вы используете метод SetCheck для управления меню и задали в качестве параметра nCheck нулевое значение, то соответствующая строка меню выделяется символом Ö, если параметр nCheck не указан или равен 1, то выделение снимается.
В случае использования метода SetCheck для управления кнопкой панели управления, параметр nCheck задает новое состояние кнопки. Если параметр nCheck равен нулю, кнопка переходит в нажатое положение, если параметр nCheck не указан или равен единице - кнопка переходит в отжатое положение, а если параметр nCheck равен 2, кнопка принимает промежуточное состояние.
Вы можете использовать метод SetCheck для управления внешним видом индикаторов панелей состояния. Если параметр nCheck равен нулю, то рамка индикатора изменяется таким образом, что он будет располагается выше общего уровня панели состояния. Если параметр nCheck равен 1, тогда индикатор переходит в нормальное состояние.
Метод Enable также можно использовать для выбора положения переключателей в диалоговых панелей управления.
Метод SetMenu класса CWnd
В качестве параметра pMenu передайте методу SetMenu указатель на объект класса CMenu, представляющий меню. Если вы желаете просто удалить текущее меню, используемое окном, передайте методу SetMenu в качестве параметра значение NULL:
BOOL SetMenu(CMenu* pMenu);
В случае успешного завершения операции метод SetMenu вернет ненулевое значение. В противном случае SetMenu вернет ноль.
После того, как вы установили меню, вызвав метод SetMenu, и до того, как соответствующий объект CMenu будет удален, надо вызвать метод Detach класса CMenu. Этот метод разорвет связь между меню и соответствующим объектом класса CMenu, после чего последний может быть удален:
HMENU Detach();
Метод Detach возвращает в случае успешного завершения идентификатор меню, а в случае ошибки - значение NULL.
Сразу отметим, что если до установки меню окно уже имело меню, надо удалить его, воспользовавшись методом DestroyMenu класса CMenu. Если с меню, подлежащим удалению, не связан объект класса CMenu, вы можете обратиться к методу Attach:
BOOL Attach(HMENU hMenu);
Для этого создайте объект класса CMenu, а затем вызовите для него метод Attach, указав в качестве параметра hMenu идентификатор меню. Метод Attach возвращает в случае успешного завершения ненулевое значение, а в случае ошибки - ноль.
Чтобы определить идентификатор меню известного окна, можно воспользоваться методом GetMenu, определенным в классе CWnd. Этот метод возвращает указатель на объект типа CMenu:
CMenu* GetMenu() const;
Вы можете получить из него идентификатор меню, если обратитесь к элементу данных m_hMenu, входящему в класс CMenu.
Мы продемонстрируем различные методы создания и управления меню в приложении MultiMenu, а сейчас сделаем несколько замечаний относительно остальных методов класса CMenu.
Класс CMenu, наследованный от базового класса CObject, содержит все необходимые методы для создания и управления меню. Используя эти методы, вы можете добавлять к меню новые строки, удалять и изменять их. Специальные методы класса CMenu позволяют выделять отдельные строки меню и даже создавать элементы меню, содержащие не только текст но и изображение.
Метод SetRadio
Виртуальный метод SetRadio, также как метод SetCheck, можно использовать для изменения состояния строки меню и кнопок панели управления:
virtual void SetRadio(BOOL bOn = TRUE);
Если вы используете метод SetRadio для управления меню и задали в качестве параметра bOn значение TRUE, то соответствующая строка меню выделяется символом ·, если параметр nCheck равен FALSE, то выделение снимается.
В случае использования метода SetRadio для управления кнопкой панели управления, параметр bOn задает новое состояние кнопки. Если параметр bOn равен FALSE, кнопка переходит в нажатое положение, если параметр bOn не указан или равен TRUE - кнопка переходит в отжатое положение.
Вы можете использовать метод SetRadio для управления внешним видом индикаторов панелей состояния. Если параметр bOn равен FALSE, рамка индикатора изменяется таким образом, что он будет располагается выше общего уровня панели состояния. Если параметр bOn равен TRUE, тогда индикатор переходит в нормальное состояние.
Метод Enable также можно использовать для выбора положения переключателей в диалоговых панелей управления.
Метод SetText
Виртуальный метод SetText может быть использован для изменения текста, отображаемого в индикаторе панели состояния, в строке меню, в названии кнопок и некоторых органах диалоговых панелей управления. В качестве параметра lpszText надо указать текстовую строку, которую надо вывести:
virtual void SetText(LPCTSTR lpszText);
Следует отметить, что при использовании метода SetText для изменения текста в индикаторах панели состояния, вы должны отдельно позаботиться об изменении размера индикатора. Метод SetText не меняет размер индикатора, вы должны сами рассчитать ширину текста и изменить размер индикатора с помощью соответствующего метода. Более подробно об изменении параметров индикаторов панели состояния мы расскажем в разделе “Панель состояния”.
Метод ShowSplashScreen класса CSplashWnd
Метод ShowSplashScreen класса CSplashWnd создает и отображает на экране окно заставки. Перед этим он проверяет состояние флага c_bShowSplashWnd и переменной c_pSplashWnd:
if (!c_bShowSplashWnd c_pSplashWnd != NULL)
return;
Если флаг c_bShowSplashWnd содержит значение FALSE или объект c_pSplashWnd, представляющий окно заставки уже создан, метод ShowSplashScreen немедленно завершает свою работу.
Если эти условия не выполняются, метод ShowSplashScreen создает новый объект класса CSplashWnd, который будет представлять окно заставки:
c_pSplashWnd = new CSplashWnd;
Затем вызывается метод Create для объекта c_pSplashWnd (он, кстати, переопределен в классе CSplashWnd), который и выполняет фактическое создание окна заставки:
if (!c_pSplashWnd->Create(pParentWnd))
delete c_pSplashWnd;
else
c_pSplashWnd->UpdateWindow();
Если окно заставки не создано, метод Create возвращает нулевое значение и объект c_pSplashWnd удаляется. Если создание окна прошло успешно, для c_pSplashWnd вызывается метод UpdateWindow, вызывающий перерисовку окна. Такая перерисовка выполняется с помощью метода OnPaint класса CSplashWnd.
Методы AssertValid и Dump класса CChildFrame
Методы AssertValid и Dump переопределяются в классе CMainFrame только для отладочной версии приложения и используются при отладке приложения:
//////////////////////////////////////////////////////////////
// Диагностические методы класса CChildFrame
#ifdef _DEBUG
void CChildFrame::AssertValid() const
{
CMDIChildWnd::AssertValid();
}
void CChildFrame::Dump(CDumpContext& dc) const
{
CMDIChildWnd::Dump(dc);
}
Методы AssertValid и Dump класса CDaterDoc
Методы AssertValid и Dump класса CMainFrame могут использоваться при отладке приложения.
Методы AssertValid и Dump класса CDaterSet
Методы AssertValid и Dump класса CDaterSet могут использоваться при отладке приложения.
Методы AssertValid и Dump класса CDaterView
Методы AssertValid и Dump класса CDaterView могут использоваться при отладке приложения.
Методы AssertValid и Dump класса CMainFrame
В отладочной версии приложения класс CMainFrame содержит переопределения виртуальных методов AssertValid и Dump. Эти методы определены в базовом классе CObject и используются при отладке приложения:
//////////////////////////////////////////////////////////////
// Диагностические методы класса CMainFrame
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CMDIFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CMDIFrameWnd::Dump(dc);
}
Методы AssertValid и Dump переопределяются в классе CMainFrame только для отладочной версии приложения и используются при отладке приложения:
#ifdef _DEBUG
void CMultiView::AssertValid() const
{
CView::AssertValid();
}
void CMultiView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
#endif //_DEBUG
Методы AssertValid и Dump класса CMainFrame могут использоваться при отладке приложения.
Методы AssertValid и Dump класса CMultiDoc
Методы AssertValid и Dump переопределяются в классе CMainFrame только для отладочной версии приложения и используются при отладке приложения:
//////////////////////////////////////////////////////////////
// Диагностические методы класса CMultiDoc
#ifdef _DEBUG
void CMultiDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CMultiDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
Методы BarCommandOne и BarCommandRange класса CMultiBarWindow
Методы BarCommandOne и BarCommandRange определены в классе главного окна приложения CMultiBarWindow и используются для обработки сообщений от кнопок панелей управления.
Фактически методы BarCommandOne и BarCommandRange не выполняют никакой полезной работы. Единственное, что делает метод BarCommandOne, - это отображает на экране сообщение о том, что выбранная вами команда не реализована. Для этого мы используем метод MessageBox:
void CMultiBarWindow::BarCommandOne()
{
// Отображаем сообщение о том, что команда не реализована
MessageBox("Command not implemented");
}
Метод BarCommandRange вообще не выполняет никакой полезной работы. Однако не спешите исключать его из программы. Если вы удалите методы BarCommandOne и BarCommandRange из программы и удалите соответствующие макрокоманды из таблицы сообщений класса окна, тогда все кнопки, для обработки сообщений от которых использовались эти методы, окажутся заблокированы. MFC определит, что сообщения от кнопок не обрабатываются и запретит их использование:
void CMultiBarWindow::BarCommandRange( UINT nID )
{
// Обработчик не выполняет никакой работы
}
Методы DockControlBar и FloatControlBar класса CFrameWnd
Чтобы пристыковать панель управления к границе окна, надо вызвать метод DockControlBar класса CFrameWnd:
void
DockControlBar(
CControlBar * pBar,
UINT nDockBarID = 0,
LPCRECT lpRect = NULL
);
Панель управления, заданная параметром pBar, пристыковывается к границе окна, указанной параметром nDockBarID. В качестве nDockBarID можно использовать один или несколько флагов, перечисленных ниже.
Флаг | Описание | ||
AFX_IDW_DOCKBAR_TOP | Панель управления присоединяется к верхней границе окна | ||
AFX_IDW_DOCKBAR_BOTTOM | Панель управления присоединяется к нижней границе окна | ||
AFX_IDW_DOCKBAR_LEFT | Панель управления присоединяется к левой границе окна | ||
AFX_IDW_DOCKBAR_RIGHT | Панель управления присоединяется к правой границе окна |
Если параметр nDockBarID равен нулю, то панель управления присоединяется к любой стороне окна.
Как видите, параметр nDockBarID может задавать несколько сторон окна одновременно. В этом случае панель управления присоединяется к той границе окна, которая одновременно указана методами CFrameWnd::EnableDocking и CControlBar::EnableDocking. Если таких границ несколько, то они выбираются в следующем порядке - сначала верхняя, а если к ней панель не может быть присоединена, тогда нижняя, левая, и правая стороны окна.
Последний параметр lpRect определяет, где именно будет отображаться панель управления. Положение панели задается в экранных координатах.
Если вам надо отобразить панель управления в отдельном мини-окне и не пристыковывать его к границам окна, то вместо метода DockControlBar вызовите метод FloatControlBar класса CFrameWnd:
CFrameWnd*
FloatControlBar(
CControlBar * pBar,
CPoint point
);
Панель управления, указанная параметром pBar, отображается в отдельном мини-окне. Расположение окна панели управления задается параметром point, который указывает координаты верхнего левого угла панели управления. Используются экранные координаты.
Метод FloatControlBar возвращает указатель на текущее окно.
По умолчанию, панель управления не имеет заголовка. Для установки и изменения текста заголовка используйте метод SetWindowText, определенный в классе CWnd:
void SetWindowText(LPCTSTR lpszString);
Параметр lpszString должен содержать указатель на объект класса CString или строку символов, закрытую двоичным нулем. В ней должен быть записан заголовок для панели управления.
Методы класса CCmdUI
Важную роль в работе таких объектов интерфейса пользователя, как меню, панели управления и панели состояния, играет класс CCmdUI. Методы этого класса позволяют заблокировать отдельные элементы меню, панелей управления и панелей состояния, отметить их символами Ö или ·.
Класс CCmdUI один из немногих классов библиотеки MFC, который не имеет других базовых классов. Поэтому для объектов данного класса доступно относительно мало методов. Вы можете использовать только методы, определенные в самом классе CCmdUI.
Метод | Описание | ||
Enable | Устанавливает или снимает блокировку | ||
SetCheck | Помечает строку меню символом Ö | ||
SetRadio | Помечает строку меню символом · | ||
SetText | Устанавливает текст. Обычно используется для изменения текста в индикаторах панели состояния |
Методы класса CColorDialog
Чтобы вывести диалоговую панель выбора цвета на экран, вы должны использовать метод DoModal:
virtual int DoModal();
После отображения панели на экране пользователь может выбрать из нее цвет и нажать кнопку OK или Cancel для подтверждения выбора цвета или отказа от него. Когда диалоговая панель закрывается, метод DoModal возвращает значение IDOK или IDCANCEL, в зависимости от того, какую кнопку нажал пользователь:
CColorDialog dlgColor;
int iResult;
iResult = dlgColor.DoModal();
На экране появится стандартная диалоговая панель выбора цвета Color (рис. 4.2). В верхней половине диалоговой панели, ниже надписи Basic colors, рассположены 48 прямоугольников, имеющих различные цвета. Они представляют так называемые основные цвета. Вы можете выбрать любой из этих цветов, и нажать кнопку OK.
Рис. 4.2. Стандартная диалоговая панель Color
После того как диалоговая панель закрыта, вы можете воспользоваться методами класса CColorDialog, чтобы узнать цвета, выбранные пользователем.
Для определения цвета, выбранного пользователем можно обратиться к методу GetColor класса CColorDialog:
COLORREF GetColor() const;
Данный метод возвращает значение COLORREF, соответствующее выбранному цвету. Если вам недостаточно основных цветов, представленных в диалоговой панели Color, вы можете выбрать до 16 дополнительных цветов. Чтобы выбрать дополнительные цвета, нажмите кнопку Define Custom Colors. Диалоговая панель Color изменит свой внешний вид (рис. 4.3).
Рис. 4.3. Выбор дополнительных цветов
С правой стороны появятся дополнительные органы управления, позволяющие выбрать любой из 16777216 цветов. Когда цвет выбран, нажмите кнопку Add Custom Colors. Выбранный вами цвет будет добавлен к дополнительным цветам. С левой стороны панели, под надписью Custom colors, один из свободных прямоугольников окрасится соответствующим цветом.
Вы можете определить дополнительные цвета, выбранные пользователем в диалоговой панели Color, при помощи метода GetSavedCustomColors класса CColorDialog:
static COLORREF * GetSavedCustomColors();
Метод GetSavedCustomColors возвращает указатель на массив из 16 элементов типа COLORREF. Каждый элемент массива описывает один дополнительный цвет.
Когда диалоговая панель Color отображается приложением первый раз, все прямоугольники, отображающие дополнительные цвета, имеют белый цвет. Соответствующие элементы массива, полученного методом GetSavedCustomColors, будут иметь значение RGB(255,255,255). Дополнительные цвета, выбранные пользователем, сохраняются во время работы приложения. После перезапуска приложения дополнительные цвета сбрасываются.
Методы класса CDialogBar
Непосредственно в состав класса CDialogBar входят всего два метода - это конструктор класса CDialogBar и метод Create.
Конструктор класса CDialogBar создает только соответствующий объект, но не саму панель управления:
CDialogBar();
Чтобы создать панель управления, следует вызвать метод Create и указать ему шаблон диалоговой панели, используемый для создания диалоговой панели управления.
Метод Create имеет два различных формата:
BOOL
Create(
CWnd* pParentWnd,
LPCTSTR lpszTemplateName,
UINT nStyle,
UINT nID
);
BOOL
Create(
CWnd* pParentWnd,
UINT nIDTemplate,
UINT nStyle,
UINT nID
);
Первый параметр CWnd задает окно, для которого создается диалоговая панель управления. Обычно в качестве такого окна выступает главное окно приложения.
Второй параметр метода Create указывает шаблон панели управления. В зависимости от того, как определена панель управления, в качестве второго параметра можно использовать либо идентификатор шаблона диалоговой панели nIDTemplate, либо его имя lpszTemplateName.
Третий параметр nStyle определяет начальное положение диалоговой панели управления в окне приложения. Вы можете указать следующие флаги: CBRS_TOP, CBRS_BOTTOM, CBRS_LEFT и CBRS_RIGHT. Они позволяют установить панель управления соответственно у верхней, нижней, левой или правой границы окна.
Форма диалоговой панели управления зависит от шаблона диалоговой панели и ее расположения в окне приложения. В случае если диалоговая панель управления отображается в верхней или нижней части окна (параметр nStyle равен CBRS_TOP или CBRS_BOTTOM), то ширина панели управления соответствует ширине окна CWnd, а высота - высоте шаблона диалоговой панели. Если же диалоговая панель управления отображается с левой или правой части окна (параметр nStyle равен CBRS_LEFT или CBRS_RIGHT), то ширина панели управления соответствует ширине шаблона диалоговой панели, а высота - высоте окна CWnd.
Последний параметр nID определяет идентификатор диалоговой панели управления.
В случае успешного создания диалоговой панели управления метод Create возвращает ненулевое значение. Если при создании панели управления обнаружены ошибки, например, вы указали несуществующий шаблон диалоговой панели, тогда метод Create возвращает нулевое значение.
Методы класса CFileDialog
Создание объекта класса CFileDialog еще не вызывает отображения соответствующей диалоговой панели. Для этого необходимо воспользоваться специальным методом DoModal класса CFileDialog.
Виртуальный метод DoModal, первоначально определенный в классе CDialog, переопределен в классе CFileDialog:
virtual int DoModal();
При вызове метода DoModal для ранее созданного объекта класса CFileDialog на экране открывается соответствующая диалоговая панель. После того, как вы закончите работать с диалоговой панелью и закроете ее, метод DoModal вернет значения IDOK или IDCANCEL в случае успешного завершения и 0 - в случае возникновения ошибок.
Если вы выберите имя файла и нажмете кнопку Open (для панели Open) или кнопку Save (для панели Save As), метод DoModal вернет значение IDOK. Если вы решите отменить выбор файла и нажмете кнопку Cancel или выберите из меню диалоговой панели строку Close, метод DoModal вернет значение IDCANCEL.
После того, как вы закроете диалоговую панель и метод DoModal вернет управление, можно воспользоваться другими методами класса CFileDialog, чтобы определить имена выбранных файлов.
Метод | Описание | ||
GetPathName | Определяет полный путь выбранного файла | ||
GetFileName | Определяет имя выбранного файла | ||
GetFileExt | Определяет расширение имени выбранного файла | ||
GetFileTitle | Позволяет определить заголовок выбранного файла | ||
GetNextPathName | Если диалоговая панель позволяет выбрать сразу несколько файлов, то метод GetNextPathName можно использовать для определения полного пути следующего из выбранных файлов | ||
GetReadOnlyPref | Позволяет узнать состояние атрибута “только читаемый” (read-only) выбранного файла | ||
GetStartPosition | Возвращает положение первого элемента из списка имен файлов |
Наиболее важный метод из представленных в таблице - GetPathName. Он получает полный путь файла, выбранного из диалоговых панелей Open или Save As:
CString GetPathName() const;
Как мы уже говорили, диалоговые панели Open и Save As можно использовать для выбора нескольких файлов. Для этого, в поле Flags структуры m_ofn должен быть установлен флаг OFN_ALLOWMULTISELECT. Тогда метод GetPathName возвращает массив строк, состоящий из нескольких строк, заканчивающихся двоичным нулем. Первая из данных строк содержит путь к каталогу, в котором расположены выбранные файлы, остальные строки содержат имена выбранных файлов. Естественно, с тем чтобы выделить путь к каталогу проблем не возникает, а чтобы получить имена выбранных файлов, вы должны использовать методы GetStartPosition и GetNextPathName.
Метод GetStartPosition возвращает значение типа POSITION. Оно предназначено для передачи методу GetNextPathName и получения очередного имени выбранного файла. Если пользователь не выбрал ни одного файла, метод GetStartPosition возвращает значение NULL:
POSITION GetStartPosition() const;
Значение, полученное методом GetStartPosition, следует записать во временную переменную типа POSITION и передать ссылку на нее методу GetNextPathName:
CString GetNextPathName(POSITION& pos) const;
Метод GetNextPathName вернет полный путь первого, из выбранных в диалоговой панели файлов, и изменит значение переменной pos, переданной методу по ссылке. Новое значение переменной pos можно использовать для последующих вызовов метода GetNextPathName и получения полных путей всех остальных выбранных файлов. Когда метод GetNextPathName вернет имена всех выбранных файлов, в переменную pos записывается значение NULL.
В отличие от метода GetPathName, метод GetFileName позволяет определить только имя выбранного файла, без пути и расширения:
CString GetFileName() const;
Метод GetFileExt возвращает только расширение файла, выбранного в диалоговой панели:
CString GetFileExt() const;
Метод GetFileTitle позволяет получить полное имя файла, включая его расширение:
CString GetFileTitle() const;
В стандартных диалоговоых панелях Open и Save As имеется переключатель Read Only. Заметим, что по умолчанию этот переключатель не отображается. Если вы желаете воспользоваться этим переключателем, флаг OFN_HIDEREADONLY должен быть сброшен.
Метод GetReadOnlyPref позволяет определить положение переключателя Read Only. Если переключатель включен, то метод GetReadOnlyPref возвращает ненулевое значение. В противном случае GetReadOnlyPref возвращает нуль:
BOOL GetReadOnlyPref() const;
Методы класса CFontDialog
Для отображения диалоговой панели Font предназначен виртуальный метод DoModal:
virtual int DoModal();
Если пользователь выбрал шрифт и нажал на кнопку OK, метод DoModal возвращает идентификатор IDOK, если пользователь отменил выбор шрифта, метод DoModal возвращает идентификатор IDCANCEL.
Остальные методы класса предназначены для определения характеристик выбранного пользователем шрифта. Полное описание этих методов содержится в документации, поставляемой с Visual C++.
Метод GetCurrentFont позволяет сразу определить все характеристики выбранного щрифта, записав их в структуру LOGFONT. Вы можете найти описание структуры LOGFONT в документации SDK.
Остальные методы класса позволяют определить только отдельные характеристики выбранного шрифта. Перечислим названия этих методов.
Метод | Описание | ||
GetFaceName | Возвращает имя выбранного шрифта | ||
GetStyleName | Возвращает имя стиля выбранного шрифта | ||
GetSize | Возвращает кегль выбранного шрифта | ||
GetColor | Возвращает цвет выбранного шрифта | ||
GetWeight | Возвращает плотность выбранного шрифта | ||
IsStrikeOut | Определяет является ли шрифт выделеным перечеркнутой линией | ||
IsUnderline | Определяет является ли шрифт выделеным подчеркиванием | ||
IsBold | Определяет является ли шрифт жирным | ||
IsItalic | Определяет является ли шрифт наклонным |
Методы класса CMultiView, предназначенные для печати
Виртуальные методы OnPreparePrinting, OnBeginPrinting и OnEndPrinting, определенные в классе CView, вызываются, если пользователь желает распечатать документ, отображенный в данном окне просмотра:
//////////////////////////////////////////////////////////////
// Методы класса CMultiView, управляющие печатью документов
BOOL CMultiView::OnPreparePrinting(CPrintInfo* pInfo)
{
return DoPreparePrinting(pInfo);
}
void CMultiView::OnBeginPrinting(CDC* /*pDC*/,
CPrintInfo* /*pInfo*/)
{
// TODO:
}
void CMultiView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO:
}
Многооконное приложение, подготовленное MFC AppWizard, уже “умеет” выводить созданные в нем документы на печатающее устройство. Методы OnPreparePrinting, OnBeginPrinting и OnEndPrinting класса CView предназначены для расширения возможностей печати и в этой книге не рассматриваются.
Методы OnMenuSwitchTEXT и OnUpdateTEXT класса CStateWindow
Методы OnMenuSwitchTEXT и OnUpdateTEXT используются в приложении совместно для управления состоянием индикатора ID_INDICATOR_TEXT.
Метод OnMenuSwitchTEXT вызывается для обработки командного сообщения с идентификатором ID_WORK_ON_SWITCH_TEXT. Это сообщение поступает в случае выбора из меню Work строки Switch TEXT:
ON_COMMAND(ID_WORK_ON_SWITCH_TEXT, OnMenuSwitchTEXT)
Единственная задача метода OnMenuSwitchTEXT заключается в изменении состояния флага bIndicatorTEXT. Если флаг bIndicatorTEXT имеет значение TRUE, тогда метод OnMenuSwitchTEXT меняет его на FALSE и наоборот:
void CStateWindow::OnMenuSwitchTEXT()
{
bIndicatorTEXT = !bIndicatorTEXT;
}
Метод OnUpdateTEXT класса CStateWindow, вызывается макрокомандой ON_UPDATE_COMMAND_UI из таблицы сообщений класса CStateWindow:
ON_UPDATE_COMMAND_UI(ID_INDICATOR_TEXT, OnUpdateTEXT)
Мы используем этот метод, чтобы изменить текст, отображаемый в индикаторе ID_INDICATOR_TEXT. В зависимости от состояния флага bIndicatorTEXT, установленного методом OnMenuSwitchTEXT, метод OnUpdateTEXT отображает в индикаторе либо строку TEXT, либо строку PIC:
void CStateWindow::OnUpdateTEXT(CCmdUI* pCmdUI)
{
// В зависимости от состояния флага bIndicatorTEXT
// отображаем в индикаторе ID_INDICATOR_TEXT
// строку TEXT или PIC
if(bIndicatorTEXT)
pCmdUI->SetText("TEXT"); // отображаем строку TEXT
else
pCmdUI->SetText("PIC"); // отображаем строку PIC
// Разрешаем отображение текста в индикаторе
pCmdUI->Enable();
}
В качестве параметра pCmdUI методу OnUpdateTEXT передается указатель на объект класса CCmdUI. Этот объект представляет объект интерфейса приложения (строку меню, кнопку панели управления или индикатор панели состояния). В контексте данного конкретного метода этот объект представляет индикатор панели состояния, имеющий идентификатор ID_INDICATOR_TEXT.
Для управления индикатором мы используем методы SetText и Enable класса CCmdUI. Эти методы устанавливают текст индикатора и снимают с него блокировку (если блокировка ранее была установлена).
Методы OnNewDocument и Serialize класса CMultiDoc
В классе CMultiDoc переопределены два виртуальных метода - OnNewDocument и Serialize. Виртуальный метод OnNewDocument определен в классе CDocument, от которого непосредственно наследуется класс CSingleDoc.
Метод OnNewDocument вызывается, когда надо создать новый документ для приложения. Для одноконных приложений метод OnNewDocument вызывался только один раз при запуске приложения.
Для многооконного приложения метод OnNewDocument вызывается каждый раз, когда пользователь создает новый документ. Более подробно об использовании метода OnNewDocument мы расскажем в следующих главах, когда к шаблону приложения, созданному MFC AppWizard, мы будем добавлять собственный код:
BOOL CMultiDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: Здесь можно выполнить инициализацию документа
return TRUE;
}
Метод Serialize вызывается в тех случаях, когда надо загрузить документ из файла на диске или наоборот, записать его в файл:
//////////////////////////////////////////////////////////////
// Метод Serialize класса CMultiDoc
void CMultiDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO:
}
else
{
// TODO:
}
}
Методы OnRestrictMenu и OnFullMenu класса CMultiMenuWindow
Приложение MultiMenu имеет два меню, полное и укороченное. Вы можете выбирать, какое меню будет использоваться в данный момент, с помощью строки Restrict и Full меню Menu. Если в данный момент используется полный вариант меню, то чтобы заменить его укороченным вариантом, следует выбрать из меню Menu строку Restrict. Для обратной замены меню с укороченного варианта на полный, надо выбрать из меню Menu строку Full.
При выборе строк Restrict и Full приложению передаются командные сообщения с идентификаторами IDR_RESTRICT_MENU и IDR_FULL_MENU, соответственно. Для их обработки вызываются методы OnRestrictMenu и OnFullMenu. По сути, методы OnRestrictMenu и OnFullMenu практически идентичны. Отличие между ними заключается только в том, что метод OnRestrictMenu заменяет текущее меню укороченным вариантом меню (идентификатор меню IDR_RESTRICT_MENU), а метод OnFullMenu меняет текущее меню на полный вариант меню (идентификатор меню IDR_FULL_MENU).
Метод OnRestrictMenu работает следующим образом. Сначала он получает указатель на текущее меню окна приложения. Указатель на объект класса CMenu, представляющий это меню, записывается во временную переменную pMenu:
pMenu = this->GetMenu();
Затем текущее меню удаляется, для чего вызывается метод DestroyMenu:
pMenu->DestroyMenu();
Теперь загружается ресурс нового меню, имеющего идентификатор IDR_RESTRICT_MENU (или IDR_FULL_MENU для метода OnFullMenu):
CMenu menuRestrict; // Новое меню
menuRestrict.LoadMenu(IDR_RESTRICT_MENU);
Загруженное меню подключается к окну приложения - вызывается метод SetMenu класса окна. В качестве параметра ему передается указатель на объект menuRestrict, представляющий новое меню:
SetMenu(&menuRestrict);
И, наконец, вызывается метод Detach, отпускающий меню в “свободное плавание”, то есть отсоединяющее его от объекта menuRestrict класса CMenu:
menuRestrict.Detach();
MFC AppWizard и базы данных
Самый короткий путь для разработки приложений, работающих с базами данных заключается в использовании MFC AppWizard. С помощью MFC AppWizard вы можете быстро создать приложение, позволяющее просматривать записи базы данных. В дальнейшем вы можете совершенствовать шаблон приложения, подготовленный MFC AppWizard, с помощью средств MFC ClassWizard и добавить другие операции по работе с базой данных, такие как добавление новых записей в таблицу, поиск нужных записей и т. д.
Создайте новый проект, присвоив ему имя Dater. Используйте для создания проекта средства MFC AppWizard. AppWizard предложит вам заполнить ряд панелей, перечислив в них свойства и характеристики создаваемого приложения.
Чтобы упростить приложние, на первом шаге определения свойств приложения выберите для него однооконный интерфейс. На втором шаге MFC AppWizard запросит у вас разрешения, чтобы включить поддержку баз данных. Соответствующая диалоговая панель MFC AppWizard представлена нами на рисунке 5.6.
Рис. 5.6. Диалоговая панель MFC AppWizard - Step 2 of 6
Переключатель с зависимой фиксацией, расположенный в панели MFC AppWizard - Step 2 of 6, определяет на каком уровне в приложении будет обеспечена поддержка баз данных. Следующая таблица кратко описывает этот переключатель.
Положение переключателя | Описание | ||
None | Работа с базами данных не предусматривается | ||
Header files only | К файлаам проекта подключаются файлы заголовков, необходимые для использования средств доступа к базам данных | ||
Database view without file support | Обеспечивается работа с базами данных. Полученное приложение позволяет просматривать базу данных в окне просмотра. Приложения не работает с файлами документов. Меню File такого приложения содержит только строки, не имеющие отношения к работе с файлами, например строку Exit. Строки Open и Save (и некоторых других) в меню File отсутствуют | ||
Database view with file support | Обеспечивается работа с базами данных. Полученное приложение позволяет просматривать базу данных в окне просмотра. Поддерживается работа приложения с файлами документов. Приложение имеет полное меню File |
Мы выбрали для нашего приложения режим работы с базами данных без поддержки файлов. Переключатель надо перевести в положение Database view without file support.
Теперь надо указать MFC AppWizard какую базу данных и какую таблиицу из нее мы желаем просматривать в нашем приложении. Для этого мы должны нажать кнопку Data Source, также рассположенную в диаалоговой панели MFC AppWizard - Step 2 of 6.
На экране появится диалоговая панель Database Options (рис. 5.7). В ней находится ряд органов управления, разделенных на три группы - Datasource, Recordset type и Advanced.
Рис. 5.7. Диалоговая панель Database Options
Группа Datasource предназначена для выбора базы данных (источника данных). Вы можете использовать для доступа к базе данных либо драйверы ODBC, либо средства DAO. В этой книге мы рассмотрим использование только драйверов ODBC. Переведите переключатель Datasource в положение ODBC. Из списка, расположенного справой стороны от переключателя ODBC выберите имя источника данных. В нашем случае вы должны выбрать строку Address Pad.
В группе Recordset type отображается переключатель с зависимой фиксацией. Он может принимать одно из трех положений Snapshot, Dynaset или Table. Используйте этот переключатель, чтобы определить метод работы приложения с базой данных.
Переключатель Recordset type |
Описание |
Snapshot |
Используется для представления статических данных, которые не изменяются во время работы приложения |
Dynaset |
Подразуммевается, что база данных, представленная источником данных, может изменяться во время работы приложения. Такое изменение может выполнять другое приложение, если база данных используется в многопользовательском режиме |
В последную группу Advanced входит только один переключатель Detect dirty columns. Этот переключатель используется средствами DAO и в этой книге не рассматривается.
Когда панель Database Options заполнена, нажмите кнопку OK. На экране появится диалоговая панель Select Database Tables (рис. 5.8). Из нее вы должны выбрать имя таблицы базы данных, с которой будет работать приложение. Информация именно из этой таблицы будет отображаться нашим приложением. В нашем случае база данных (или источник данных) содержить только одну таблицу, поэтому выбор таблицы не составит труда. Просто щелкните мышью по строку TEXTBASE.TXT и нажмите кнопку OK.
Рис. 5.8. Диалоговая панель Select Database Tables
Если ваша база данных содержит несколько таблиц и приложение должно работать с ними со всеми, то уже после создания приложения средствами MFC AppWizard, вы можете воспользоваться ClassWizard, чтобы подключить остальные таблицы базы данных. Приложения, работающие одновременно с несколькими таблицами базы данных мы рассмотрим в одной из следующих книг серии “Библиотека системного программиста”.
После выбора источника данных, вы можете завершить создание приложения и нажать кнопку Finish. Вы также можете продолжить заполнять диалоговые панели MFC AppWizard. В этом случае заполните панели MFC AppWizard, оставляя все предложения по умолчанию. Единственное, что вы можете изменить для упрощения приложения, это отменить все особенности приложения, связанные с печатью. Для этого отключите переключатель Print and print preview в диалоговой панели MFC AppWizard - Step 4 of 6.
Когда вы дойдете до последней панели MFC AppWizard - Step 6 of 6 (рис. 5.9) вы можете просмотреть, какие классы составляют приложение Dater.
Рис. 5.9. Диалоговая панель MFC AppWizard - Step 6 of 6
Оказывается, в отличае от проектов, которые мы изучали ранее, класс окна просмотра приложения Dater наследуется от базового класса CRecordView, и в проект входит класс представляющий записи базы данных, который не имеет аналогов среди других изученных нами приложений. Этот класс наследуется от базового класса CRecordset.
MFC ClassWizard и команды обновления
Если приложение подготовлено с использованием MFC AppWizard, то наилучшим способом создания обработчиков команд обновления является использование средств ClassWizard. Процедура создания обработчиков команд обновления от строк меню и кнопок панелей управления практически не отличается от процедуры создания обычных обработчиков командных сообщений.
Запустите ClassWizard. На экране появится диалоговая панель MFC ClassWizard. Выберите из нее страницу Message Maps (рис. 3.2). Теперь из списка Object IDs выберите идентификатор интересующей вас строки меню или кнопки панели управления. В списке Messages появятся две строки - COMMAND и ON_UPDATE_COMMAND_UI.
Строка COMMAND позволяет создать обработчик командных сообщений, а строка ON_UPDATE_COMMAND_UI - обработчик команд обновления. О том как создавать с помощью MFC ClassWizard методы для обработки командных сообщений, мы рассказывали в 24 томе серии “Библиотека системного программиста”, посвященном библиотеке классов MFC.
Чтобы создать обработчик для команды обновления, выберите из списка Messages строку ON_UPDATE_COMMAND_UI, а из списка Class name имя класса к которому будет добавлен новый метод. Нажмите кнопку Add Function. MFC ClassWizard предложит имя для нового метода. Вы можете согласиться с предложением ClassWizard или изменить имя метода по своему усмотрению. В частности, для нескольких разных строк меню или кнопок панели управления вы можете указать один и тот же метод обработчик.
Рис. 3.2. MFC ClassWizard
К сожалению, MFC ClassWizard не позволяет назначить один обработчик команд обновления нескольким объектам пользовательского интерфейса с помощью макрокоманды ON_UPDATE_COMMAND_UI_RANGE. Вместо одной макрокоманды ON_UPDATE_COMMAND_UI_RANGE MFC ClassWizard разместит в таблице сообщений необходимое количество макрокоманд ON_UPDATE_COMMAND_UI.
Еще одно неприятное ограничение MFC ClassWizard заключается в том, что он не дает возможности создать обработчики для команд обновления от индикаторов панели состояния. Такие обработчики вы должны будете добавлять к классам приложения вручную.
значительно расширены, даже по
Возможности Microsoft Visual C++ версии 4. 2 значительно расширены, даже по сравнению с предыдущей версией Visual C++. Ниже мы перечислили только самые интересные, на наш взгляд, новшества.
Microsoft Visual C++ версия 4.2, Enterpise Edition
По сравнению с обычной версией Microsoft Visual C++ 4.2, версия Enterpise Edition, значительно расширяет возможности программиста при работе с базами данных.
Если вы используете в своих программах базы данных Microsoft SQL Server или Oracle, то в окне Project Workspace появится новая страница - DataView. В ней представлены различные объекты базы данных - таблицы, хранимые процедуры, триггеры и т. д.
В состав Microsoft Visual C++ 4.2 Enterpise Edition включен отладчик, позволяющий отлаживать хранимые процедуры на языке SQL. Это значительно упрощает этап отладки программы и поиска возможных ошибок.
Интересные новшества введены и в текстовый редактор Microsoft Visual C++. Теперь он имеет возможность более полно работать с текстами на языке SQL, выделяя цветом ключевые слова этого языка.
Многооконный графический редактор
Доработаем приложение Multi так, чтобы оно обладало возможностями приложения Single, описанного в томе 24 серии “Библиотека системного программиста”. Приложение Single представляет собой простейший графический редактор, в котором можно рисовать изображения, содержащие маленькие квадраты, а также сохранять эти рисунки в файлах на диске.
Добавьте в определение класса CMultiDoc новый элемент pointFigCenter, который будет хранить графический документ. Как и в приложении Single, этот элемент сделан на основе шаблона CArray. Однако вместо разработанного нами класса CFigure, здесь мы используем стандартный класс CPoint, входящий в состав MFC. Тип фигуры запоминать не надо, так как приложение Multi будет рисовать фигуры только одного типа:
class CMultiDoc : public CDocument
{
// Attributes
public:
CArray<CPoint, CPoint&> pointFigCenter;
Шаблоны классов CArray, CMap и CList определены во включаемом файле afxtempl.h. Так как мы используем класс CArray, добавьте файл afxtempl.h в конце включаемого файла stdafx.h:
#include <afxtempl.h>
Добавьте обработчик сообщения от левой кнопки мыши. Для этого лучше всего воспользоваться средствами MFC ClassWizard:
//////////////////////////////////////////////////////////////
// CMultiView message handlers
void CMultiView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO:
// Получаем указатель на документ (объект класса CSingleDoc)
CMultiDoc* pDoc = GetDocument();
// Проверяем указатель pDoc
ASSERT_VALID(pDoc);
// Отображаем на экране квадрат
CClientDC dc(this);
dc.Rectangle(
point.x-10, point.y-10, point.x+10, point.y+10);
// Добавляем к массиву, определяющему документ, новый
// элемент
pDoc->pointFigCenter.Add(point);
// Устанавливаем флаг изменения документа
pDoc->SetModifiedFlag();
// Вызываем метод OnLButtonDown базового класса CView
CView::OnLButtonDown(nFlags, point);
}
Обработчик этого сообщения рисует квадрат. Для отображения квадрата используется метод Rectangle. Первые два параметра этого метода определяют расположение левого верхнего угла параллелепипеда. Третий и четвертый параметры задают размеры по горизонтали и вертикали.
Затем добавляем к документу новый элемент, определяющий координаты верхнего левого угла квадрата. В данном случае графический документ приложения представляется массивом pointFigCenter, содержащим объекты класса CPoint.
Так как метод OnLButtonDown изменяет документ, устанавливаем флаг модификации документа, для чего вызываем метод SetModifiedFlag. Затем вызываем метод OnLButtonDown базового класса CView. На этом обработка сообщения завершается.
Приложение должно отображать документ, когда в окно просмотра поступает сообщение WM_PAINT. Для этого следует изменить метод OnDraw окна просмотра документа. MFC AppWizard определяет шаблон этого метода, вам остается только “наполнить” готовый шаблон.
Метод OnDraw должен уметь отображать документ в любой момент времени. Так как документ записан в массиве pointFigCenter класса документа, сначала надо определить указатель на документ, а потом последовательно отобразить на экране все его элементы:
//////////////////////////////////////////////////////////////
// CMultiView drawing
void CMultiView::OnDraw(CDC* pDC)
{
CMultiDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
int i;
for (i=0; i<pDoc->pointFigCenter.GetSize(); i++)
pDC->Rectangle(
pDoc->pointFigCenter[i].x-10,
pDoc->pointFigCenter[i].y-10,
pDoc->pointFigCenter[i].x+10,
pDoc->pointFigCenter[i].y+10
);
}
Переопределите метод DeleteContents класса CMultiDoc так, чтобы он удалял содержимое документа. Для этого достаточно удалить все элементы массива pointFigCenter, воспользовавшись методом RemoveAll класса CArray. После очистки документа необходимо вызвать метод DeleteContents базового класса CDocument.
Чтобы вставить в класс CMultiDoc метод DeleteContents используйте MFC ClassWizard, а затем модифицируйте его в соответствии со следующим фрагментом кода:
//////////////////////////////////////////////////////////////
// CMultiDoc commands
void CMultiDoc::DeleteContents()
{
// Очищаем документ, удаляя все элементы массива arrayFig.
pointFigCenter.RemoveAll( );
// Вызываем метод DeleteContents базового класса CDocument
CDocument::DeleteContents();
}
Теперь, когда документ создан и приложение умеет отображать его на экране, остается доработать приложение, чтобы оно могло сохранять документ в файле на диске и загружать уже существующие документы из файлов. Для этого переопределите метод Serialize класса документа. Шаблон для этого метода уже определен в приложении:
//////////////////////////////////////////////////////////////
// CMultiDoc serialization
void CMultiDoc::Serialize(CArchive& ar)
{
pointFigCenter.Serialize(ar);
}
Постройте измененное приложение и запустите полученный выполнимый файл. У вас получился настоящий многооконный графический редактор. Вы можете одновременно открыть несколько окон с документами. Каждый документ можно сохранить в отдельном файле на диске и загрузить при следующем запуске приложения.
Многооконный интерфейс
Приложение с однооконным интерфейсом не всегда может полностью удовлетворять потребностям пользователя. Если нужно одновременно работать с несколькими документами, вы, конечно, можете одновременно запустить несколько копий одного приложения, но гораздо удобнее использовать приложения с многооконным интерфейсом.
В таких приложениях вы одновременно можете открыть несколько документов. Каждому документу будет отведено собственное окно просмотра, но тем не менее все окна просмотра документов будут расположены внутри главного окна приложения, будут иметь общее меню, а также панели управления и состояния.
В этом разделе мы рассмотрим приложение Multi с многооконным интерфейсом, созданное с использованием средств MFC AppWizard. Сначала мы создадим простое приложение, а затем покажем, как его можно изменить, добавив возможности создания новых документов, рисования в окне и сохранения изменений в файле на диске.
Далее мы усовершенствуем наше приложение так, что оно сможет работать с документами двух типов - графическими и текстовыми.
В ходе своих объяснений мы иногда будем ссылаться на однооконное приложение Single, также созданное с использованием средств MFC AppWizard. Приложение Single мы рассматривали в 24 томе “Библиотеки системного программиста”. Если у вас нет под рукой 24 тома, вы можете быстро создать приложение Single, воспользовавшись MFC AppWizard.
Национальные ресурсы
Обратите внимание, что все ресурсы, представленные на странице RecourceView в окне проекта Project Workspace, английские. К сожалению, MFC AppWizard из доступных нам версий Microsoft Visual C++ не позволяет выбрать для создаваемого приложения русские ресурсы (язык для ресурсов выбирается в первой панели MFC AppWizard - Step 1, во время определения свойств приложения). Поэтому для приложения Multi и всех других приложений, созданных с помощью MFC AppWizard, мы выбрали английский язык.
Если вы в Control Panel с помощью приложения Regional Settings выбрали русский язык, то в некоторых случаях ClassWizard может работать неправильно. Например, если вы добавите к английской диалоговой панели новые органы управления, то ClassWizard не позволит автоматически привязать к ним переменные. Возникнут также сложности при использовании русского текста в строковых ресурсах, помеченных как английские. Чтобы избежать этих проблем, измените язык, используемый для ресурсов. Для этого достаточно в окне Project Workspace щелкнуть по идентификатору ресурса правой кнопкой мыши и выбрать из открывшегося контекстного меню строку Properties. На экране появится диалоговая панель со свойствами выбранного ресурса. Измените в ней язык ресурса, выбрав из списка Language строку Russian.
Недокументированные возможности класса 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 (см. раздел “Обработка командных сообщений”).
Новая кнопка в панели управления
Чтобы добавить в панели управления новую кнопку, переместите указатель мыши на крайне правую кнопку в панели управления, отображаемой в верхней части окна редактора ресурсов, и нажмите на левую кнопку мыши. Теперь вы можете нарисовать изображение, которое будет отображаться на новой кнопке.
Вместе с Microsoft Visual C++ поставляются несколько изображений кнопок панелей управления, которые можно использовать в разрабатываемых приложениях. Откройте файл ресурсов Common.res, записанный на компакт диске Microsoft Visual C++, и просмотрите записанные в нем ресурсы типа toolbar. Если вы обнаружите подходящие вам изображение, скопируйте его в обменный буфер Windows clipboard и вставьте в редактируемую панель управления. Для более полного описания файла Common.res обратитесь к разделу “Ресурсы Microsoft”.
Введите идентификатор новой кнопки панели управления. Для этого, выполните двойной щелчок по изображению этой кнопки в верхней части окна редактирования. В поле ID, открывшейся диалоговой панели Toolbar Button Properties, введите идентификатор ID_MY_BUTTON (рис. 3.8).
Теперь вы можете построить проект и запустить приложение. В панели управления появится новая кнопка, но она будет иметь серый цвет и будет заблокирована. Такая блокировка выполняется автоматически, если кнопка не имеет соответствующего обработчика сообщений.
Когда вы разрабатываете в редакторе ресурсов меню или диалоговую панель, то достаточно нажать правую кнопку мыши и откроется временное меню из которого можно запустить ClassWizard. В окне редактора панелей управления toolbar правая кнопка не работает, точнее она задействована для других целей.
Чтобы воспользоваться ClassWizard, сначала надо выбрать кнопку, к которой вы желаете привязать код, а затем нажать кнопку ClassWizard из панели Standard. ClassWizard откроет страницу Message Map и сразу предложит создать методы для выбранной кнопки (рис. 3.10).
Рис. 3.10. Диалоговая панель ClassWizard
По умолчанию, в списке Object IDs будет отображаться идентификатор кнопки, выбранной в редакторе панели управления - ID_MY_BUTTON. В списке Class name выбран класс CMainFrame - класс главного окна приложения. Вы можете выбрать и любой другой класс приложения, если желаете чтобы он обрабатывал команды от данной кнопки.
Теперь выберите из списка Messages идентификатор сообщения, подлежащего обработке. Вам доступны два варианта - COMMAND и UPDATE_COMMAND_UIё.
Выберите из списка Messages идентификатор COMMAND и нажмите кнопку Add Function. ClassWizard добавит к таблице сообщений класса CMainFrame новую макрокоманду для обработки команды от кнопки и запросит имя метода для обработки этой команды. По умолчанию будет предложено имя OnMyButton. Вы можете согласиться с предложением и нажать кнопку OK. ClassWizard добавит к классу CMainFrame метод OnMyButton.
Чтобы сразу перейти к редактированию данного метода, достаточно нажать на кнопку Edit Code. В окне редактирования появится файл с исходными текстами методов класса CMainFrame, а курсор будет установлен на метод OnMyButton:
//////////////////////////////////////////////////////////////
// Метод OnMyButton класса CMainFrame
void CMainFrame::OnMyButton()
{
// TODO: Здесь вы можете добавить собственный
// программный код
}
Как видите, метод OnMyButton не имеет параметров. Одно то, что он вызван, служит сигналом нажатия на кнопку ID_MY_BUTTON. Добавьте после комментария TODO код, который вы желаете выполнять по нажатию кнопки. Для нашего первого тестового примера достаточно добавить вызов всего одного метода MessageBox или функции AfxMessageBox:
//////////////////////////////////////////////////////////////
// Метод OnMyButton класса CMainFrame
void CMainFrame::OnMyButton()
{
// TODO: Здесь вы можете добавить собственный
// программный код
MessageBox(“Button is pressed”);
}
Постройте проект и запустите полученное приложение. Теперь, когда вы добавили обработчик для команд от кнопки с идентификатором ID_MY_BUTTON, она отображается в нормальном виде и вы можете на нее нажать.
Когда вы нажимаете на кнопку ID_MY_BUTTON, вызывается метод обработчик OnMyButton из класса CMainFrame. Он отображает на экране сообщение Button is pressed.
Новые версии Visual C++
За короткий промежуток времени, прошедший с момента выхода нашей первой книги, посвященной MFC, Microsoft выпустила еще две версии Visual C++. В них делается основной упор на создание приложений для работы с базами данных и глобальной сетью Internet.
Обнаруженные опечатки
Во время подготовки этой книги мы обнаружили несколько опечаток в томе 24 из серии “Библиотека системного программиста”, посвященном библиотеке MFC. Мы приносим вам свои извенения и недеемся, что они не ввели вас в заблуждение. На дискетах, которые вы можете приобрести вместе с книгой, все перечисленные ошибки исправлены.
На странице 17 метод ConvertString, объявленный как int, неверно определен как void. Этот метод должен возвращать значение типа int.
На странице 21 метод GetPi, объявлен как static void. На самом деле метод GetPi возвращает числовое значение и должен быть объявлен как static float.
На странице 22, в определении метода SetTitle, следует указать для переменной title имя соответствующего класса - CWindow::title.
На странице 32 следует взять текстовые строки, вводимые на экран, и символы \n в двойные кавычки. Следует также исправить ошибку в определении указателей ptrRectObject и ptrFigObject. Символ * должен быть расположен перед именами этих переменных. На странице 33 предпоследняя строка, выводимая на экран программой, должна выглядеть, не как Figure PrintName, а как Rectangle PrintName.
На странице 106, в конструкторе класса CMyDialog, в качестве параметра конструктора класса CDialog, должен передаваться не идентификатор CMyDialog::IDD, а имя шаблона диалоговой панели DIALOGPANEL. Правильный конструктор класса CMyDialog, представлен на странице 116.
На рисунках 2.3, 2.4 и 2.5, представляющих деревья наследования классов CWnd, CView и CDialog, пропущен базовый класс CCmdTarget. Правильный порядок наследования следующий: CWnd <- CCmdTarget <- CObject. Правильный порядок наследования классов также представлен на рисунке 2.2.
Обработка командных сообщений
Процесс обработки командных сообщений значительно отличается от обработки других сообщений. Обычные сообщения обрабатываются тем объектом, которому они поступили. Если таблица сообщений класса объекта не содержит обработчика сообщения, будут просмотрены таблицы сообщений его базовых классов. В том случае, если ни один из базовых классов также не содержит обработчик сообщения, выполняется обработка сообщения по умолчанию.
Судьба командных сообщений гораздо сложнее. Командное сообщение, переданное для обработки объекту приложения, может последовательно передаваться другим объектам приложения. Один из объектов, класс (или базовый класс) которого содержит обработчик этого сообщения, выполняет его обработку. Так, например, командное сообщение, переданное главному окну приложения, в конечном счете может быть обработано активным окном просмотра.
Существует стандартная последовательность объектов приложения, которым передаются командные сообщения. Каждый объект в этой последовательности может обработать командное сообщение, если в его таблице сообщений или таблице сообщений базовых классов есть соответствующая макрокоманда. Необработанные сообщения передаются дальше, другим объектам приложения.
Объекты различных классов обрабатывают командные сообщения по-разному. Например, объекты, представляющие главное окно приложения, сначала предоставляют возможность обработать полученное сообщение другим объектам, в том числе активному окну просмотра и соответствующему ему документу. Только если сообщение остается необработанным, просматривается таблица сообщений класса главного окна приложения. Если и здесь сообщение не обрабатывается, оно направляется другим объектам приложения.
Подавляющее большинство приложений, созданных на основе MFC, использует ряд стандартных командных сообщений, как правило соответствующих элементам меню или кнопкам панели управления. К ним относятся командные сообщения для завершения работы приложения, создания нового документа, открытия документа, записанного на диске, сохранения документа на диске, вызова справочной системы, управления текстовым редактором и т. д. За каждым таким командным сообщением зарезервирован отдельный идентификатор.
MFC обеспечивает различный уровень обработки стандартных командных сообщений, начиная от простого резервирования идентификатора и кончая полной его обработкой. Информацию об использовании стандартных командных сообщений вы можете получить в документации Microsoft Visual C++. Мы также рекомендуем вам изучить реализацию обработчиков стандартных командных сообщений непосредственно в исходных текстах библиотеки MFC.
В некоторых случаях вам может понадобиться изменить порядок, в котором сообщения передаются для обработки объектам приложения. В этом случае вы должны переопределить виртуальный методом OnCmdMsg. Этот метод первоначально определен в классе CCmdTarget и переопределен в классах CView и CDocument.
Ниже описаны последовательности обработки командных сообщений объектами различных классов.