Microsoft Visual C++ и MFC. Программирование для Win95 и WinNT

         

Базы данных


Расширены возможности работы с базами данных. Внесены изменения и дополнения в классы, взаимодействующие с базами данных через ODBC, в том числе модифицированы классы CRecordset и CDatabase. Добавлены новые компоненты к Component Gallery, которые можно использовать для связи с базами данных.



Базы данных и библиотека MFC


Сегодня без преувеличения можно сказать, что основной областью применения компьютеров стало хранение и обработка различной информации. Для этого предназначено большое количество различных систем управления базами данных (СУБД).

Такие системы позволяют хранить большие объемы данных (десятки и сотни тысяч записей) и обеспечивать быстрый поиск необходимой информации.

Диапазон применения СУБД огромен. СУБД используются везде, начиная от небольших домашних баз данных, содержащих картотеку домашней библиотеки книг, и кончая распределенными базами данных, объединяющих десятки банков, офисов, магазинов и хранящих сведения о клиентах, товарах, производителях.

До недавнего времени на рынке персональных компьютеров превалировали базы данных для операционной системы MS-DOS. Среди них наиболее распространены Clipper, Clarion, Dbase, FoxPro 2.0 и некоторые другие.

С развитием операционной системы Windows практически все крупные производители программного обеспечения выпустили собственные системы управления базами данных для этой операционной системы. Так, Microsoft производит и распространяет две различные СУБД примерно одного класса - FoxPro for Windows и Access, Borland выпускает Object Vision и Paradox for Windows. Даже фирмы, производящие СУБД для больших и малых компьютеров, выпустили версии своих систем для операционной системы Windows.

В этой книге рассматривается интерфейс ODBC (Open Database Connectivity), разработанный Microsoft. Этот интерфейс позволяет приложениям Windows получить доступ к данным различных систем управления базами данных, используя запросы на языке SQL. При этом можно получить доступ к данным любой СУБД, для которой существует ODBC драйвер. Так, например, в состав дистрибутива Visual C++ входят ODBC драйверы для баз данных в формате Access, Btrieve, dBase, FoxPro, Excel, Paradox, а также для обычных текстовых файлов. Кроме того, поставляются ODBC драйверы и для удаленных СУБД - SQL Server и Oracle.

Библиотека классов MFC, поставляемая в составе Visual C++ содержит классы, предназначенные для упрощения взаимодействия с ODBC драйверами. Мы кратко расскажем про эти классы и расскажем как использовать систему автоматизированной разработки приложений AppWizard для создания приложений, поддерживающих работу с базами данных.



Component Gallery и контекстное меню


Новые операционные системы Windows 95 и Windows NT версии 4.0 и приложения, разработанные для них, значительно шире используют правую кнопку мыши, чем ранние версии Windows. Обычно при нажатии правой кнопки мыши на экране появляется временное меню, внешний вид которого зависит от выбранного объекта.

Современные приложения используют правую клавишу мыши для вывода контекстного меню. В диалоговой панели Component Gallery расположен компонент Pop-up Menu. Он позволяет подключить контекстное меню к любому окну приложения.

Если вы желаете подключить контекстное меню к вашему приложению, выберите в диалоговой Component Gallery панели компонент Pop-up Menu и нажмите кнопку Insert. На экране появится диалоговая панель Pop-up Menu. В списке Add pop-up menu to перечислены классы проекта, представляющие окна и диалоговые панели. К одному из них вы можете добавить контекстное меню. По умолчанию к проекту добавляется новое меню, состоящее из трех строк, которому присваивается идентификатор, состоящий из префикса CG_IDR_POPUP_, названия приложения и части названия класса окна, к которому добавлено меню.

Далее мы опишем добавление компонента Pop-up Menu к приложению Multi, рассмотренному в разделе “Приложение Multi”.

Загрузите в Microsoft Visual C++ проект Multi, откройте диалоговую панель Component Gallery, выберите компонент Pop-up Menu и нажмите кнопку Insert. На экране появится диалоговая панель Pop-up Menu (рис. 3.5). Выберите из списка Add pop-up menu to класс CMultiView.

По умолчанию к проекту добавляется новое меню, состоящее из трех строк, которому присваивается идентификатор CG_IDR_POPUP_MULTI_VIEW.



Рис. 3.5. Диалоговая панель Pop-up Menu

Название идентификатора контекстного меню отображается в поле Menu resource ID диалоговой панели Pop-up Menu. Вы можете заменить его по своему усмотрению.

Нажмите кнопку OK. Диалоговая панель Pop-up Menu закроется. В исходных текстах приложения будут выполнены все необходимые изменения, а к ресурсам добавиться новое меню с идентификатором CG_IDR_POPUP_MULTI_VIEW.


Редактор ресурсов Microsoft Visual C++ позволяет изменять шаблон контекстного меню по вашему усмотрению. Из него можно удалить строки, добавленные Component Gallery по умолчанию, и вставить строки нужные вам.

Когда вы построите проект и запустите приложение, то при нажатии на правую кнопку мыши будет открываться контекстное меню окна над которым расположен указатель мыши.



Рис. 3.6. Контекстное меню, которое использует компонент Pop-up Menu

В файл ресурсов будет добавлено определение контекстного меню CG_IDR_POPUP_MULTI_VIEW. Как видите, оно не отличается от меню, которые вы создавали или использовали ранее, за исключением того, что соответствующее меню верхнего уровня обозначено строкой _POPUP_ (рис. 3.6). Эта строка не будет отображаться в контекстном меню.

Если в приложении имеется несколько окон, то вы можете добавить к каждому окну свое контекстное меню. Для этого вставьте в проект компонент Pop-up Menu несколько раз, указывая в поле Add pop-up menu to различные классы окон. Конечно, каждое вставленное в проект меню может состоять из различного набора строк.

Например, если у вас многооконное приложение, то вы можете вставить компонент Pop-up Menu для главного окна приложения и для окна просмотра. Тогда если вы нажмете правую кнопку мыши в то время, когда указатель мыши находится в окне просмотра, то отображается одно контекстное меню, а если вы нажмете правую кнопку мыши когда ее указатель расположен вне окна просмотра - отображается другое контекстное меню.


Диалоговая панель


В ресурсах приложения определена диалоговая панель с идентификатором IDD_ABOUTBOX. Она содержит краткую информацию о приложении и отображается на экране, когда пользователь выбирает из меню Help строку About Multi:

//////////////////////////////////////////////////////////////

// Диалоговая панель

IDD_ABOUTBOX DIALOG DISCARDABLE  0, 0, 217, 55

CAPTION "About Multi"

STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU

FONT 8, "MS Sans Serif"

BEGIN

   ICON          IDR_MAINFRAME,IDC_STATIC,11,17,20,20

   LTEXT         "Multi Version 1.0",IDC_STATIC,40,10,119,8,

                  SS_NOPREFIX

   LTEXT         "Copyright \251 1996",IDC_STATIC,40,25,119,8

   DEFPUSHBUTTON "OK",IDOK,178,7,32,14,WS_GROUP

END


Диалоговые панели представляются объектами классов, наследованных от базового класса СDialog. Если командное сообщение, поступившее объекту диалоговой панели, не может быть обработано, оно передается его родительскому окну.

Если родительское окно диалоговой панели также не может обработать командное сообщение, оно передается главному объекту приложения.



Диалоговая панель управления


В том случае, если в панели управления приложения надо разместить много разнообразных органов управления, то значительно удобнее создать его на основе другого класса, имеющего название CDialogBar:

CDialogBar <- CControlBar <- CWnd <- CCmdTarget <- CObject

Этот класс, также как класс CToolBar, наследован от базового класса CControlBar. Класс CDialogBar позволяет создать диалоговую панель управления на основе шаблона диалоговой панели. В отличии от обычной диалоговой панели, диалоговая панель управления, созданная на основе класса CDialogBar, имеет все свойства панели управления. Она может быть присоединена к одной из границ окна или может отображаться в отдельном мини-окне.

Приложение может иметь несколько панелей управления, созданных на основе классов CToolBar и CDialogBar.



Диалоговая панель управления и MFC AppWizard


Если вам надо добавить панель управления к приложению, созданному с использованием средств MFC AppWizard, вы должны выполнить точно такие же действия, какие были нами описаны в предыдущих разделах. Сначала надо создать шаблон диалоговой панели, затем добавить к классу окна, в котором будет отображаться диалоговая панель управления, элемент класса CDialogBar, и наконец, создать диалоговую панель управления, вызвав соответствующий метод Create.

Наибольший интерес представляет использование ClassWizard для добавления обработчиков сообщений от диалоговой панели управления. Откройте в редакторе ресурсов шаблон диалоговой панели управления и запустите ClassWizard.

ClassWizard обнаружит новый ресурс и предложит создать или выбрать для него управляющий класс (рис. 3.20). Сообщения от диалоговой панели управления передаются для обработки в ее родительское окно. Поэтому в качестве управляющего класса надо выбрать класс этого окна. Так как в большинстве случаев в качестве родительского окна для панелей управления, в том числе и для диалоговой панели управления, выступает главное окно приложения, надо выбрать класс CMainFrame.

Рис. 3.20. Диалоговая панель Adding a Class

Переведите переключатель диалоговой панели Adding a Class в положение Select an existing class и нажмите на кнопку OK. На экране появится диалоговая панель Select Class, содержащая список классов, определенных в приложении (рис. 3.21).

Рис. 3.21. Диалоговая панель Select Class

Выберите из списка Class list класс главного окна приложения CMainFrame и нажмите на кнопку Select. ClassWizard сообщит о том, что выбранный класс CMainFrame не относится к классам, которые предназначены для управления диалоговыми панелями (рис. 3.22). Для продолжения нажмите на кнопку Yes.

Рис. 3.22. Предупреждение

Теперь на экране появится окно ClassWizard, в котором вы можете назначить обработчики сообщений от диалоговой панели управления, также просто как для меню или панели управления toolbar.



Для самостоятельного изучения


Классы библиотеки MFC, описанные нами, содержат большое количество различных методов, оставшихся неохваченными данной книгой. Мы не имеем возможности уделить им больше времени и места, поэтому предлагаем вам самостоятельно изучить остальные методы этих классов.

Для этого вы можете использовать документацию, поставляемую в электронном виде вместе с Microsoft Visual C++ или обратиться к библиотеке Microsoft Development Library. Библиотека Microsoft Development Library является незаменимым средством для разработчика приложений Microsoft Visual C++ и других пакетов Microsoft. В нее включена документация, книги, отдельные статьи, а также большое количество исходных текстов всевозможных приложений.

Наиболее свежую информацию вы можете получить через глобальную сеть Internet. В первую очередь обратите свое внимание на WWW и FTP сервера Microsoft, содержащие сведения обо всех продуктах этой компании, включая Microsoft Visual C++. На сервере Microsoft вы сможете найти ссылки на другие сервера сети, также посвященные проблемам программирования в среде Microsoft Visual C++ с использованием библиотеки классов MFC.



Добавление компонент Microsoft


Для добавления к вашему проекту новой компоненты, выберите соответствующую пиктограмму и нажмите кнопку Insert. Дальнейший процесс вставки компонента зависит от него самого. Наиболее общий сценарий выглядит следующим образом. Когда вы нажмете кнопку Insert, у вас запрашивается различная дополнительная информация о том, что вы желаете получить. Это могут быть какие-либо характеристики компонента, названия классов, файлов и т. д. Когда вы введете всю необходимую информацию, начнется модификация проекта. На этом этапе в проект могут быть добавлены новые ресурсы и классы, а в исходные тексты приложения могут быть автоматически внесены исправления.

Сейчас мы расскажем об использовании компонент Microsoft на примере компоненты Splash Screen. Далее, когда мы будем рассказывать о меню, панелях управления и панелях состояния мы также будем делать ссылки на Component Gallry.



Добавление компонентов в проект


Процедура использования Component Gallery для добавления разрабатываемому приложению новых возможностей предельно проста. Выберите из меню Insert строку Component. На экране появится диалоговая панель Component Gallery (рис. 2.1).

Она состоит из нескольких страниц, в которых отображаются различные пиктограммы. Именно эти пиктограммы и представляют компоненты, которые вы можете добавить к вашему приложению.

Количество страниц Component Gallery и набор компонент зависит от версии Visual C++ и постоянно расширяется. В Component Gallery можно включить компоненты, разработанные другими фирмами, например Blue Sky Software, VideoSoft. Более того, вы можете включить в Component Gallery собственные компоненты, разработанные вами. В простейшем случае, в качестве таких компонент могут выступать классы приложений, которые вы создали.

Рис. 2.1. Диалоговая панель Component Gallery



Документ


Также как и окно просмотра, объект, представляющий документ, сначала проверяет свою таблицу сообщений. Только в том, случае если в классе документа отсутствует обработчик командного сообщения, оно передается для обработки шаблону данного документа.



Дополнительные панели управления


Приложения, создаваемые с использованием средств MFC AppWizard, имеют только одну панель управления. Во многих случаях этого явно недостаточно. Сложные приложения, наподобие офисных приложений Microsoft и графических редакторов, имеют несколько таких панелей.



Дополнительные возможности панели состояния


Если во время работы приложения выполняется какой-либо длительный процесс, например загрузка или сохранение документа, тогда в панели состояния можно вывести линейный индикатор progress bar. С ее помощью вы легко сможете показать ход данного процесса.

Многие офисные приложения, и сама среда Microsoft Visual C++, использует панель состояния подобным образом. Так, например, когда вы сохраняете документ в текстовом процессоре Microsoft Word, то в панели состояния отображается линейный индикатор progress bar, отражающий процесс сохранения документа.

Методика размещения полосы progress bar на панели состояния достаточно проста. В тот момент, когда потребуется вывести полосу progress bar, просто создайте ее, указав в качестве родительского окна панель состояния. Координаты линейного индикатора progress bar желательно выбрать таким образом, чтобы он отображался на месте одного из индикаторов. Предварительно вы можете убрать рамку с этого индикатора и заблокировать его так, чтобы в нем не отображался текст.



Дополнительные возможности панели управления


Панель управления, созданная на основе класса CToolBar, состоит из одних только кнопок и разделителей. Стандартные средства для отображения в ней других органов управления, таких как поле редактирование или список, отсутствуют.

Однако, вы все же можете вывести в панели toolbar другие органы управления. Так как панель управления является ни чем иным как дочерним окном, то вы можете самостоятельно разместить в нем другие органы управления.

Для этого предлагается использовать следующий метод.

¨     В том месте панели управления toolbar, где вы желаете разместить дополнительный орган управления, вставьте разделитель

¨     Сразу после создания панели управления, измените размер разделителя вместо которого надо вставить другой орган управления. Присвойте ему другой идентификатор

¨     Создаем на месте разделителя нужный вам орган управления. Указываем, для него в качестве родительского окна - идентификатор панели управления

В состав класса CToolBar входит метод SetButtonInfo. Этот метод позволяет изменить внешний вид панели управления. Используя метод SetButtonInfo, можно изменить идентификатор, изображение, режим работы и размер разделителей кнопок панели управления:

void

SetButtonInfo(

   int nIndex,

   UINT nID,

   UINT nStyle,

   int iImage

);

Параметр nIndex метода SetButtonInfo определяет индекс кнопки или разделителя. Остальные параметры задают новые характеристики для этой кнопки.

Параметр nID позволяет задать новый идентификатор кнопки или разделителя.

Параметр nStyle определяет режимы работы данной кнопки и может содержать комбинацию флагов, которые уже были нами представлены при описании метода SetButtonStyle класса CToolBar.

Последний параметр метода позволяет изменить изображение кнопки. Новое изображение берется из ресурса панели управления. При этом используется изображение с порядковым номером, заданным параметром iImage.

Если вы вызвали метод SetButtonInfo и указали ему через параметр nIndex индекс разделителя, то назначение параметра iImage изменяется. В этом случае параметр iImage будет определять новую ширину разделителя.


Перед тем как изменять характеристики кнопок панели управления, вы можете воспользоваться методом GetButtonStyle класса CToolBar, чтобы узнать текущие характеристики кнопки:

void

GetButtonInfo(

   int nIndex,

   UINT& nID,

   UINT& nStyle,

   int& iImage

) const;

В параметре nIndex надо указать индекс кнопки, о которой надо получить информацию. Через остальные три параметра методу GetButtonInfo передаются ссылки на переменные, в которые будут записаны характеристики кнопок.

Через параметр nID вы получите идентификатор кнопки, через параметр nStyle - режим ее работы, а через параметр iImage - индекс изображения кнопки в ресурсе панели управления.

Если метод GetButtonInfo вызывается для разделителя, то через параметр iImage вы получите не индекс изображения, а ширину разделителя в пикселах.

Когда вы создаете на панели управления дополнительный орган управления, например поле редактирования, вы должны указать координаты прямоугольной области которую он будет занимать. Для определения этих координат следует воспользоваться методом GetItemRect класса CToolBar:

virtual void GetItemRect(int nIndex, LPRECT lpRect);

Вызов метода GetItemRect заполняет структуру lpRect координатами прямоугольной области, занимаемой кнопкой или разделителем, с индексом nIndex.


Доводка приложения


Взгляните на ресурсы приложения Dater. Для этого откройте страницу ResourceView в окне Project Workspace.

Обратите внимание на шаблон диалоговой панели IDD_DATER_FORM (рис. 5.10). Этот шаблон используется окном просмотра, созданным на основе класса CRecordView. Окно просмотра содержит в себе органы управления, определенные в шаблоне диалоговой панели.

Рис. 5.10. Шаблон диалоговой панели IDD_DATER_FORM

Сразу после того, как MFC AppWizard создаст проект, в этом шаблоне будет размещен одна только текстовая строка TODO: Place form controls on this dialog, предлагающая вам разместить на ней органы управления.

Удалите с шаблона эту строку, а затем создайте на ней четыре текстовых редактора, по одному для каждого поля таблицы базы данных Address Pad. Присвойте им идентификаторы IDC_NAME, IDC_ADDRESS, IDC_PHONE и IDC_PRIORITY. Около текстовых редакторов поместите краткие строки описания - Name, e-Mail, Phone и Priority. Сохраните изменения в файле ресурсов. Доработанный шаблон диалоговой панели представлен на рисунке 5.11.

Теперь вы можете выполнить наиболее интересную операцию в создании приложения Dater - привязать при помощи MFC ClassWizard к полям шаблона диалоговой панели IDD_DATER_FORM переменные, представляющие различные поля таблицы базы данных.

Рис. 5.11. Доработанный шаблон диалоговой панели IDD_DATER_FORM

Запустите MFC ClassWizard. В окне MFC ClassWizard выберите из списка ClassName имя класса окна просмотра - CDaterView и откройте страницу Member Variables. На этой странице вы увидите список идентификаторов полей редактирования шаблона диалоговой панели IDD_DATER_FORM.

Выбериете один из идентификаторов и нажмите на кнопку Add Variable. На экране появится диалоговая панель Add Member Variable (рис. 5.12). В этой панели вы должны определить переменную, которая будет отображаться в поле с данным идентификатором. В списке Category отображается категория органа управления к которому вы добавляете переменную. Для полей редактирования из этого списка будет выбрана строка Value. В списске Variable type отображается тип переменной, выбранной в поле Member variable name. Нажмите кнопку OK.




Рис. 5.12. Диалоговая панель Add Member Variable

В нашем случае список Member variable name содержит строки, представляющие различные поля записи таблицы базы данных Address Pad. Выбирая остальные идентификаторы шаблона диалоговой панели IDD_DATER_FORM поставьте им в соответствие поля базы данных, как это показано на рисунке 5.13.



Рис. 5.13. Диалоговая панель MFC ClassWizard

Если у вас возникли проблемы во время добавления переменных к полям диалоговых панелей (список идентификаторов в панели MFC ClassWizard пуст), возможно вам надо будет изменить язык для диалоговой панели IDD_DATER_FORM.

Так например, если ваш компьютер настроен на работу с русским языком, диалоговая панель IDD_DATER_FORM также должна быть русской. Чтобы поменять язык, вызовите панель свойств для диалоговой панели IDD_DATER_FORM и выберите из списка Language строку Russian (рис. 5.14). Дополнительные сведения о выборе языка смотрите в разделе “Национальные ресурсы”.



Рис. 5.14. Свойства диалоговой панели IDD_DATER_FORM

Откройте для редактирования метод GetDefaultSQL класса CDaterSet:

CString CDaterSet::GetDefaultSQL()

{

   return _T("[TextBase].[txt]");

}

MFC AppWizard не совсем правильно работает с текстовым драйвером и этот метод содержит ошибку. Вы должны убрать из него две лишние квадратные скобки. Исправленный метод будет выглядеть следующим образом:

CString CDaterSet::GetDefaultSQL()

{

   return _T("[TextBase.txt]");

}

Все! Теперь можно построить проект и запустить полученное приложение. На экране откроется главное окно приложения Dater (рис. 5.15). В окне просмотра отображаются поля базы данных Address Pad. Вы можете просмотреть все записи базы, используя меню Record и панель управления приложения.



Рис. 5.15. Приложение Dater


Форма панели управления


Панель управления может иметь постоянную форму, которую пользователь не может изменить, или может быть динамически изменяемой. В последнем случае пользователь может менять форму панели управления с помощью мыши.

Можно изменить форму панели управления или нет, определяется методом Create класса CToolBar. Если при создании панели управления был установлен флаг CBRS_SIZE_DYNAMIC ее форму можно менять, а если был установлен флаг CBRS_SIZE_FIXED - нельзя.

В состав класса CToolBar входит метод SetButtonStyle. Этот метод позволяет определить режим работы кнопок панели управления, сгруппировать несколько кнопок вместе:

void SetButtonStyle(

   int nIndex,

   UINT nStyle

);

Параметр nIndex выбирает индекс кнопки или разделителя в панели управления, а параметр nStyle позволяет установить новый режим работы для выбранной кнопки или разделителя. Индекс кнопки или разделителя соответствует ее порядковому номеру в панели управления.

В качестве параметра nStyle можно указать комбинацию из следующих флагов:

Флаг

Режим кнопки или разделителя

TBBS_BUTTON

Стандартная кнопка

TBBS_SEPARATOR

Разделитель

TBBS_CHECKBOX

Переключатель

TBBS_GROUP

С данной кнопки начинается группа кнопок

TBBS_CHECKGROUP

С данной кнопки начинается группа переключателей

TBBS_WRAPPED

Этот флаг позволяет создать панель управления, в которой кнопки расположены в несколько рядов. Установите этот флаг для самых последних кнопок в каждом ряду. Кнопка, следующая за кнопкой с установленным флагом TBBS_WRAPPED, отображается в новом ряду

¨     Заметим, что стиль TBBS_WRAPPED не описан в документации Microsoft Visual C++, но активно используется в примерах приложений и работает как положено

Перед тем, как изменить режим работы кнопки или указать группу кнопок, рекомендуется определить текущий режим кнопки. Для этого следует воспользоваться методом GetButtonStyle класса CToolBar:

UINT GetButtonStyle(int nIndex) const;

Метод возвращает комбинацию флагов, определяющих режим работы кнопки с индексом nIndex. Мы уже рассматривали эти флаги при описании метода SetButtonStyle класса CToolBar.

Вы можете определить индекс (порядковый номер) любой кнопки панели управления, если знаете ее идентификатор. Для этого предназначен метод CommandToIndex класса CToolBar. Он возвращает индекс кнопки, имеющей идентификатор nIDFind. Если вы укажите идентификатор несуществующей кнопки, тогда метод CommandToIndex возвращает значение -1:

int CommandToIndex(UINT nIDFind);

Обратную задачу выполняет метод GetItemID класса CToolBar. Этот метод возвращает идентификатор кнопки с индексом nIndex. Если в качестве параметра nIndex указать индекс разделителя, тогда метод GetItemID возвращает идентификатор ID_SEPARATOR:

UINT GetItemID(int nIndex) const;



Главное окно многооконного приложения


Большинство командных сообщений передаются главному окну приложения. Если приложение имеет многооконный интерфейс, то главное окно приложения представляет объект класса CMDIFrameWnd или класса, наследованного от базового класса CMDIFrameWnd.

Получив сообщение, главное окно приложения сначала предоставляет возможность обработать сообщение активному дочернему окну MDI. Окна MDI представляют собой объекты класса CMDIChildWnd или класса наследованного от него.

Только если окно MDI не может обработать сообщение, будет просмотрена таблица сообщений класса главного окна приложения. Следует сразу заметить, что в свою очередь, окно MDI передает сообщения другим объектам (см. ниже).

Если главное окно приложения не может обработать сообщение, оно передается объекту главного класса приложения. Напомним, что главный класс приложения наследуется от базового класса CWinApp и приложение имеет только один объект этого класса.



Главный класс приложения


Главный класс приложения CMultiApp управляет работой всего приложения. Методы этого класса выполняют инициализацию приложения, обработку цикла сообщений и вызываются при завершении приложения. Через окно Project Workspace можно просмотреть названия методов класса и загрузить их в текстовый редактор (рис. 1.8).

Рис. 1.8. Окно Project Workspace, класс CMultiApp

Класс CMultiApp определен в файле Multi.h следующим образом:

//////////////////////////////////////////////////////////////// Класс CMultiApp

class CMultiApp : public CWinApp

{

public:

   CMultiApp();

// Overrides

   //{{AFX_VIRTUAL(CMultiApp)

public:

   virtual BOOL InitInstance();

   //}}AFX_VIRTUAL

// Implementation

   //{{AFX_MSG(CMultiApp)

   afx_msg void OnAppAbout();

   //}}AFX_MSG

   // Класс CMultiApp может получать сообщения

   DECLARE_MESSAGE_MAP()

};

В приложении определен только один объект базового класса приложения theApp. Этот объект должен быть один вне зависимости от того, какой интерфейс имеет приложение - однооконный, многооконный или основанный на диалоговой панели:

CMultiApp theApp;



Главный класс приложения - CDaterApp


Класс CDaterApp приложения Dater не содержит в себе ничего особенного и практически не отличается от соответствующего класса однооконного приложения Single, созданного MFC AppWizard и не работающего с базами данных:

//////////////////////////////////////////////////////////////

// Класс CDaterApp

/

class CDaterApp : public CWinApp

{

public:

   CDaterApp();

// Overrides

   //{{AFX_VIRTUAL(CDaterApp)

   public:

   virtual BOOL InitInstance();

   //}}AFX_VIRTUAL

// Implementation

   //{{AFX_MSG(CDaterApp)

   afx_msg void OnAppAbout();

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};

Класс CDaterApp содержит конструктор, а также методы InitInstance и OnAppAbout.



Главный класс приложения CDlgBarApp


Главный класс приложения CDlgBarApp наследуется от базового класса CWinApp. Объект DlgBarApp класса CDlgBarApp объявлен как глобальный и создается сразу после запуска приложения.

В класс CDlgBarApp входит только метод InitInstance. Он создает главное окно приложения, представленное классом CDlgBarWindow, наследованным от класса CFrameWnd. Мы не станем подробно рассматривать этот метод, так как он фактически идентичен одноименному методу приложений Bar и MultiBar, представленных выше.



Главный класс приложения CMultiBarApp


Главный класс приложения CMultiBarApp наследуется от базового класса CWinApp. Объект MyMultiBarApp класса CMultiBarApp объявлен как глобальный и создается сразу после запуска приложения.

В класс CMultiBarApp входит только метод InitInstance. Он создает главное окно приложения, представленное классом CMultiBarWindow, наследованным от класса CFrameWnd.

В класс CMultiBarWindow входят три объекта - m_wndPlayerBar, m_wndStyleBar и m_wndExtendedBar, представляющие панели управления Player, Style и Extended:

class CMultiBarWindow : public CFrameWnd

{

// Определяем панели управления

protected:

   // Панель управления Player

   CToolBar       m_wndPlayerBar;

   // Панель управления Style

   CToolBar       m_wndStyleBar;

   // Панель управления Extended

   CExtendedBar   m_wndExtendedBar;

   // ...

}

Панели управления Player и Style представлены объектами класса CToolBar. Панель управления Extended представлена объектом m_wndExtendedBar класса CExtendedBar. Класс CExtendedBar определен в нашем приложении. Он наследуется от базового класса CToolBar и дополняет его двумя элементами m_edit и m_combo_box. Эти элементы представляют текстовый редактор и список combo-box, которые будут размещены на панели управления:

class CExtendedBar : public CToolBar

{

public:

   // Дополнительные органы управления панели Extended

   CEdit m_edit;          // текстовый редактор

   CComboBox m_combo_box; // список с текстовым редактором

};

В таблице сообщений класса CMultiBarWindow, находится макрокоманда ON_WM_CREATE. Поэтому в процессе создания главного окна приложения вызывается метод OnCreate. Мы используем метод OnCreate для создания сразу трех панелей управления. Рассмотрим метод OnCreate более подробно.



Главный класс приложения CMultiMenuApp


Главный класс приложения CMultiMenuApp наследуется от базового класса CWinApp. Объект MultiMenuApp класса CMultiMenuApp объявлен как глобальный и создается сразу после запуска приложения.

В класс CMultiMenuApp входит только метод InitInstance. Он создает главное окно приложения, представленное классом CMultiMenuWindow, наследованным от класса CFrameWnd.



Элементы данных класса CCmdUI


Помимо представленных методов, в состав класса входит и несколько элементов данных. Они позволяют определить идентификатор строки меню, кнопки панели управления или индикатора панели состояния, для которого вызван метод обработчик.

Метод

Описание

m_nID

Идентификатор объекта, для которого вызвано сообщение

m_nIndex

Индекс объекта, для которого вызвано сообщение

m_pMenu

Указатель на меню. Если команда обновления передана не от меню, m_pOther содержит значение NULL

m_pOther

Указатель на панель состояния или панель управления для объекта которой выполняется обновление. Если команда обновления передана от меню, m_pOther содержит значение NULL



Как хранится ресурс, описывающий панели управления


Каждый ресурс, представляющий панель управления в редакторе ресурсов Microsoft Visual C++, выступает как единое целое. Загрузив в редактор панель управления вы можете менять внешний вид кнопок, задавать их идентификаторы и строки описания, не открывая других ресурсов или дополнительных файлов.

Если вы просмотрите исходный текст файла ресурсов приложения, то обнаружите, что на самом деле ресурс панели управления состоит из двух, а если быть точнее, то из трех частей.

Первая часть описывает панель управления:

//////////////////////////////////////////////////////////////

// Панель управления toolbar

IDR_MAINFRAME TOOLBAR DISCARDABLE  16, 15

BEGIN

    BUTTON      ID_FILE_NEW

    BUTTON      ID_FILE_OPEN

    BUTTON      ID_FILE_SAVE

    SEPARATOR

    BUTTON      ID_EDIT_CUT

    BUTTON      ID_EDIT_COPY

    BUTTON      ID_EDIT_PASTE

    SEPARATOR

    BUTTON      ID_FILE_PRINT

    BUTTON      ID_APP_ABOUT

    BUTTON      ID_TOOL_EXIT

END

В нашем примере эта панель имеет идентификатор IDR_MAINFRAME. После идентификатора следует ключевое слово TOOLBAR, а затем дополнительные параметры, описывающие режим использования ресурса и два числа, определяющие размер кнопок панели.

Затем в блоке BEGIN - END идет описание каждой кнопки панели. После ключевого слова BUTTON, представляющего кнопку следует ее идентификатор. Между описаниями кнопок могут располагаться ключевые слова SEPARATOR.

В нашем маленьком примере присутствуют два таких слова. Они означают, что между кнопками, разделенными строкой SEPARATOR, увеличено расстояние. За счет увеличения расстояния между отдельными кнопками достигается эффект разделения кнопок панели управления на три отдельные группы. Это, в свою очередь, улучшает восприятие приложения и делает его более удобным для пользователя.

Как видите, в первой части ресурса панели управления отсутствуют сами изображения кнопок. Они располагаются отдельно и представляют вторую часть ресурса. Все кнопки представлены одним изображением bitmap, имеющим тот же идентификатор, что и соответствующий ресурс TOOLBAR:


//////////////////////////////////////////////////////////////

// Bitmap

IDR_MAINFRAME   BITMAP   MOVEABLE PURE   "res\\Toolbar.bmp"

Изображение кнопок нашей панели управления IDR_MAINFRAME хранится в файле Toolbar.bmp (рис. 3.9). Файл записан в каталоге RES основного каталога проекта. Все кнопки панели управления расположены последовательно, одна за другой. Порядок, в котором они расположены, соответствует порядку, в котором кнопки описаны в ресурсе TOOLBAR, и порядку в котором они будут отображаться на экране во время работы приложения.



Рис. 3.9. Файл Toolbar.bmp с изображением кнопок панели управления

Между отдельными изображениями кнопок отсутствуют промежутки, даже если в описании ресурса TOOLBAR присутствуют разделители SEPARATOR.

Когда вы подготавливаете ресурс toolbar в редакторе ресурсов, то для каждой кнопки вы можете ввести описывающую ее текстовую строку. Эти строки как раз и представляют третью, необязательную часть ресурса toolbar. Хранятся они в стоковых ресурсах приложения.

Соответствие строковых ресурсов кнопкам панели управления достигается за счет присвоения им одинаковых идентификаторов. Так, для нашего примера вы можете найти в файле ресурсов следующие текстовые ресурсы (мы привели только выборку из строковых ресурсов приложения):

STRINGTABLE DISCARDABLE

BEGIN

    ID_FILE_NEW    "Create a new document\nNew"

    ID_FILE_OPEN   "Open an existing document\nOpen"

    ID_FILE_SAVE   "Save the active document\nSave"

    ID_FILE_PRINT  "Print the active document\nPrint"

    ID_EDIT_COPY   "Copy the selection and put it on the

                    Clipboard\nCopy"

    ID_EDIT_CUT    "Cut the selection and put it on the

                    Clipboard\nCut"

    ID_EDIT_PASTE  "Insert Clipboard contents\nPaste"

    ID_APP_ABOUT   "Display program information, version

                   number and copyright\nAbout"

END

Надо сказать, что строки описания некоторых кнопок могут отсутствовать, или наоборот, использоваться еще и в других ресурсах, например, в описании ресурсов меню. Все кнопки стандартной панели управления, которая автоматически создается MFC AppWizard для однооконных и многооконных приложений, имеют соответствие в меню приложения.


Как работает приложение DialogBar


В приложении DialogBar определены всего только два класса - это главный класс приложения CDlgBarApp и класс главного окна приложения CDlgBarWindow. Как и во многих других приложениях, посвященных использованию панелей управления, главное окно приложения по сути является его единственным окном. Однако мы сохранили за ним это почетное название, чтобы внести однообразие в описание приложений, созданных с использованием MFC AppWizard и без него.



Как работает приложение MultiMenu


В приложении MultiMenu определены два класса - главный класс приложения CStateApp и класс главного окна приложения CStateWindow.



Как работает приложение Status


В приложении Status определены два класса - главный класс приложения CStateApp и класс главного окна приложения CStateWindow.



Как создать панель состояния


Процесс создания панели состояния во многом схож с процессом создания панелей управления.

Сначала надо создать объект для управления панелью состояния. Обычно для этого включают объект класса CStatusBar непосредственно в класс окна приложения, в котором будет размещена панель состояния.

Конструктор класса CStatusBar не имеет параметров и выглядит так:

CStatusBar();

В некоторых случаях, вместо использования класса CStatusBar, от него предварительно наследуют дополнительный класс. В этом случае, для создания панели состояния используют именно этот класс.

Следующим шагом является создание самой панели состояния. Панель состояния создается вызовом метода Create класса CStatusBar:

BOOL Create(

   CWnd* pParentWnd,

   DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_BOTTOM,

   UINT nID = AFX_IDW_STATUS_BAR

);

Через первый параметр метода pParentWnd вы должны указать окно, для которого создается панель состояния.

Второй параметр dwStyle позволяет задать характеристики панели состояния, в том числе ее расположение внутри окна. Панель состояния является дочерним окном, поэтому в параметре dwStyle надо указать атрибут WS_CHILD. Если вы не укажите атрибут WS_CHILD, ничего страшного тоже не случится - этот атрибут установится автоматически во время вызова метода Create. А вот атрибут WS_VISIBLE более важен. Если его опустить, то панель состояния хотя и будет создана, но на экране не появится.

Вы можете разместить панель состояния либо в верху, либо внизу окна. По умолчанию панель состояния размещается в нижней части окна (используется атрибут CBRS_BOTTOM). Чтобы панель состояния была размещена вверху окна, укажите в качестве параметра dwStyle атрибут CBRS_TOP. Если вы используете параметр dwStyle, надо обязательно указать либо атрибут CBRS_BOTTOM, либо атрибут CBRS_TOP.

Последний параметр метода nID определяет идентификатор дочернего окна панели состояния. По умолчанию используется идентификатор AFX_IDW_STATUS_BAR.

¨ Приложения, созданные MFC AppWizard, имеют меню View, содержащее строки Toolbar и Status bar. Строка Status bar с идентификатором ID_VIEW_STATUS_BAR позволяет закрывать и снова открывать панель состояния. Обработка стандартного командного сообщения ID_VIEW_STATUS_BAR выполняется методом OnUpdateControlBarMenu класса CFrameWnd. Метод OnUpdateControlBarMenu может управлять отображением панели управления только в том случае, если она имеет идентификатор AFX_IDW_STATUS_BAR. Более подробно о методе OnUpdateControlBarMenu можно прочитать в разделе “Недокументированные возможности класса CMainFrame”.


В случае успешного создания панели состояния метод Create возвращает ненулевое значение. Если в ходе создания панели состояния обнаружены ошибки, тогда метод Create возвращает нулевое значение.

После того как панель состояния создана, необходимо определить ее внешний вид. Для достижения этой цели вызывают метод SetIndicators и ему передают массив идентификаторов, представляющих индикаторы панели состояния. Каждый элемент панели состояния (индикатор) должен иметь отдельный идентификатор.

Метод SetIndicators загружает строковые ресурсы, соответствующие идентификаторам индикаторов, и размещает их на панели состояния:

BOOL SetIndicators(

   const UINT* lpIDArray,

   int nIDCount

);

Через параметр lpIDArray, методу SetIndicators, надо передать указатель на массив идентификаторов панели состояния. Общее количество индикаторов панели состояния, определенных в массиве lpIDArray, задается параметром nIDCount.

Обычно для определения количества элементов массива используют следующий код:

nIDCount = sizeof(indicators)/sizeof(UINT);

Переменная indicators представляет массив идентификаторов панели состояния.

В случае успешного завершения метод SetIndicators возвращает ненулевое значение. Если же будут обнаружены ошибки, тогда метод SetIndicators возвращает нулевое значение.

Когда индикаторы созданы, вы можете изменить некоторые их характеристики, воспользовавшись методом SetPaneInfo:

void

SetPaneInfo(

   int nIndex,

   UINT nID,

   UINT nStyle,

   int cxWidth

);

Параметр nIndex определяет порядковый номер индикатора в панели состояния или, другими словами, его индекс. Характеристики этого индикатора будут меняться.

Метод SetPaneInfo позволяет изменить расположение индикаторов на панели, или даже заменить существующий индикатор новым индикатором. Для этого можно указать новый идентификатор через параметр nID. Если вы не знаете идентификатор индикатора, тогда можете определить его с помощью метода GetItemID. Метод GetItemID возвращает идентификатор индикатора с индексом nIndex:



UINT GetItemID(int nIndex) const;

Обратная операция выполняется при помощи метода CommandToIndex. Метод CommandToIndex возвращает индекс индикатора, имеющего идентификатор nIDFind. Если идентификатор указан неверно, возвращается значение -1:

int CommandToIndex(UINT nIDFind) const;

После короткого отступления вернемся к рассказу о параметрах метода SetPaneInfo.

Внешний вид идентификатора, заданного параметрами nIndex и nID, определяется параметрами nStyle и cxWidth. В качестве nStyle можно указать один или несколько атрибутов, объединенных логической операцией ИЛИ.

Атрибут

Описание

SBPS_NOBORDERS

Убрать трехмерную рамку вокруг индикатора

SBPS_POPOUT

Обычная рамка вокруг индикатора создает впечатление, что индикатор расположен в углублении. Если указать атрибут SBPS_POPOUT, рамка изменяется таким образом, что индикатор будет располагается выше общего уровня панели состояния

SBPS_DISABLED

Если указать этот атрибут, то в индикаторе не будет отображаться текст из соответствующего строкового ресурса

SBPS_STRETCH

Один из индикаторов панели состояния может менять свой размер в зависимости от размера окна. Атрибут SBPS_STRETCH предназначен для выбора этого индикатора

SBPS_NORMAL

Стандартный индикатор

Параметр cxWidth определяет ширину индикатора. Когда вы создаете панель состояния и устанавливаете индикаторы, вызывая метод SetIndicators, размер индикаторов определяется автоматически исходя из ширины текста индикатора.

¨     Если первый элемент массива идентификаторов, переданного методу SetIndicators, содержит константу ID_SEPARATOR, то для первого индикатора панели состояния по умолчанию устанавливаются атрибуты SBPS_NOBORDERS и SBPS_STRETCH

Узнать текущие характеристики индикатора можно при помощи метода GetPaneInfo. Он позволяет определить идентификатор, стиль и ширину индикатора с индексом nIndex:

void

GetPaneInfo(

   int nIndex,

   UINT& nID,

   UINT& nStyle,

   int& cxWidth

) const;

Идентификатор записывается в переменную, ссылка на которую передается через параметр nID, набор атрибутов, определяющих внешний вид индикатора - в переменную nStyle, а ширина - в переменную cxWidth.

Если вам требуется определить или установить только стиль индикатора в панели управления, то вместо методов GetPaneInfo и SetPaneInfo лучше использовать два других метода класса CStatusBar - метод GetPaneStyle и метод SetPaneStyle.


Как создать панель управления во время работы приложения


Во всех примерах, которые мы привели выше, для создания панели управления мы вызывали метод Create класса CToolBar во время создания окна приложения. В принципе, панель управления можно создать и позже, когда окно уже отображается на экране.

Возьмите приложение Bar. Добавьте к нему меню Tools, состоящее из одной строки Show Bar. Определите метод OnShowBar, который будет вызываться для обработки команд от этой строки меню. Не забудьте вставить в таблицу сообщений класса окна соответствующую макрокоманду.

Перенесите код для создания панели управления из метода OnCreate в метод OnShowBar. Теперь панель управления будет создаваться только после того, как вы выберите из меню Tools строку Show Bar.

Постройте проект и запустите приложение. Вы заметите, что панель управления почему-то возникает не сразу после выбора строки Show Bar. Чтобы панель управления появилась, необходимо еще изменить размер окна приложения.

Оказывается, метод Create класса CToolBar устанавливает нулевой размер окна панели управления. Настоящий размер панели управления выбирается позже, в зависимости от ее характеристик, а также размеров и характеристик родительского окна.

Чтобы установить правильные размеры и расположение панели управления следует вызвать метод RecalcLayout. Метод RecalcLayout входит в класс CFrameWnd и вызывается автоматически, если вы используете методы CFrameWnd::ShowControlBar, CFrameWnd::OnIdleUpdateCmdUI, CFrameWnd::OnSize, CFrameWnd::FloatControlBar, CMDIChildWnd::Create, а также некоторые другие.



Как связаться с авторами


Авторы имеют почтовый адрес в сети GlasNet. Все свои замечания и предложения по содержанию книг серий "Библиотека системного программиста", а также "Персональный компьютер - шаг за шагом" вы можете присылать нам по следующему адресу:

:   frolov@glas.apc.org

Наш почтовый адрес доступен не только пользователям сети GlasNet. Абоненты других компьютерных сетей также могут передавать нам сообщения. Ниже мы приводим наш адрес в различных сетях:

Глобальная сеть

Наш адрес

CompuServe

>internet:frolov@glas.apc.org

GlasNet

frolov@glas.apc.org

Internet

frolov@glas.apc.org

Relcom

frolov@glas.apc.org

UUCP

uunet!cdp!glas!frolov

Вы также можете присылать свои пожелания почтой по адресу:

*        Издательский отдел АО "ДИАЛОГ-МИФИ".

Индекс 115409, город Москва, улица Москворечье,

дом 31, корпус 2.

Приносим свои извинения за то, что не можем ответить на каждое письмо. Мы также не занимаемся рассылкой книг, дискет и исходных текстов к нашим книгам. По этому вопросу обращайтесь непосредственно в издательство “Диалог-МИФИ”.



Как устроен компонент Splash Screen


Откройте окно просмотра проекта Project Workspace и обратите внимание на произошедшие в нем изменения. На странице ClassView появился новый класс CSplashWnd, включающий несколько методов и элементов данных. В главном классе приложения появился новый метод PreTranslateMessage.

На странице ResourceView к ресурсам приложения добавился ресурс Bitmap с идентификатором IDB_SPLASH. На странице FileView также произошли изменения. В ней добавился файл Splash.cpp, а в папке зависимых файлов Dependencies появились имена файлов Splash.h и Splash16.bmp.

Число 16 на конце имени файла Splash16.bmp означает, что в изображении используется шестнадцать цветов. К сожалению, компонент Splash Screen не работает с изображениями, имеющими большее количество цветов.

Кроме перечисленных изменений, хорошо заметных из окна просмотра проекта Project Workspace, имеют место и изменения в существующих методах главного класса приложения. Такие изменения обнаружить значительно труднее, особенно если программный код приложения слишком велик и данный компонент не имеет полной документации.

Для облегчения поиска фрагментов измененного кода они обозначаются специальными комментариями следующего вида:

// CG:

Символы CG являются сокращением от Component Gallry. После символов CG: как правило следует словесное описание добавленного программного кода. Так как Microsoft Visual C++ не умеет вставлять в текст программы русскоязычные комментарии, мы полностью заменили текст комментариев и добавили собственное описание программного кода компоненты Splash Screen.



Как устроено приложение CBarApp


Обратите внимание на первые строки файла Bar.cpp. Они содержат директивы #include, которые включают в исходный текст два файла - afxwin.h и afxext.h:

// Включаемый файл для MFC

#include <afxwin.h>

#include <afxext.h>

// Включаемый файл для ресурсов приложения

#include "resource.h"

С файлом afxwin.h вы уже знакомы. В этом файле определены классы, методы, константы и другие структуры для библиотеки классов MFC. Кроме того, файл afxwin.h автоматически подключает другой включаемый файл - windows.h.

Файл afxext.h необходим, так как в нем описываются классы, используемые для создания панели управления, в том числе сам класс панели управления - CToolBar.

Кроме системных файлов afxwin.h и afxext.h, в исходный текст файла Bar.cpp включен файл resource.h. Этот файл создается автоматически редактором ресурсов Microsoft Visual C++ и содержит определение различных идентификаторов приложения.

В приложении Bar определены два класса CBarApp и CBarWindow. Главный класс приложения CBarApp наследуется от базового класса CWinApp. Объект MyBarApp класса CBarApp объявлен как глобальный и создается сразу после запуска приложения.

В класс CBarApp входит единственный метод InitInstance. Метод InitInstance создает главное окно приложения, представленное классом CBarWindow, наследованным от класса CFrameWnd.

Взаимодействие главного класса приложения и главного класса окна приложения мы описывали в первой книге серии “Библиотека системного программиста”, посвященной программированию в Microsoft Visual C++ с использованием библиотеки классов MFC.

Обратите внимание, что в состав класса CBarWindow входит объект m_wndToolBar класса CToolBar. Именно этот объект и будет представлять панель управления. Включение объекта класса CToolBar в состав класса главного окна приложения вполне закономерно, так как панель управления, точно также как и меню, является атрибутом именно главного окна приложения:

class CBarWindow : public CFrameWnd

{

protected:

   CToolBar    m_wndToolBar;


// ...

}

Объект m_wndToolBar, представляющий панель управления, объявлен как protected. Доступ к нему открыт только для методов класса CBarWindow. Если надо открыть доступ к панели управления из вне класса CBarWindow,  тогда ключевое слово protected надо заменить на public.

В таблице сообщений класса CBarWindow находится макрокоманда ON_WM_CREATE. Поэтому в процессе создания главного окна приложения вызывается метод OnCreate. Мы используем метод OnCreate для создания панели управления.

Метод OnCreate класса CBarWindow сначала вызывает метод OnCreate базового класса CFrameWnd. Затем создается панель управления toolbar. Для этого вызывается метод Create объекта m_wndToolBar. В качестве указателя на родительское окно панели управления методу Create передается ключевое слово this, указывающее на текущий объект, то есть на главное окно приложения.

После создания панели управления вызывается метод LoadToolBar, загружающий панель управления с идентификатором IDR_MAINFRAME. Если вы запустите приложение под отладкой, то в случае возникновения ошибок при создании панели управления вызывается макрокоманда TRACE0. Она отображает сообщение об ошибке на странице Debug панели Output. Панель Output обычно располагается в нижней части окна Microsoft Visual C++.

Каждый раз, когда пользователь нажимает на кнопки в панели управления, в окно приложения, являющееся родительским окном панели управления, поступают командные сообщения. Идентификатор этих командных сообщений соответствует идентификатору нажатой кнопки.

Чтобы обработать командные сообщения от панели управления, в таблицу сообщений класса CBarWindow включены макрокоманды ON_COMMAND. В приложении Bar мы обрабатываем командные сообщения только от трех кнопок панели управления - ID_FILE_OPEN, ID_FILE_SAVE и ID_TOOL_EXIT:

//============================================================

// Таблица сообщений класса CBarWindow

//============================================================

BEGIN_MESSAGE_MAP(CBarWindow, CFrameWnd)

   // Макрокоманда необходима для перехвата сообщения

   // WM_CREATE. Для обработки сообщения вызывается

   // метод OnCreate

   ON_WM_CREATE()

   // Обработка сообщений от кнопок панели управления

   ON_COMMAND(ID_FILE_OPEN, CBarWindow::BarCommand)

   ON_COMMAND(ID_FILE_SAVE, CBarWindow::BarCommand)

   ON_COMMAND(ID_TOOL_EXIT, CBarWindow::BarCommand)

END_MESSAGE_MAP()

Чтобы не усложнять исходный текст приложения мы вызываем для обработки командных сообщений от кнопок панели управления один и тот же метод BarCommand. Метод BarCommand входит в состав класса CBarWindow. Единственное, что делает метод BarCommand - это выводит на экран сообщение, что данная команда не реализована.

Конечно, вы можете назначить для каждой кнопки панели управления свой собственный метод обработчик, выполняющий любые определенные вами действия.


Как устроено приложение Dater


Список всех классов, входящих в проект Dater, а также их методов можно просмотреть в окне Project Workspace на странице ClassView (рис. 5.16).

Рис. 5.16. Окно Project Workspace, страница ClassView

В приложение Dater входят следующие классы.

Класс

Базовый класс

Назначение

CAboutDlg

CDialog

Управляет информационной диалоговой панелью About

CDaterApp

CWinApp

Главный класс приложения

CDaterDoc

CDocument

Представлляет документ приложения

CDaterSet

CRecordset

Представлляет запись таблицы базы данных

CDaterView

CRecordView

Управляет окном просмотра приложения. В этом окне отображаются записи таблицы базы данных

CMainFrame

CFrameWnd

Главное окно приложения



Как устроено приложение MultiBar


В приложении MultiBar определены три класса CMultiBarApp, CMultiBarWindow и CExtendedBar. Классы CMultiBarApp и CMultiBarWindow представляют основные классы приложения, класс CExtendedBar представляет одну из панелей управления и будет рассмотрен ниже.



Класс CCmdUI


В MFC реализован специальный механизм для обновления таких объектов интерфейса пользователя как меню, панели управления и панели состояния. Этот механизм предусматривает передачу приложению команд обновления пользовательского интерфейса (update command user interface). Для обработки этих команд предназначена макрокоманда ON_UPDATE_COMMAND_UI, размещаемая в таблице сообщений класса.

Для каждой строки меню, для каждой кнопки панели управления и для каждого индикатора панели состояния передается отдельное сообщение.

Когда передаются команды обновления интерфейса пользователя? Многое зависит от самого обновляемого объекта.

В случае меню, команды обновления передаются в момент, когда пользователь открывает меню. Для каждой строки меню посылается отдельное сообщение.

Для кнопок панели управления и индикаторов панели состояния команды обновления передаются в период “бездействия” приложения, когда очередь сообщений приложения пуста.



Класс CMenu


Вы можете создать меню и без использования методов Create или LoadFrame. Для этого вы должны будете создать объект класса CMenu и вызвать для него несколько методов.



Класс CMultiView


Все изменения в программном коде приложения Multi, выполненные при вставке в него компонента Pop-up Menu, происходят только в классе окна, к которому добавляется контекстное меню. Компонент Pop-up Menu добавляет макрокоманду ON_WM_CONTEXTMENU к таблице сообщений класса CMultiView, а также встсавляет в класс CMultiView методы OnContextMenu и PreTranslateMessage.

В определении класса CMultiView добавляется только метод-обработчик OnContextMenu. Все остальные элементы класса не изменяются. После добавления к проекту Pop-up Menu класс CMultiView, определенный в файле MultiView.h будет выглядеть следующим образом:

class CMultiView : public CView

{

protected:

   // CG: Метод OnContextMenu добавлен компонентом Pop-up Menu

   afx_msg void OnContextMenu(CWnd*, CPoint point);

   CMultiView();

   DECLARE_DYNCREATE(CMultiView)

// Attributes

public:

   virtual BOOL PreTranslateMessage(MSG* pMsg);

   CMultiDoc* GetDocument();

// Operations

public:

// Overrides

   //{{AFX_VIRTUAL(CMultiView)

public:

   virtual void OnDraw(CDC* pDC);

   virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

   virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

   virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

   virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

   //}}AFX_VIRTUAL

// Implementation

public:

   virtual ~CMultiView();

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

protected:

   //{{AFX_MSG(CMultiView)

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};

Остальные классы приложения остаются без изменения.



Класс CSplashWnd


Практически весь программный код, отвечающий за отображение заставки Splash Screen, содержится в классе CSplashWnd. Этот класс включается в состав проекта и вы можете просмотреть его содержимое в окне проекта Project Workspace на странице ClassView (рис. 2.4).

Рис. 2.4. Окно Project Workspace, класс CSplashWnd

Определение класса CSplashWnd находится в файле Splash.h. Мы привели его полностью в листинге 2.1.

Класс CSplashWnd создан на основе базового класса CWnd. Он включает в себя ряд методов и несколько элементов данных. Класс CSplashWnd может обрабатывать сообщения, поэтому для него в  файле Splash.h определена макрокоманда DECLARE_MESSAGE_MAP, а в файле реализации - Splash.cpp - таблица сообщений класса.

Листинг 2.1. Файл Splash.h

// CG: This file was added by the Splash Screen component.

#ifndef _SPLASH_SCRN_

#define _SPLASH_SCRN_

// Splash.h : header file

//

//////////////////////////////////////////////////////////////

//   Splash Screen class

class CSplashWnd : public CWnd

{

// Construction

protected:

   CSplashWnd();

// Attributes:

public:

   CBitmap m_bitmap;

// Operations

public:

   static void EnableSplashScreen(BOOL bEnable = TRUE);

   static void ShowSplashScreen(CWnd* pParentWnd = NULL);

   static void PreTranslateAppMessage(MSG* pMsg);

// Overrides

   // ClassWizard generated virtual function overrides

   //{{AFX_VIRTUAL(CSplashWnd)

   //}}AFX_VIRTUAL

// Implementation

public:

   ~CSplashWnd();

   virtual void PostNcDestroy();

protected:

   BOOL Create(CWnd* pParentWnd = NULL);

   void HideSplashScreen();

   static BOOL c_bShowSplashWnd;

   static CSplashWnd* c_pSplashWnd;

// Generated message map functions

protected:

   //{{AFX_MSG(CSplashWnd)

   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

   afx_msg void OnPaint();

   afx_msg void OnTimer(UINT nIDEvent);

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};

#endif

Методы класса CSplashWnd определены в файле реализации - Splash.cpp. Этот файл также добавляется к проекту Multi. Мы привели полный исходный текст этого файла в листинге 2.2.


Листинг 2.2. Файл Splash.cpp

// CG: Файл Splash.cpp добавляется в проект во время вставки

// компонента Splash Screen и содержит реализацию класса

// CSplashWnd

#include "stdafx.h"

#include "resource.h"

#include "Splash.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char BASED_CODE THIS_FILE[] = __FILE__;

#endif

//////////////////////////////////////////////////////////////

//   Splash Screen class

BOOL CSplashWnd::c_bShowSplashWnd;

CSplashWnd* CSplashWnd::c_pSplashWnd;

CSplashWnd::CSplashWnd()

{

}

CSplashWnd::~CSplashWnd()

{

   // Clear the static window pointer.

   ASSERT(c_pSplashWnd == this);

   c_pSplashWnd = NULL;

}

BEGIN_MESSAGE_MAP(CSplashWnd, CWnd)

   //{{AFX_MSG_MAP(CSplashWnd)

   ON_WM_CREATE()

   ON_WM_PAINT()

   ON_WM_TIMER()

   //}}AFX_MSG_MAP

END_MESSAGE_MAP()

void CSplashWnd::EnableSplashScreen(BOOL bEnable /*= TRUE*/)

{

   c_bShowSplashWnd = bEnable;

}

void CSplashWnd::ShowSplashScreen(CWnd* pParentWnd /*= NULL*/)

{

   if (!c_bShowSplashWnd c_pSplashWnd != NULL)

      return;

   // Allocate a new splash screen, and create the window.

   c_pSplashWnd = new CSplashWnd;

   if (!c_pSplashWnd->Create(pParentWnd))

      delete c_pSplashWnd;

   else

      c_pSplashWnd->UpdateWindow();

}

BOOL CSplashWnd::PreTranslateAppMessage(MSG* pMsg)

{

   if (c_pSplashWnd == NULL)

      return FALSE;

   // If we get a keyboard or mouse message, hide the splash

   // screen.

   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



   }

   return FALSE;   // message not handled

}

BOOL CSplashWnd::Create(CWnd* pParentWnd /*= NULL*/)

{

   if (!m_bitmap.LoadBitmap(IDB_SPLASH))

      return FALSE;

   BITMAP bm;

   m_bitmap.GetBitmap(&bm);

   return CreateEx(0, AfxRegisterWndClass(0,

               AfxGetApp()->LoadStandardCursor(IDC_ARROW)),

               NULL, WS_POPUP | WS_VISIBLE, 0, 0, bm.bmWidth,

               bm.bmHeight, pParentWnd->GetSafeHwnd(), NULL);

}

void CSplashWnd::HideSplashScreen()

{

   // Destroy the window, and update the mainframe.

   DestroyWindow();

   AfxGetMainWnd()->UpdateWindow();

}

void CSplashWnd::PostNcDestroy()

{

   // Free the C++ class.

   delete this;

}

int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

   if (CWnd::OnCreate(lpCreateStruct) == -1)

      return -1;

   // Center the window.

   CenterWindow();

   // Set a timer to destroy the splash screen.

   SetTimer(1, 750, NULL);

   return 0;

}

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);

}

void CSplashWnd::OnTimer(UINT nIDEvent)

{

   // Destroy the splash screen window.

   HideSplashScreen();

}

Вы всегда можете получить файл Splash.cpp следуя инструкциям в начале раздела “Заставка для приложения”. Теперь опишем отдельные методы класса.


Класс дочернего окна MDI


Многооконное приложение строится с использованием большего числа классов, чем однооконное приложение. Помимо классов главного окна приложения и классов окна просмотра документа, в нем определен еще один класс, непосредственно связанный с отображением дочерних окон MDI. Этот класс называется CChildFrame и он наследуется от базового класса CMDIChildWnd, определенного в библиотеке MFC:

class CChildFrame : public CMDIChildWnd

{

   DECLARE_DYNCREATE(CChildFrame)

public:

   CChildFrame();

// Attributes

public:

// Operations

public:

// Overrides

   //{{AFX_VIRTUAL(CChildFrame)

   virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

   //}}AFX_VIRTUAL

// Implementation

public:

   virtual ~CChildFrame();

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

protected:

   //{{AFX_MSG(CChildFrame)

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};

Элементы класса CChildFrame вы можете просмотреть в окне Project Workspace на странице ClassView (рис. 1.11).

Рис. 1.11. Окно Project Workspace, класс CChildFrame

Объекты класса CChildFrame представляют дочерние окна MDI главного окна приложения. Внутри этих окон отображаются окна просмотра документа.



Класс документа приложения


Класс документа приложения CMultiDoc наследуется от базового класса CDocument библиотеки MFC. Определение этого класса вы можете найти в файле MultiDoc.h. Мы привели структуру класса CMultiDoc на рисунке 1.12.

Рис. 1.12. Окно Project Workspace, класс CMultiDoc

MFC AppWizard определяет класс CMultiDoc одинаково для однооконных и для многооконных приложений. Единственное исключение составляет название класса документа, которое создается на основе имени проекта:

class CMultiDoc : public CDocument

{

protected:

   CMultiDoc();

   DECLARE_DYNCREATE(CMultiDoc)

// Attributes

public:

// Operations

public:

// Overrides

   //{{AFX_VIRTUAL(CMultiDoc)

public:

   virtual BOOL OnNewDocument();

   virtual void Serialize(CArchive& ar);

   //}}AFX_VIRTUAL

// Implementation

public:

   virtual ~CMultiDoc();

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

protected:

protected:

   //{{AFX_MSG(CMultiDoc)

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};



Класс документа приложения - CDaterDoc


Класс документа приложения CDaterDoc представляет документ, с которым работает приложение. В него входит элемент m_daterSet класса CDaterSet, также определенного в нашем приложении, который представляет запись базы данных.

Кроме этого элемента в классе CDaterDoc определены конструктор, деструктор, метод OnNewDocument, а также методы AssertValid и Dump:

class CDaterDoc : public CDocument

{

protected:

   CDaterDoc();

   DECLARE_DYNCREATE(CDaterDoc)

// Attributes

public:

   CDaterSet m_daterSet;

// Operations

public:

// Overrides

   //{{AFX_VIRTUAL(CDaterDoc)

   public:

   virtual BOOL OnNewDocument();

   //}}AFX_VIRTUAL

// Implementation

public:

   virtual ~CDaterDoc();

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

protected:

   //{{AFX_MSG(CDaterDoc)

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};



Класс главного окна приложения


Внутри главного окна приложения отображаются панели управления и состояния, дочерние MDI окна, используемые для просмотра документов. Для управления главным окном приложения используется класс CMainFrame, определенный в файле MainFrm.h.

Вы можете изучить класс CMDIFrameWnd, просмотрев его структуру в окне Project Workspace, на странице ClassView (рис. 1.10). Выполните двойной щелчок левой кнопкой мыши по названию класса или по названию интересующего вас метода, и соответствующий программный код загрузится в окно редактора Microsoft Visual C++.

Рис. 1.10. Окно Project Workspace, класс CMainFrame

Ниже мы привели определение класса CMainFrame:

class CMainFrame : public CMDIFrameWnd

{

   DECLARE_DYNAMIC(CMainFrame)

public:

   CMainFrame();

// Attributes

public:

// Operations

public:

// Overrides

   //{{AFX_VIRTUAL(CMainFrame)

   virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

   //}}AFX_VIRTUAL

// Implementation

public:

   virtual ~CMainFrame();

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

protected:

   CStatusBar  m_wndStatusBar;

   CToolBar    m_wndToolBar;

protected:

   //{{AFX_MSG(CMainFrame)

   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};

Класс главного окна многооконного приложения CMainFrame практически полностью соответствует классу главного окна однооконного приложения. Даже названия этих классов одинаковы. Однако обратите внимание, что класс CMainFrame наследуется от базового класса CMDIFrameWnd, а не от CFrameWnd, как это было для однооконного приложения.



Класс главного окна приложения CDlgBarWindow


Класс CDlgBarWindow управляет главным окном приложения, создает диалоговую панель управления, а также обрабатывает сообщения, поступающие от диалоговой панели управления:

class CDlgBarWindow : public CFrameWnd

{

// Определяем панель управления

protected:

   // Панель управления на основе класса CDialogBar      

   CDialogBar       m_wndDialogBar;

  

protected:

   // Метод OnCreate используется для создания диалоговой

   // панели управления

   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

public:

   // Объявляем конструктор класса CDlgBarWindow

   CDlgBarWindow();

   // Объявляем методы для обработки команд от диалоговой

   // панелей управления

   afx_msg BOOL DlgBarCommand(UINT nID);

   afx_msg void DlgBarCombo();

  

   // Макрокоманда необходима, так как класс

   // CDlgBarWindow обрабатывает сообщения

   DECLARE_MESSAGE_MAP()   

};

Кроме ряда методов, в класс CDlgBarWindow входит элемент m_wndDialogBar класса CDialogBar. Этот элемент представляет диалоговую панель управления, которая будет отображаться в главном окне приложения.

Рассмотрим отдельные методы класса CDlgBarWindow более подробно.

Сейчас для нас наиболее важен метод OnCreate, который собственно, и создает диалоговую панель управления приложения DialogBar. В таблице сообщений класса CDlgBarWindow, находится макрокоманда ON_WM_CREATE. Поэтому в процессе создания главного окна приложения вызывается метод OnCreate.



Класс главного окна приложения - CMainFrame


Класс CMainFrame предназначен для управления главным окном приложения. Для этого класса определены конструктор, деструктор, методы PreCreateWindow, OnCreate, AssertValid и Dump. В него также входят два элемента данных m_wndToolBar и m_wndStatusBar, представляющие панель управления и панель состояния:

class CMainFrame : public CFrameWnd

{

protected:

   CMainFrame();

   DECLARE_DYNCREATE(CMainFrame)

// Attributes

public:

// Operations

public:

// Overrides

   //{{AFX_VIRTUAL(CMainFrame)

   virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

   //}}AFX_VIRTUAL

// Implementation

public:

   virtual ~CMainFrame();

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

protected: 

   CStatusBar  m_wndStatusBar;

   CToolBar    m_wndToolBar;

protected:

   //{{AFX_MSG(CMainFrame)

   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};

Мы не стали приводить исходные тексты методов класса CMainFrame, так как они практически не отличаются от методов класса CMainFrame любого другого однооконного приложения созданного MFC AppWizard.



Класс главного окна приложения CMultiMenuWindow


Класс CMultiMenuWindow управляет главным окном приложения, создает меню, загружает панель управления а также обрабатывает сообщения, в том числе командные сообщения и команды обновления от меню.

Фактически все методы, определенные в классе CMultiMenuWindow, можно условно разделить на три группы. В первую группу попал только один метод OnCreate. Он обрабатывает сообщение WM_CREATE, поступающее в момент создания окна приложения. Вторая группа состоит из шести методов - OnDisable, OnCommand, OnExit, OnConstruct, OnRestrictMenu и OnFullMenu. Эти методы используются для обработки командных сообщений от меню приложения. И, наконец, третья группа методов включает три метода - OnUpdateProcess, OnUpdateConstruct и OnUpdateDisable, которые обрабатывают команды обновления от трех различных строк меню приложения.

В состав класса также входит несколько элементов данных. Это флаги bEnable, bRadio и nCheck, управляющие характеристиками трех строк меню, а также объект m_wndStatusBar класса CStatusBar, представляющий панель состояния нашего приложения.

Рассмотрим отдельные методы класса CMultiMenuWindow более подробно.



Класс главного окна приложения CStateWindow


Класс CStateWindow управляет главным окном приложения, создает панель состояния, а также обрабатывает сообщения.

Кроме ряда методов, в класс CStateWindow входит флаг bIndicatorTEXT, используемый для управления индикатором ID_INDICATOR_TEXT, и объект m_wndStatusBar класса CStatusBar, предназначенный для создания и отображения полосы progress bar.

Рассмотрим отдельные методы класса CStateWindow более подробно.



Класс окна просмотра документа


Класс окна просмотра документа, также как класс документа и главный класс приложения, имеют своего двойника в однооконном приложении. Так, в приложении Single определен класс окна просмотра CSingleView, совпадающий с классом CMultiView.

Рис. 1.13. Окно Project Workspace, класс CMultiView

Вы можете просмотреть список методов, входящих в класс CMultiView, если откроете в окне Project Workspace страницу ClassView (рис. 1.13). А сейчас приведем определение класса CMultiView:

class CMultiView : public CView

{

protected:

   CMultiView();

   DECLARE_DYNCREATE(CMultiView)

// Attributes

public:

   CMultiDoc* GetDocument();

// Operations

public:

// Overrides

   //{{AFX_VIRTUAL(CMultiView)

public:

   virtual void OnDraw(CDC* pDC); 

   virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

   virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

   virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

   virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

   //}}AFX_VIRTUAL

// Implementation

public:

   virtual ~CMultiView();

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

protected:

   //{{AFX_MSG(CMultiView)

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};

Как видите, класс CMultiView наследуется от базового класса CView. Вы, однако, можете наследовать этот класс и от некоторых других классов библиотеки MFC.



Класс окна просмотра приложения - CDaterView


Большой интерес представляет класс окна просмотра приложения CDaterView. В нем содержится указатель m_pSet на объект класса CDaterSet, который представляет запись базы данных. Обратите внимание, что определение указателя находится внутри комментариев вида //{{AFX_DATA. Эти комментарии используются MFC ClassWizard:

class CDaterView : public CRecordView

{

protected:

   CDaterView();

   DECLARE_DYNCREATE(CDaterView)

public:

   //{{AFX_DATA(CDaterView)

   enum { IDD = IDD_DATER_FORM };

   CDaterSet* m_pSet;

   //}}AFX_DATA

// Attributes

public:

   CDaterDoc* GetDocument();

// Operations

public:

// Overrides

   //{{AFX_VIRTUAL(CDaterView)

public:

   virtual CRecordset* OnGetRecordset();

   virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

   virtual void DoDataExchange(CDataExchange* pDX);

   virtual void OnInitialUpdate();

   //}}AFX_VIRTUAL

// Implementation

public:

   virtual ~CDaterView();

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

protected:

   //{{AFX_MSG(CDaterView)

   //}}AFX_MSG

   DECLARE_MESSAGE_MAP()

};

Помимо конструктора и деструктора в классе CDaterView определен целый ряд методов - PreCreateWindow, GetDocument, OnGetRecordset, DoDataExchange, OnInitialUpdate, а также AssertValid и Dump. Опишем наиболее важные из этих методов более подробно.



Класс панели состояния


Для управления панелями состояния в состав библиотеки MFC включен класс CStatusBar. Как и классы CToolBar и CDialogBar, предназначенные для работы с панелями управления, класс CStatusBar также наследуется от базового класса CControlBar:

CStatusBar <- CControlBar <- CWnd <- CCmdTarget <- CObject



Класс записи базы данных - CDaterDoc


Центральным классом приложений, которые взаимодействуют с базами данных через драйвера ODBC, является класс, наследованный от базового класса CRecordset. В нашем приложении в качестве этого класса выступает класс CDaterSet:

class CDaterSet : public CRecordset

{

public:

   CDaterSet(CDatabase* pDatabase = NULL);

   DECLARE_DYNAMIC(CDaterSet)

// Field/Param Data

   //{{AFX_FIELD(CDaterSet, CRecordset)

   CString   m_NAME;

   CString   m_ADDRESS;

   long   m_PRIORITY;

   CString   m_PHONE;

   //}}AFX_FIELD

// Overrides

   //{{AFX_VIRTUAL(CDaterSet)

   public:

   virtual CString GetDefaultConnect();

   virtual CString GetDefaultSQL();

   virtual void DoFieldExchange(CFieldExchange* pFX);

   //}}AFX_VIRTUAL

// Implementation

#ifdef _DEBUG

   virtual void AssertValid() const;

   virtual void Dump(CDumpContext& dc) const;

#endif

};

Класс CDaterSet содержит в себе переменные, представляющие поля записи базы данных. Эти переменные размещаются внутри комментариев вида //{{AFX_FIELD.

В нашем случае эти переменные называются m_NAME, m_ADDRESS, m_PRIORITY и m_PHONE. Они представляют поля NAME, ADDRESS, PRIORITY и PHONE соответственно.

В классе CDaterSet также определены конструктор класса и несколько методов - GetDefaultConnect, GetDefaultSQL, DoFieldExchange, а также AssertValid и Dump.



Классы панелей управления


В состав библиотеки MFC включены два класса для работы с панелями управления - CToolBar и CDialogBar. Оба они наследуются от базового класса CControlBar, реализующего основные функции панелей управления. Кроме того, от базового класса CControlBar наследуется еще один класс - CStatusBar. Он предназначен для работы с панелями состояния и будет рассмотрен позже:

CToolBar   <- | <- CControlBar <- CWnd <- CCmdTarget <- CObject

CDialogBar <- |

CStatusBar <- |

Класс CToolBar представляет панель управления, состоящую из ряда кнопок. При желании, вы, конечно, сможете разместить на панели управления и другие органы управления, например списки или поля редактирования, однако такая возможность требует дополнительного программирования.

Если требуется создать панель, содержащую различные органы управления, а не только кнопки, то гораздо удобнее воспользоваться классом CDialogBar. Класс CDialogBar, также наследованный от базового класса CControlBar, позволяет создать панель управления на основе хорошо известного вам шаблона диалоговой панели. Более подробно о возможностях использования класса CDialogBar мы расскажем несколько позже, а сейчас остановим свое внимание на классе CToolBar.

Кнопки панели управления могут работать как обычные кнопки, как переключатели и как переключатели с зависимой фиксацией. Тип кнопок панели управления выбирается методами класса CToolBar.

Чтобы создать панель управления, сначала необходимо определить объект класса CToolBar, который будет представлять данную панель. Если панель имеет много органов управления, можно наследовать от класса CToolBar новый класс, расширить его дополнительными методами, и использовать полученный класс вместо класса CToolBar.

Объект CToolBar обычно включают как элемент главного окна приложения. Так, например, в приложениях, созданных с помощью средств MFC AppWizard, панель управления объявляется как элемент класса CMainFrame, наследованного от класса CFrameWnd или CMDIFrameWnd (в зависимости от интерфейса приложения). Класс CMainFrame как раз представляет главное окно приложения, внутри которого расположены панели управления, окна просмотра и т. д.


Конструктор класса CToolBar не имеет параметров:

CToolBar();

После того как объект класса CToolBar создан, следует вызвать метод Create, который создает панель управления. В качестве параметров, методу Create указываются различные характеристики создаваемой панели:

BOOL Create(

   CWnd* pParentWnd,

   DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP,

   UINT nID = AFX_IDW_TOOLBAR

);

Только первый параметр метода pParentWnd является обязательным. В нем надо указать идентификатор родительского окна для панели управления. В качестве такого окна обычно выступает главное окно приложения, элементом класса которого является объект класса CToolBar.

Второй параметр метода dwStyle не обязательный, но именно он определяет, как будет отображаться панель управления. В качестве параметра pParentWnd можно указать комбинацию флагов, представленных в следующей таблице.

Флаг

Описание

CBRS_BOTTOM

Панель управления отображается в нижней части окна

CBRS_FLOATING

Панель управления отображается в отдельном окне

CBRS_FLYBY

Панель состояния отображает краткое описание выбранной кнопки. Конечно, для этого как минимум необходимо, чтобы окно, в котором располагается панель управления, также имело панель состояния и чтобы для кнопок панели были определены соответствующие строковые ресурсы

CBRS_SIZE_DYNAMIC

Размер панели управления можно изменять. При этом кнопки в панели управления перестраиваются в несколько рядов

CBRS_SIZE_FIXED

Панель состояния имеет фиксированную форму (размер)

CBRS_TOOLTIPS

Для кнопок панели управления отображаются их краткие описания в окнах tool tips

CBRS_TOP

Панель управления отображается в верхней части окна

В качестве последнего параметра метода Create вы можете указать идентификатор, который будет присвоен панели управления. По умолчанию используется идентификатор AFX_IDW_TOOLBAR.

¨     Приложения, созданные MFC AppWizard, имеют меню View, содержащее строки Toolbar и Status bar. Строка Toolbar с идентификатором ID_VIEW_TOOLBAR позволяет закрывать и снова открывать панель управления. Обработка стандартного командного сообщения ID_VIEW_TOOLBAR выполняется методом OnUpdateControlBarMenu класса CFrameWnd. Сразу отметим, что метод OnUpdateControlBarMenu может управлять отображением панели управления только в том случае, если она имеет идентификатор AFX_IDW_TOOLBAR. Более подробно о методе OnUpdateControlBarMenu можно прочитать в разделе “Недокументированные возможности класса CMainFrame”.



Метод Create возвращает ненулевое значение в случае успешного создания панели или нуль в случае ошибки.

После того как вы создали панель управления, надо загрузить ресурс панели управления. Для этого предназначен метод LoadToolBar класса CToolBar. Метод LoadToolBar имеет две реализации:

BOOL LoadToolBar(LPCTSTR lpszResourceName);

BOOL LoadToolBar(UINT nIDResource);

В качестве параметра lpszResourceName следует указать имя ресурса панели управления. Если вы знаете идентификатор ресурса панели управления, используйте второй прототип метода и укажите идентификатор в качестве параметра nIDResource.

Если загрузка ресурса прошла успешно, метод LoadToolBar возвращает ненулевое значение. В случае ошибки возвращается нуль.

В Microsoft Visual C++ версии 2.х и более ранних версиях ресурс типа toolbar отсутствует. Вместо этого ресурса в файле ресурсов приложения записывалось только изображение кнопок панели управления. А вместо метода LoadToolBar класса CToolBar использовались вызовы двух других методов этого же класса - LoadBitmap и SetButtons.

Метод LoadBitmap загружал из ресурсов приложения изображение кнопок панели управления, а метод SetButtons устанавливал соответствие каждой кнопке панели управления ее изображения и идентификатора. Так как при создании новых приложений лучше использовать новый метод для отображения панелей управления, предполагающий работу с ресурсами toolbar и методом LoadToolBar, то мы не будем останавливаться на методах LoadBitmap и SetButtons.

На этом создание панели управления можно считать оконченным. Теперь ваше приложение имеет полноценную панель управления. Однако стоит изучить еще несколько методов класса CToolBar и его базового класса CControlBar, которые помогут сделать панель управления еще более удобной для пользователя.