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

         

Классы приложения Multi


MFC AppWizard создает для приложения Multi, обладающего многооконным интерфейсом, шесть основных классов, что на один класс больше, чем для однооконного приложения. Пять классов из шести представляют основу любого многооконного приложения, созданного MFC AppWizard. Шестой класс управляет информационной диалоговой панелью About.

Список названий классов, а также входящие в них методы и элементы данных можно просмотреть на странице ClassView окна Project Workspace (рис. 1.7). В отдельной папке Globals представлены глобальные объекты и переменные приложения. Приложение Multi имеет только один глобальный объект theApp. Это объект главного класса приложения.

Рис. 1.7. Окно Project Workspace, классы приложения

В следующей таблице кратко описано назначение отдельных классов приложения Multi. Более подробный рассказ об этих классах и их методах расположен ниже.

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

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

Описание

CMultiApp

CWinApp

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



CMainFrame

CMDIFrameWnd

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

CChildFrame

CMDIChildWnd

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

CMultiDoc

CDocument

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

CMultiView

CView

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

Кроме пяти основных классов создается также класс CAboutDlg, наследованный от базового класса CDialog. Он отвечает за диалоговую панель About. Если во время определения характеристик приложения вы включите возможность работы с базами данных, работу с сетевыми протоколами или использование технологии OLE, список классов приложения может стать значительно шире.



Команды панелей управления


Каждый раз когда пользователь нажимает на кнопки в панели управления или работает с дополнительными органами управления (текстовым редактором и списком combo-box), в окно приложения, являющееся родительским окном панели управления, поступают соответствующие сообщения.

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

Таблица сообщений класса CMultiBarWindow обрабатывает целый ряд сообщений от меню и панелей управления. Кроме них в таблице сообщений класса CMultiBarWindow располагается макрокоманда ON_WM_CREATE, которая вызывает метод OnCreate во время создания окна:

ON_WM_CREATE()

Для обработки командных сообщений от кнопок панелей Player и Style мы вызываем методы BarCommandOne и BarCommandRange, входящие в класс CMultiBarWindow.

Метод BarCommandOne отображает на экране сообщение о том, что данная команда не реализована - Command not implemented. Метод BarCommandRange не выполняет никаких действий:

// Обработчики команд от панели управления Player

ON_COMMAND(ID_STOP, BarCommandOne)

ON_COMMAND(ID_PLAY, BarCommandOne)

ON_COMMAND(ID_PAUSE, BarCommandOne)

ON_COMMAND_RANGE(ID_LEFT, ID_RIGHT, BarCommandRange)

ON_COMMAND_RANGE(ID_TYPE, ID_WAVE,  BarCommandRange)

// Обработчик команд от панели управления Style

ON_COMMAND_RANGE(ID_UNDERLINE, ID_MARK_4, BarCommandRange)

Для перехвата командных сообщений от панели управления Player и Style используются макрокоманды ON_COMMAND и ON_COMMAND_RANGE. Макрокоманда ON_COMMAND вызывает метод, указанный во втором параметре командного сообщения, соответствующего идентификатору, приведенному в первом параметре. Макрокоманда ON_COMMAND_RANGE. работает аналогично ON_COMMAND, но позволяет вызвать метод обработчик, указанный в третьем параметре, сразу для нескольких командных сообщений. Идентификаторы обрабатываемых сообщений находятся в промежутке значений, указанных первым и вторым параметрами макрокоманды.


Для обработки командных сообщений от кнопок панели управления Extended мы также используем метод BarCommandRange. Исключение составляет только кнопка ID_ADD. Сообщения от этой кнопки обрабатываются методом AddStringToComboBox класса CMultiBarWindow:

// Обработчики команд от панели управления Extended

ON_COMMAND(ID_ADD, AddStringToComboBox)

ON_COMMAND_RANGE(ID_FOTO, ID_DISK,  BarCommandRange)

В таблице сообщений класса CMultiBarWindow также расположены макрокоманды для обработки командных сообщений от меню View. Для их обработки используется метод ShowStyle класса CMultiBarWindow:

// Обработчики команд меню View

ON_COMMAND_EX(ID_Style, ShowStyle)

ON_COMMAND_EX(ID_Extended, ShowStyle)

ON_COMMAND_EX(ID_Player, ShowStyle)

Командные сообщения от всех строк меню View обрабатываются одним методом ShowStyle,  однако его вызов осуществляется с помощью макрокоманды ON_COMMAND_EX. Эта макрокоманда вызывает для обработки командного сообщения с идентификатором, заданным первым параметром, метод указанный во втором параметре. В отличие от макрокоманды ON_COMMAND, макрокоманда ON_COMMAND_EX передает методу-обработчику идентификатор полученного командного сообщения.

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


Комбинированный редактор


Некоторые многооконные приложения позволяют одновременно работать с документами различных типов. Примером такого приложения является сама среда разработки Visual C++. В ней вы одновременно можете открыть окно редактирования исходного текста приложения и редактор ресурсов. Большинство систем управления базами данных также позволяют работать с документами различных типов. Так FoxPro и Access позволяют в одном окне просматривать поля базы данных, а в другом разрабатывать диалоговую форму для отображения информации из этой базы данных.

Ранее мы уже научились создавать приложения, которые могут отображать графические объекты (окружности, прямоугольники и т. д.) и текстовую  информацию. Теперь мы приступим к разработке наиболее сложного приложения, которое может одновременно работать с документами двух различных типов - графическими и текстовыми.

Для упрощения возьмите уже готовое многооконное приложение, которое уже может работать с простейшими графическими документами - Multi.



Компоненты


Среда Microsoft Visual C++ предусматривает дополнительные возможности для повторного использования программного кода при создании новых программ. Для этого предназначена так называемая галерея компонентов - Component Gallery.

Component Gallery служит вместилищем для компонентов. В качестве компонентов выступают классы (возможно вместе с необходимыми ресурсами), органы управления ActiveX (OCX), а также сложные компоненты. Компоненты Component Gallery можно включать в ваше приложение и использовать по своему усмотрению.

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



Компоненты Microsoft


На странице Microsoft диалоговой панели Component Gallery расположены компоненты, разработанные фирмой Microsoft. Среди них содержатся много интересных компонент, добавляющих к вашему приложению различные возможности практически без дополнительных затрат с вашей стороны. Среди них компонент, позволяющий приложениям использовать обменный буфер Windows Clipboard, компонент, выполняющий фоновые работы во время бездействия приложения, компонент, содержащий готовые диалоговые панели для ввода пароля и отображения хода различных процессов и многое многое другое.

Чтобы получить полные описания каждого компонента, достаточно выбрать его в панели Component Gallery и нажать на кнопку с вопросительным знаком. Сейчас мы кратко опишем назначение компонент Microsoft, а затем рассмотрим использование одной из компонент на примере.

Пиктограмма

Назначение соответствующего компонента

Предназначен для использования со средствами автоматизированной разработки проектов - Custom AppWizard

Компонент добавляет к классам окон просмотра, наследованным от базового класса CView, методы для обработки команд меню Edit, предназначенные для взаимодействия с обменным буфером Clipboard

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

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

Этот компонент позволяет вам создать уникальный глобальный идентификатор - GUID. Такие идентификаторы используются при создании приложений, работающих с технологией OLE, регистрационной базой Windows и др. Созданный идентификатор записывается в буфер clipboard. Модификация проекта не выполняется, вы должны сами вставить идентификатор в исходный текст приложения

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

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

Включает поддержку OLE Automation

Если во время создания приложения средствами MFC AppWizard вы не указали, что оно может использовать органы управления OCX, используйте этот компонент

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

Используйте данный компонент, если ваше приложение должно работать с цветовыми палитрами

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

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

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

Компонент позволяет добавить к приложению блокнот Property Sheet (диалоговую панель с несколькими страницами) или ряд панелей выбора свойств Wizard

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

Используйте компонент для разделения окна на несколько отдельных частей

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

Компонент добавляет к диалоговой панели About приложения сведения о ресурсах системы

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

Компонент позволяет реализовать краткие подсказки (органы управления Tool Tips) для диалоговых панелей приложения

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

Компонент обеспечивает работу с сокетами Windows, что позволяет ему взаимодействовать с другими приложениями по протоколу TCP/IP. Если вы не указали во время создания проекта, что приложение будет использовать сокеты, вы можете добавить в проект этот компонент

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

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



Конструктор и деструктор класса CChildFrame


MFC AppWizard определяет для класса CChildFrame конструктор и деструктор. По умолчанию они не выполняют никаких действий. Вы можете изменить их для выполнения инициализации объектов класса дочернего окна MDI:

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

// Конструктор и деструктор класса CChildFrame

CChildFrame::CChildFrame()

{

   // TODO:

}

CChildFrame::~CChildFrame()

{

}



Конструктор и деструктор класса CDaterDoc


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



Конструктор и деструктор класса CDaterView


Конструктор класса CMainFrame вызывает конструктор базового класса CRecordView и передает ему в качестве параметра символ IDD, определенный как идентификатор шаблона диалоговой панели IDD_DATER_FORM, используемого окном просмотра.

Конструктор CMainFrame также приваивает указателю m_pSet значение NULL:

CDaterView::CDaterView()

   : CRecordView(CDaterView::IDD)

{

   //{{AFX_DATA_INIT(CDaterView)

   m_pSet = NULL;

   //}}AFX_DATA_INIT

   // TODO:

}

Деструктор класса CMainFrame не содержжат программного кода:

CDaterView::~CDaterView()

{

}



Конструктор и деструктор класса CMainFrame


Ниже представлены конструктор и деструктор класса CMainFrame. Изначально они не содержат программного кода и представляют собой простые заготовки. Вы можете использовать их для дополнительной инициализации объекта класса:

// Конструктор класса CMainFrame

CMainFrame::CMainFrame()

{

   // TODO:

}

// Деструктор класса CMainFrame

CMainFrame::~CMainFrame()

{

}


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



Конструктор и деструктор класса CMultiDoc


Конструктор и деструктор класса CMultiDoc не содержит программного кода. Вы можете добавить его по мере необходимости:

CMultiDoc::CMultiDoc()

{

   // TODO:

}

CMultiDoc::~CMultiDoc()

{

}



Конструктор и деструктор класса CMultiView


Конструктор и деструктор класса CMultiView не выполняют полезной работы. MFC AppWizard создает для них только пустые шаблоны, которые вы можете “наполнить” сами:

CMultiView::CMultiView()

{

   // TODO:

}

CMultiView::~CMultiView()

{

}



Конструктор и деструктор класса CSplashWnd


Конструктор класса CSplashWnd не содержит программного кода. Вы можете использовать его как заготовку, если решите расширить возможности компонента Splash Screen.

Деструктор класса CSplashWnd также не содержит ничего сложного, он используется исключительно для записи в указатель c_pSplashWnd значения NULL:

c_pSplashWnd = NULL;



Конструктор класса CDaterApp


Конструктор класса CSingleApp не выполняет никаких действий и состоит из пустого блока:

CDaterApp::CDaterApp()

{

   // TODO:

}



Конструктор класса CDaterSet


Конструктор класса CDaterSet вызывает конструктор базового класса CRecordset. В качестве параметра конструктору CDaterSet и конструктору базового класса передается указатель pdb на объект класса CDatabase, представляющий источник данных.

В приложении Dater конструктору CDaterSet параметр pdb не передается (см. класс CDaterDoc). Посмотрите описание конструктора класса CRecordset в документации Microsoft Visual C++. Если он вызывается без параметра или с параметром NULL, то конструктор автоматически создает объект класса CDatabase. С Этим объектом связывается источник данных, определенный в методе GetDefaultConnect:

CDaterSet::CDaterSet(CDatabase* pdb)

   : CRecordset(pdb)

{

   //{{AFX_FIELD_INIT(CDaterSet)

   m_NAME = _T("");

   m_ADDRESS = _T("");

   m_PRIORITY = 0;

   m_PHONE = _T("");

   m_nFields = 4;

   //}}AFX_FIELD_INIT

   m_nDefaultType = snapshot;

}

В конструкторе CDaterSet располагается блок операторов, ограниченный комментариями вида //{{AFX_FIELD_INIT, //}}AFX_FIELD_INIT. В нем выполняется инициализация элементов m_NAME, m_ADDRESS, m_PRIORITY и m_PHONE. Эти элементы входят в класс CDaterSet и представляют поля таблицы базы данных, связанной с соответствующим объектом CDaterSet (набором записей). Затем в этом же блоке инициализируется элемент m_nFields, принадлежащий базовому классу CRecordset.

Вы не должны модифицировать код, рассположенный внутри блока AFX_FIELD_INIT. Для этого используется MFC ClassWizard.

Последний оператор конструктора CDaterSet присваивает элементу m_nDefaultType, принадлежащему базовому классу CRecordset, значение snapshot (snapshot также входит в класс CRecordset). Этот элемент определяет тип набора записей, представленных классом CDaterSet. MFC AppWizard добавляет этот оператор, когда вы определяете режим работы с базой данных в диалоговой панели Database Options (рис. 5.7).



Конструктор класса CDlgBarWindow


Конструктор класса CDlgBarWindow используется для создания главного окна приложения. Мы рассказывали о процедуре создания главного окна приложения в томе 24 серии “Библиотека системного программиста”, посвященном библиотеке MFC, поэтому сейчас не будем на нем останавливаться более подробно.



Конструктор класса CMenu


Объект класса CMenu не является меню, он только представляет существующее меню. Вы можете создать объект класса CMenu как локальный, а после использования удалить. На меню это не повлияет:

{

   CMenu myMenu;

}



Конструктор класса CMultiApp


Конструктор класса, созданный MFC AppWizard, не выполняет никаких действий. В нем вы можете разместить код для инициализации объекта CMultiApp:

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

// Конструктор класса CMultiApp

CMultiApp::CMultiApp()

{

   // TODO:

}



Конструктор класса CMultiMenuWindow


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

Для создания окна приложения вызывается метод Create класса CFrameWnd. Обратите внимание, что метод Create создает окно с меню, которое имеет идентификатор IDR_MENU:

Create(NULL, "Status Bar Sample", WS_OVERLAPPEDWINDOW,

      rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU));

Затем выполняется загрузка таблицы акселераторов IDR_ACCELERATOR с помощью метода LoadAccelTable класса CFrameWnd:

LoadAccelTable(MAKEINTRESOURCE(IDR_ACCELERATOR));

 И, в конце, конструктор устанавливает значение флагов bEnable, bRadio и nCheck. Флагам bEnable и bRadio присваивается значение TRUE, а флагу nCheck - нулевое значение.



Конструктор класса CStateWindow


Конструктор класса CStateWindow используется для создания главного окна приложения. Для этого вызывается метод Create класса CFrameWnd. Обратите внимание, что метод Create создает окно с меню, которое имеет идентификатор IDR_MENU:

Create(NULL, "Status Bar Sample", WS_OVERLAPPEDWINDOW,

      rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU));

В конструкторе класса CStateWindow также устанавливается начальное состояние флага bIndicatorTEXT:

bIndicatorTEXT = TRUE;



Копирование панели управления


Чтобы ускорить процесс разработки панели управления приложения Bar, можно взять за основу панели управления ресурс toolbar приложения Multi, созданного с использованием средств MFC AppWizard. Мы описывали приложение Multi в разделе “Многооконное приложение”.

Не закрывая проект Bar и файл ресурсов Bar.rc, откройте файл ресурсов приложения Multi. Выберите панель управления toolbar и запишите ее в буфер clipboard. Затем вставьте эту панель в файл ресурсов приложения Bar - Bar.rc.

Оставьте название панели toolbar, изображения кнопок, их идентификаторы и текстовые описания без изменения. Добавьте в конце панели еще одну кнопку, и присвойте ей идентификатор ID_TOOL_EXIT. Введите текстовое описание кнопки - строку Exit\nExit.

Сохраните измененный файл ресурсов приложения Bar и закройте файл ресурсов приложения Multi без изменений. Исходный текст файла ресурсов Bar.rc представлен в листинге 3.5.

Листинг 3.5. Файл Bar.rc

//Microsoft Developer Studio generated resource script.

//

#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS

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

//

// Generated from the TEXTINCLUDE 2 resource.

//

#include "afxres.h"

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

#undef APSTUDIO_READONLY_SYMBOLS

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

//

// Russian resources

#if !defined(AFX_RESOURCE_DLL) defined(AFX_TARG_RUS)

#ifdef _WIN32

LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT

#pragma code_page(1251)

#endif //_WIN32

#ifdef APSTUDIO_INVOKED

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

//

// TEXTINCLUDE

//

1 TEXTINCLUDE DISCARDABLE

BEGIN

    "resource.h\0"

END

2 TEXTINCLUDE DISCARDABLE

BEGIN

    "#include ""afxres.h""\r\n"

    "\0"

END

3 TEXTINCLUDE DISCARDABLE

BEGIN

    "\r\n"

    "\0"

END

#endif    // APSTUDIO_INVOKED


#endif    // Russian resources

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

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

// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) defined(AFX_TARG_ENU)

#ifdef _WIN32

LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

#pragma code_page(1252)

#endif //_WIN32

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

//

// 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

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

//

// Bitmap

//

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

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

//

// String Table

//

STRINGTABLE DISCARDABLE

BEGIN

    ID_TOOL_EXIT            "Exit\nExit"

END

#endif    // English (U.S.) resources

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

#ifndef APSTUDIO_INVOKED

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

// Generated from the TEXTINCLUDE 3 resource.

//

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

#endif    // not APSTUDIO_INVOKED

Идентификаторы всех ресурсов приложения Bar определены в файле resource.h. Этот файл создается автоматически редактором ресурсов Microsoft Visual C++ (листинг 3.6).

Листинг 3.6. Файл resource.h

//{{NO_DEPENDENCIES}}

// Microsoft Developer Studio generated include file.

// Used by Bar.rc

//

#define IDR_HAND_BAR                    101

#define IDR_MAINFRAME                   128

#define ID_TOOL_EXIT                    32771

#define ID_BUTTON40001                  40001



#define ID_BUTTON40002                  40002

#define ID_BUTTON40003                  40003

#define ID_BUTTON40004                  40004

#define ID_BUTTON40005                  40005

#define ID_FILE_NEW                     0xE100

#define ID_FILE_OPEN                    0xE101

#define ID_FILE_SAVE                    0xE103

#define ID_FILE_PRINT                   0xE107

#define ID_EDIT_COPY                    0xE122

#define ID_EDIT_CUT                     0xE123

#define ID_EDIT_PASTE                   0xE125

#define ID_APP_ABOUT                    0xE140

// Next default values for new objects

//

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE        103

#define _APS_NEXT_COMMAND_VALUE         40006

#define _APS_NEXT_CONTROL_VALUE         1000

#define _APS_NEXT_SYMED_VALUE           101

#endif

#endif

Изображения кнопок панели управления IDR_MAINFRAME располагаются в файле Toolbar.bmp (рис. 3.11). Файл Toolbar.bmp содержит только изображения кнопок, разделители SEPARATOR в нем не представлены.



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

Постройте приложение Bar и запустите его на выполнение. На экране появится главное окно приложения, содержащее панель управления (рис. 3.12). Панель управления нельзя переместить в другое место, она жестко зафиксирована в верхней части окна.



Рис. 3.12. Приложение Bar

Все кнопки, кроме трех, недоступны и отображаются серым цветом.

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


Литература


1. Фролов А. В., Фролов Г. В. Операционная система Microsoft Windows 3.1 для программиста: В 3 ч. М.: Диалог-МИФИ, 1994. (Б-ка системного программиста; Т.11-13.).

2.     Фролов А. В., Фролов Г. В. Графический интерфейс GDI в Microsoft Windows. М.: Диалог-МИФИ, 1994. (Б-ка системного программиста; Т.14.).

3.     Фролов А. В., Фролов Г. В. Операционная система Microsoft Windows 3.1 для программиста. Дополнительные главы. М.: Диалог-МИФИ, 1994. (Б-ка системного программиста; Т.17.).

4.     Фролов А. В., Фролов Г. В. Операционная система Microsoft Windows 95 для программиста. М.: Диалог-МИФИ, 1994. (Б-ка системного программиста; Т.22.).

5.     Фролов А. В., Фролов Г. В. Программирование для Windows NT: В 2 ч. М.: Диалог-МИФИ, 1996. (Б-ка системного программиста; Т.26-27.).

6.     Эллис М., Строуструп В. Справочное руководство по языку программирования С++ с комментариями: Пер. с англ. М.: Мир, 1992.

7.     Том Сван. Программирование для Windows в Borland C++: Пер. с англ. - М.: БИНОМ, 1995.

8.     Viktor Toth. Visual C++™ 4 Unleashed. Sams Publishing, 1996.



Макрокоманда ON_UPDATE_COMMAND_UI


Макрокоманда ON_UPDATE_COMMAND_UI предназначена для использования в таблицах сообщений приложения и имеет следующий формат:

ON_UPDATE_COMMAND_UI(id, memberFxn)

Параметр id определяет идентификатор строки меню, кнопки панели управления или индикатора панели состояния, для которых надо обработать команду обновления. Параметр memberFxn задает метод, выполняющий обновление.

Если один и тот же метод вызывается для обработки различных команд обновления, можно использовать другую макрокоманду - ON_UPDATE_COMMAND_UI_RANGE. Она вызывает метод memberFxn для обработки всех команд обновления, идентификаторы которых находятся в промежутке значений от id1 до id2:

ON_UPDATE_COMMAND_UI_RANGE(id1, id2, memberFxn)

Метод - обработчик команд обновления, который вызывается макрокомандами ON_UPDATE_COMMAND_UI и ON_UPDATE_COMMAND_UI_RANGE имеет следующий формат:

afx_msg void memberFxn(CCmdUI* pCmdUI);

Имя метода - обработчика обычно формируется из префикса OnUpdate и названия соответствующего объекта интерфейса пользователя - строки меню, кнопки панели управления или индикатора панели состояния.

В качестве параметра pCmdUI методу передается указатель на объект класса CCmdUI. Этот объект представляет элемент интерфейса пользователя (строку меню, кнопку панели управления…), для которого надо обработать команду обновления. Вызывая методы класса CCmdUI, вы можете легко изменять состояние соответствующего объекта интерфейса пользователя.

Более подробно самые важные методы класса CCmdUI мы рассмотрим в следующем разделе.



Меню


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

Для создания и изменения меню приложения следует использовать редактор ресурсов Microsoft Visual C++. С помощью него вы разработаете меню буквально за несколько минут.

Редактор ресурсов позволяет для каждой строки меню определить ее название, идентификатор, текст подсказки, а также некоторые дополнительные характеристики. Но самым ценным является возможность, добавив к меню новые строки, сразу запустить MFC ClassWizard и определить методы приложения, которые будут использоваться для обработки командных сообщений от этих строк меню.

Чтобы добавить новую строку к меню, достаточно выполнить двойной щелчок левой кнопкой мыши по одному из пустых прямоугольников из точек, которые располагаются в конце главного меню (вы создадите еще одно меню верхнего уровня) и в низу каждого из меню (создается новая строка меню). При этом на экране появится диалоговая панель Menu Item Properties, которую вы должны заполнить (рис. 3.1).

Рис. 3.1. Редактор меню и диалоговая панель Menu Item Properties

Текст, который будет отображаться в строке меню, вы должны ввести в поле Caption. Затем в списке с полем редактирования ID надо выбрать идентификатор для этой строки меню. Если вы не заполните поле ID, редактор ресурсов самостоятельно создаст новый идентификатор на основе имени меню и строки.

В поле Prompt вы можете ввести текстовую строку, которая будет отображаться при выборе данного элемента меню в панели состояния приложения. Редактор ресурсов Microsoft Visual C++ создаст для введенного текста новый строковый ресурс и запишет его в файл ресурсов приложения, присвоив ему тот же идентификатор, что и меню. Так как строки меню и описывающий их текст, имеют одинаковые идентификаторы, то MFC сможет использовать их вместе. При выборе строки меню, MFC просто загружает строковый ресурс с идентичным идентификатором и отображает его в панели состояния.

Остальные переключатели диалоговой панели Menu Item Properties задают различные характеристики строк меню, отвечающие в первую очередь за их внешний вид. Изучите их самостоятельно, используя документацию Microsoft Visual C++.

Также легко можно просмотреть и изменить свойства уже существующих строк меню. Для этого надо выполнить по ним двойной щелчок левой кнопкой мыши. На экране появится уже описанная нами выше диалоговая панель Menu Item Properties, которая уже заполнена текущими параметрами строки меню.


В момент, когда пользователь открывает меню, приложению передаются команды обновления. В результате для всех строк меню, для которых в таблице сообщений приложения присутствуют макрокоманды ON_UPDATE_COMMAND_UI, вызываются соответствующие методы-обработчики. Они могут изменить состояние меню - заблокировать отдельные строки меню, выделить их символами · или Ö.



Меню без класса CMenu


Как и для других элементов пользовательского интерфейса, для управления меню в состав библиотеки классов MFC включен специальный класс - класс CMenu. Класс CMenu - один из самых незаметных классов библиотеки MFC. Ваше приложение может активно работать с меню, но все же в исходных текстах вы не найдете ни одного объекта этого класса.

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

// Объявляем указатель на шаблон документа

CSingleDocTemplate* pDocTemplate;

// Создаем шаблон документа

pDocTemplate = new CSingleDocTemplate(

   IDR_MAINFRAME,                // Идентификатор меню, панели

                                 // управления и пиктограммы

   RUNTIME_CLASS(CSingleDoc),    // Класс документа

   RUNTIME_CLASS(CMainFrame),    // Класс главного окна

   RUNTIME_CLASS(CSingleView));  // Класс окна просмотра

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

// Создаем главное окно многооконного приложения

CMainFrame* pMainFrame = new CMainFrame;

// Загружаем ресурсы с идентификатором IDR_MAINFRAME,

// в том числе и меню

if(!pMainFrame->LoadFrame(IDR_MAINFRAME))

   return FALSE;

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

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

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



Меню, панели управления и панели состояния


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

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

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

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

В предыдущем томе из серии “Библиотека системного программиста”, посвященном использованию библиотеки классов MFC, и в первой главе этой книги, называющейся “Многооконное приложение“ мы уже рассказали об основных принципах устройства меню и панелей управления. Сейчас мы более подробно расскажем об этих наиболее важных элементах интерфейса приложения.



Метод AddStringToComboBox класса CMultiBarWindow


Метод AddStringToComboBox класса CMultiBarWindow выполняет обработку командных сообщений от кнопки ID_ADD панели управления Extended. Для этого он сначала считывает строку, введенную в текстовом редакторе m_edit, а затем добавляет ее в список m_combo_box:

void CMultiBarWindow::AddStringToComboBox()

{

   // Получаем строку, введенную в текстовом редакторе m_edit

   char  tmpStr[39];

   m_wndExtendedBar.m_edit.GetLine(0, tmpStr,40);             

   // Добавляем новую строку к списку m_combo_box

   m_wndExtendedBar.m_combo_box.AddString(tmpStr);

}



Метод BarCommand класса CDlgBarWindow


Командные сообщения от кнопок Set, Clear, и переключателя Alighn обрабатываются методом BarCommand класса CDlgBarWindow. В качестве параметра nID методу BarCommand передается идентификатор вызвавшего его органа управления:

BOOL CDlgBarWindow::DlgBarCommand(UINT nID)

{

   //...

}

В приложении мы определили для кнопок Set, Clear, и переключателей группы Alighn, описывающие их строковые ресурсы, которые имеют точно такие же идентификаторы. Поэтому когда вызывается метод DlgBarCommand и ему передается идентификатор кнопки или переключателя, мы загружаем строковый ресурс, который имеет точно такой же идентификатор и отображаем его на экране:

if(szCommandAbout.LoadString(nID))

   MessageBox(szCommandAbout);

else

{

   // Ошибка при загрузке строкового ресурса

   TRACE0("Failed to load string\n");

   return -1;     

}



Метод Create


Метод Create создает и инициализирует окно, связанное с объектом CFrameWnd. В случае успешного завершения метод Create возвращает ненулевое значение, а в противном случае - ноль:

BOOL Create(

   LPCTSTR lpszClassName,               // Класс окна

   LPCTSTR lpszWindowName,              // Имя окна

   DWORD dwStyle = WS_OVERLAPPEDWINDOW, // Тип окна

   const RECT& rect = rectDefault,      // Расположение окна

   CWnd* pParentWnd = NULL,             // Родительское окно

   LPCTSTR lpszMenuName = NULL,         // Меню

   DWORD dwExStyle = 0,                 // Дополнительные

                                        // характеристики окна

   CCreateContext* pContext = NULL ); // Используется для

                                    // организации механизма

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

Обязательно надо указать только два первых параметра метода Create. Первый параметр lpszClassName служит для задания класса окна. В качестве него можно также указать значение NULL, тогда по умолчанию будет использован класс, определенный для окон CFrameWnd. Второй параметр lpszWindowName указывает имя окна - оно будет отображаться в заголовке окна.

Остальные параметры метода необязательные. Если их не указать, будут использованы значения, принятые по умолчанию. Нас, однако, сейчас интересует только параметр lpszMenuName. Через него вы можете указать имя ресурса меню, которое будет создано для данного окна. По умолчанию редактор ресурсов Microsoft Visual C++ присваивает созданным в нем ресурсам, в том числе меню, числовые идентификаторы. Чтобы получить из такого идентификатора значение, совместимое по типу с параметром lpszMenuName, следует использовать макрокоманду MAKEINTRESOURCE.

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

CMultiMenuWindow::CMultiMenuWindow()

{

   // Создаем окно приложения, соответствующее

   // данному объекту класса CMultiMenuWindow

   Create(NULL, "Multi Menu Sample", WS_OVERLAPPEDWINDOW,

      rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU));

}

Класс CMultiMenuWindow, конструктор которого представлен выше, наследован от базового класса CFrameWnd. Конструктор CMultiMenuWindow создает окно с заголовком Multi Menu Sample. Это окно имеет меню IDR_MENU. Меню с идентификатором IDR_MENU должно быть определено в файле ресурсов приложения.



Метод Create класса CSplashWnd


В классе CSplashWnd компонент Splash Screen переопределяет виртуальный метод Create базового класса CWnd:

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

{

/// ..

}

Класс CSplashWnd добаляет к этому методу программный код, который загружает ресурс изображения IDB_SPLASH. Для этого используется метод LoadBitmap:

if (!m_bitmap.LoadBitmap(IDB_SPLASH))

   return FALSE;

При помощи метода GetBitmap для объекта, представляющего изображения bitmap, определяются различные характеристики этого изображения, которые записываются в объект bm структуры BITMAP:

BITMAP bm;

m_bitmap.GetBitmap(&bm);

Последний оператор, завершающий метод Create, вызывает метод CreateEx, который и создает окно заставки:

return CreateEx(

   0,

   AfxRegisterWndClass(

      0,

      AfxGetApp()->LoadStandardCursor(IDC_ARROW)),

   NULL,

   WS_POPUP | WS_VISIBLE,

   0, 0, bm.bmWidth, bm.bmHeight,

   pParentWnd->GetSafeHwnd(), NULL

);

Метод CreateEx определен в классе CWnd. Первый параметр метода задает дополнительные стили создаваемого окна заставки. Этот параметр содержит нулевое значение. Описание дополнительных стилей вы можете найти в документации Microsoft Visual C++.

Второй параметр метода CreateEx должен содержать имя класса Windows, на основе которого создается окно. Для этого параметра используется класс, зарегистрированный функцией AfxRegisterWndClass.

Третий параметр метода CreateEx определяет текст заголовка создаваемого окна. Так как для окна заставки заголовок не нужен, то в качестве этого параметра передается значение NULL.

В четвертом параметре должны быть указаны основные стили создаваемого окна. Мы используем в качестве этого параметра комбинацию флагов WS_POPUP и WS_VISIBLE. Эти флаги означают, что создается временное окно, которое сразу отображается на экране. Дополнительную информацию об основных и дополнительных стилях окон вы можете получить из 11 тома “Библиотеки системного программиста”.

Пятый, шестой, седьмой и восьмой параметры метода CreateEx определяют начальное положение, а также ширину и высоту окна. Начальное положение окна заставки выбирается по умолчанию - пятый и шестой параметры содержат нулевые значения, а ширина и высота берутся исходя из размеров изображения bitmap.


Предпоследний, девятый параметр метода определяет родительское окно для окна заставки. В качестве этого параметра используется идентификатор окна (полученный методом CWnd::GetSafeHwnd), указанного параметром pParentWnd метода CSplashWnd::Create. Метод GetSafeHwnd класса CWnd возвращает идентификатор окна, связанного с объектом класса CWnd. Если объект класса CWnd не связан с окном, то метод GetSafeHwnd возвращает значение NULL, и, в этом случае, окно заставки не имеет родительского окна.

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

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

LPCTSTR AFXAPI

AfxRegisterWndClass(

   UINT nClassStyle,

   HCURSOR hCursor = 0,

   HBRUSH hbrBackground = 0,

   HICON hIcon = 0

);

Параметр nClassStyle указывает комбинацию стилей, используемых для создаваемого окна. Список стилей вы можете просмотреть в 11 томе “Библиотеки системного программиста” или в документации Microsoft Visual C++. Окна, созданные на основе зарегистрированного класса, будут использовать курсор с идентификатором hCursor, кисть с идентификатором hbrBackground и пиктограмму с идентификатором hIcon.

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


Метод DlgBarCombo класса CDlgBarWindow


Когда пользователь выбирает строку из списка combo-box в диалоговой панели управления, в ее родительское окно, которое в нашем случае является главным окном приложения, поступает сообщение. Для его обработки вызывается метод DlgBarCombo класса CDlgBarWindow.

Метод DlgBarCombo выводит на экран сообщение о том, что пользователь сделал выбор из списка combo-box:

void CDlgBarWindow::DlgBarCombo()

{

   // Отображаем сообщение о том, что сделан выбор из списка

   MessageBox("Combo-box selection changed");

}



Метод DoDataExchange класса CDaterView


Виртуальный метод DoDataExchange класса CDaterView, первоначально определен в классе CWnd. Он служит для реализации механизмов автоматического обмена данными - Dialog Data Exchange (DDX) и автоматической проверки данных - Dialog Data Validation (DDV). Мы рассматривали этот механизм в 24 томе серии “Библиотека системного программиста”:

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

// Метод DoDataExchange класса CDaterView

void CDaterView::DoDataExchange(CDataExchange* pDX)

{

   CRecordView::DoDataExchange(pDX);

   //{{AFX_DATA_MAP(CDaterView)

   DDX_FieldText(pDX,IDC_ADDRESS, m_pSet->m_ADDRESS, m_pSet);

   DDX_FieldText(pDX,IDC_NAME, m_pSet->m_NAME, m_pSet);

   DDX_FieldText(pDX,IDC_PHONE, m_pSet->m_PHONE, m_pSet);

   DDX_FieldText(pDX,IDC_PRIORITY, m_pSet->m_PRIORITY,m_pSet);

   //}}AFX_DATA_MAP

}

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

Обмен выполняется при помощи функций DDX_FieldText. Могут также использоваться и другие функции, например, DDX_FieldRadio, DDX_FieldCheck, DDX_FieldScroll. Практически каждый тип органов управления диалоговой панели имеет собственную функцию для выполнения процедуры обмена данными.

Всем функциям DDX_FieldText, вызываевым в методе DoDataExchange класса CDaterView передаются четыре параметра.

Первый параметр содержит указатель на объект класса CDataExchange. Этот объект определяет параметры обмена, в том числе направление, в котором надо выполнить обмен данными.

Второй параметр определяет идентификатор органа управления окна просмотра, с которым выполняется обмен данными (окно просмотра доолжно быть представлено классом CRecordView). В нашем случае это идентификаторы полей IDC_ADDRESS, IDC_NAME, IDC_PHONE и IDC_PRIORITY, котоорые принадлежат шаблону диалоговой панели используемому окном просмотра.

Третий параметр содержит ссылку на элемент данных класса CDaterSet, представляющий соответствующее поле базы данных. В нашем методе в качестве этого парамтера фигурируют m_pSet->m_ADDRESS, m_pSet->m_NAME, m_pSet->m_PHONE и m_pSet->m_PRIORITY.

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



Метод DoFieldExchange класса CDaterSet


Метод DoFieldExchange выполняет обмен данными между элементами класса CDaterSet, представляющими поля набора записей, и источником данных:

void CDaterSet::DoFieldExchange(CFieldExchange* pFX)

{

   //{{AFX_FIELD_MAP(CDaterSet)

   pFX->SetFieldType(CFieldExchange::outputColumn);

   RFX_Text(pFX, _T("[NAME]"), m_NAME);

   RFX_Text(pFX, _T("[ADDRESS]"), m_ADDRESS);

   RFX_Long(pFX, _T("[PRIORITY]"), m_PRIORITY);

   RFX_Text(pFX, _T("[PHONE]"), m_PHONE);

   //}}AFX_FIELD_MAP

}

Метод DoFieldExchange содержит блок из комментариев //{{AFX_FIELD_MAP, в котором расположены несколько методов RFX_Text, которые выполняют обмен данными между полями источника данных (в нашем случае это поля NAME,  ADDRESS, PRIORITY, PHONE) и соответствующими элементами класса CDaterSet (m_NAME, m_ADDRESS, m_PRIORITY, m_PHONE).

Вы не должны вручную исправлять программный код в блоке AFX_FIELD_MAP. Для этого надо использовать MFC ClassWizard (рис. 5.17).

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



Метод Enable


Виртуальный метод Enable позволяет установить или снять блокировку с объекта интерфейса пользователя, представленного объектом класса CCmdUI. Метод имеет единственный параметр bOn. Если параметр bOn содержит значение TRUE или не указан совсем, то блокировка снимается. Если параметр bOn содержит значение FALSE, то блокировка устанавливается:

virtual void Enable(BOOL bOn = TRUE);

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

Метод Enable также можно использовать для блокирования органов диалоговых панелей управления.



Метод EnableDocking класса CControlBar


Чтобы панель управления можно было перемещать с одной стороны окна к другой, надо вызвать метод EnableDocking для окна и для каждой панели управления (если их несколько).

Формат вызова метода EnableDocking класса CFrameWnd соответствует формату метода EnableDocking класса CControlBar. Однако набор флагов, которые можно указать в качестве параметра dwStyle, расширен:

void EnableDocking(DWORD dwStyle);

Флаг

Описание

CBRS_ALIGN_TOP

Панель управления можно пристыковать к верхней границе окна

CBRS_ALIGN_BOTTOM

Панель управления можно пристыковать к нижней границе окна

CBRS_ALIGN_LEFT

Панель управления можно пристыковать к левой границе окна

CBRS_ALIGN_RIGHT

Панель управления можно пристыковать к правой границе окна

CBRS_ALIGN_ANY

Панель управления можно пристыковать к любой границе окна

Если ни один из флагов не установлен, и параметр dwStyle равен нулю, то данная панель управления не может быть пристыкована ни к одной границе окна. В этом случае надо вызвать метод CFrameWnd::FloatControlBar и панель управления появится в отдельном мини-окне.

Панель управления можно пристыковать только к тем границам окна, которые одновременно выбраны методами CFrameWnd::EnableDocking и CControlBar::EnableDocking.



Метод EnableDocking класса CFrameWnd


Метод EnableDocking класса CFrameWnd разрешает пристыковку панели управления к определенным границам окна:

void EnableDocking(DWORD dwDockStyle);

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

Флаг

Описание

CBRS_ALIGN_TOP

Панель управления можно пристыковать к верхней границе окна

CBRS_ALIGN_BOTTOM

Панель управления можно пристыковать к нижней границе окна

CBRS_ALIGN_LEFT

Панель управления можно пристыковать к левой границе окна

CBRS_ALIGN_RIGHT

Панель управления можно пристыковать к правой границе окна

CBRS_ALIGN_ANY

Панель управления можно пристыковать к любой границе окна



Метод EnableSplashScreen класса CSplashWnd


Метод EnableSplashScreen класса CSplashWnd устанавливает флаг c_bShowSplashWnd, записывая в него значение, переданное через единственный параметр метода - bEnable:

c_bShowSplashWnd = bEnable;



Метод GetBarStyle класса CControlBar


Чтобы определить текущие характеристики панели управления, используйте метод GetBarStyle класса CControlBar. Метод GetBarStyle возвращает комбинацию флагов. Подробное описание флагов смотрите выше, в описании метода SetBarStyle:

DWORD GetBarStyle();

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



Метод GetDefaultConnect класса CDaterSet


Метод GetDefaultConnect возвращает текстовую строку, которая определяет источник данных, который будет связан с объектом CDaterSet. Эта строка формируется MFC AppWizard, при выборе вами источника данных:

CString CDaterSet::GetDefaultConnect()

{

   return _T("ODBC;DSN=Address Pad");

}



Метод GetDefaultSQL класса CDaterSet


Метод GetDefaultSQL возвращает текстовую строку, которая должна содержать имя таблицы источника данных или выражение SELECT языка SQL. На основе этой таблицы или результата запроса SELECT будет сформирован набор записей для объекта CDaterSet:

CString CDaterSet::GetDefaultSQL()

{

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

}



Метод GetDocument класса CDaterView


Метод GetDocument возвращает указатель на документ, связанный с данным окном просмотра. Если окно просмотра не связано ни с каким документом, метод возвращает значение NULL.

Метод GetDocument имеет две реализации. Одна используется для отладочной версии приложения, а другая для окончательной.

Окончательная версия GetDocument определена непосредственно после самого класса окна просмотра CDaterView как встраиваемый (inline) метод. Когда вы используете страницу ClassView окна Project Workspace, чтобы просмотреть определение метода GetDocument, вы увидите именно этот код:

// Окончательная версия приложения

#ifndef _DEBUG 

inline CDaterDoc* CDaterView::GetDocument()

   { return (CDaterDoc*)m_pDocument; }

#endif

Отладочная версия GetDocument расположена в файле реализации класса окна просмотра DaterView.cpp. Откройте этот файл вручную, выбрав его название из страницы FileView окна Project Workspace:

// Отладочная версия приложения

#ifdef _DEBUG

CDaterDoc* CDaterView::GetDocument()

{

   ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDaterDoc)));

   return (CDaterDoc*)m_pDocument;

}

#endif //_DEBUG

Макрокоманда RUNTIME_CLASS возвращает указатель на структуру CRuntimeClass, содержащую информацию о классе CDaterDoc. Метод IsKindOf, определенный в классе CObject, проверяет, принадлежит ли объект, на который указывает m_pDocument, к классу CDaterDoc или классу наследованному от CDaterDoc. Если в приложении есть ошибка и m_pDocument не указывает на документ приложения, макрокоманда ASSERT отображает соответствующее сообщение и прерывает работу приложения.



Метод GetDocument класса CMultiView


В секции атрибутов класса CMultiView после комментария Attributes объявлен метод GetDocument. Этот метод возвращает указатель на документ, связанный с данным окном просмотра. Если окно просмотра не связано ни с каким документом, метод возвращает значение NULL.

Метод GetDocument имеет две реализации. Одна используется для отладочной версии приложения, а другая - для окончательной. Окончательная версия GetDocument определена непосредственно после самого класса окна просмотра CMultiView как встраиваемый (inline) метод:

#ifndef _DEBUG

inline CMultiDoc* CMultiView::GetDocument()

   { return (CMultiDoc*) m_pDocument; }

#endif

Переменная m_pDocument является элементом класса CView, определенным как protected. В документации на класс CView описание элемента m_pDocument отсутствует. Однако, вам достаточно знать, что после инициализации документа и окна просмотра в нем записан указатель на соответствующий документ. Если вы желаете получить дополнительную информацию, обратитесь к исходным текстам библиотеки MFC. Вы найдете определение класса CView и элемента этого класса m_pDocument в файле Afxwin.h.

Метод GetDocument совпадает с одноименным методом класса окна просмотра однооконного приложения за исключением того, что тип возвращаемого им указателя CMultiDoc.

Отладочная версия GetDocument расположена в файле реализации класса окна просмотра MultiView.cpp:

#ifdef _DEBUG

CMultiDoc* CMultiView::GetDocument()

{

   ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMultiDoc)));

   return (CMultiDoc*) m_pDocument;

}

#endif //_DEBUG



Метод HideSplashScreen класса CSplashWnd


Метод HideSplashScreen класса CSplashWnd закрывает окно заставки, вызывая метод DestroyWindow, а затем устанавливает флаг обновления для всех окон приложения с помощью метода UpdateWindow:

DestroyWindow();

AfxGetMainWnd()->UpdateWindow();



Метод InitInstance класса CDaterApp


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

BOOL CDaterApp::InitInstance()

{

#ifdef _AFXDLL

   Enable3dControls();

#else

   Enable3dControlsStatic();

#endif

   LoadStdProfileSettings();

   CSingleDocTemplate* pDocTemplate;

   pDocTemplate = new CSingleDocTemplate(

      IDR_MAINFRAME,

      RUNTIME_CLASS(CDaterDoc),

      RUNTIME_CLASS(CMainFrame),  

      RUNTIME_CLASS(CDaterView));

   AddDocTemplate(pDocTemplate);

   CCommandLineInfo cmdInfo;

   ParseCommandLine(cmdInfo);

   if (!ProcessShellCommand(cmdInfo))

      return FALSE;

   return TRUE;

}

При создании шаблона документа указывается идентификатор типа документа IDR_MAINFRAME, класс документа приложения CDaterDoc, класс главного окна приложения CMainFrame и класс окна просмотра CDaterView

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

Подробное описание метода InitInstance главного класса однооконного приложения можно получить в 24 томе серии “Библиотека системного программиста”.



Метод InitInstance класса CMultiApp


Основную работу по инициализации приложения выполняет метод InitInstance главного класса приложения, определенный в файле Multi.cpp. Как видите, он отличается от метода InitInstance, который используется для однооконных приложений:

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

// Метод InitInstance

BOOL CMultiApp::InitInstance()

{

#ifdef _AFXDLL

   Enable3dControls();  

#else

   Enable3dControlsStatic();

#endif

   // Загружаем файл конфигурации

   LoadStdProfileSettings(); 

   // Создаем шаблон документа

   CMultiDocTemplate* pDocTemplate;

   pDocTemplate = new CMultiDocTemplate(

      IDR_MULTITYPE,

      RUNTIME_CLASS(CMultiDoc),

      RUNTIME_CLASS(CChildFrame),

      RUNTIME_CLASS(CMultiView));

   // Регистрируем шаблон документа

   AddDocTemplate(pDocTemplate);

   // Создаем главное окно приложения (MDI Frame window)

   CMainFrame* pMainFrame = new CMainFrame;

   if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

      return FALSE;

   m_pMainWnd = pMainFrame;

   // Выполняем стандартную обработку командной строки

   // приложения

   CCommandLineInfo cmdInfo;

   ParseCommandLine(cmdInfo);

   // Обрабатываем командную строку приложения

   if (!ProcessShellCommand(cmdInfo))

      return FALSE;

   // Отображаем окно

   pMainFrame->ShowWindow(m_nCmdShow);

   pMainFrame->UpdateWindow();

   return TRUE;

}

В начале InitInstance вызываются методы Enable3dControls и LoadStdProfileSettings. Они уже были описаны в предыдущем томе серии “Библиотека системного программиста”, посвященном MFC, поэтому мы не станем на них останавливаться и перейдем к рассмотрению шаблонов документа приложения.

Затем создается указатель pDocTemplate на объекты класса шаблона документов. Для однооконных приложений это класс CSingleDocTemplate, а для многооконных - CMultiDocTemplate. Создается новый объект класса и указатель на него записывается в переменную pDocTemplate. Для создания шаблона документа используется оператор new.


Конструктору класса CMultiDocTemplate передаются четыре параметра:

CMultiDocTemplate(

   UINT nIDResource,

   CRuntimeClass* pDocClass,

   CRuntimeClass* pFrameClass,

   CRuntimeClass* pViewClass

);

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

Остальные три параметра pDocClass, pFrameClass и pViewClass содержат указатели на объекты класса CRuntimeClass, полученные с помощью макрокоманд RUNTIME_CLASS из классов документа CMultiDoc, дочернего окна MDI CChildFrame и окна просмотра CMultiView. Таким образом, шаблон документа объединяет всю информацию, относящуюся к данному типу документов.

Созданный шаблон документов заносится в список шаблонов, с которыми работает приложение. Для этого указатель на созданный шаблон документа передается методу AddDocTemplate из класса CWinApp. Указатель на шаблон документов передается через параметр pTemplate:

void AddDocTemplate(CDocTemplate* pTemplate);

Указатель pTemplate должен указывать на объект класса CDocTemplate, однако мы передаем через него указатель на объект класса CMultiDocTemplate. Это допустимо, так как класс CDocTemplate является базовым классом для CMultiDocTemplate.

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

После создания шаблона документа создается главное окно MDI (главное окно приложения).

Для создания главного окна приложения мы формируем объект класса CMainFrame и записываем указатель на него в pMainFrame. Класс CMainFrame определен в нашем приложении. Мы расскажем о нем немного позже:

// Создаем главное окно MDI (главное окно приложения)



CMainFrame* pMainFrame = new CMainFrame;

Затем для только что созданного объекта вызывается метод LoadFrame класса CFrameWnd. Он создает окно, загружает ресурсы, указанные первым параметром, и связывает их с объектом класса CMainFrame. Параметр метода LoadFrame определяет меню, пиктограмму, таблицу акселераторов и таблицу строк главного окна приложения:

if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

   return FALSE;

Указатель на главное окно приложения, которым является главное окно MDI, записывается в элемент данных m_pMainWnd главного класса приложения. Элемент данных m_pMainWnd, определенн в классе CWinThread. Когда окно, представленное указателем m_pMainWnd закрывается, приложение автоматически будет завершено (в случае если приложение включает в себя несколько задач, завершается только соответствующая задача):

m_pMainWnd = pMainFrame;

Метод LoadFrame не отображает главное окно приложения на экране. Для этого надо вызвать методы ShowWindow и UpdateWindow:

// Отображаем главное окно приложения

pMainFrame->ShowWindow(m_nCmdShow);

// Обновляем содержимое окна

pMainFrame->UpdateWindow();

В заключение метода InitInstance обрабатывается командная строка приложения. Для этого создается объект cmdInfo класса CCommandLineInfo и для него вызываются методы ParseCommandLine и ProcessShellCommand:

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

// стандартных команд и обрабатываем их

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

// Распределяем команды, указанные в командной строке

// приложения

if (!ProcessShellCommand(cmdInfo))

      return FALSE;


Метод LoadFrame


Виртуальный метод LoadFrame позволяет динамически создавать окно, пользуясь информацией из файла ресурсов. В случае успешного завершения метод LoadFrame возвращает ненулевое значение, а в противном случае - ноль:

virtual BOOL LoadFrame(

   UINT nIDResource,

   DWORD dwDefaultStyle = WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE,

   CWnd* pParentWnd = NULL,

   CCreateContext* pContext = NULL

);

Параметры метода LoadFrame практически идентичны параметрам метода Create, описанного ранее. Исключение составляет первый параметр - nIDResource. Он представляет идентификатор, общий для нескольких ресурсов, используемых при создании окна. К таким ресурсам относятся меню (будет использоваться как меню окна), строковый ресурс (заголовок окна), пиктограмма (отображается в случае минимизации окна) и таблица клавиш акселерации (используется для ускоренного выбора строк меню).



Метод LoadMenu


После объявления объекта класса CMenu вы можете загрузить меню из ресурсов приложения, воспользовавшись для этой цели методом LoadMenu. В случае успешного завершения метод LoadMenu возвратит ненулевое значение, и нуль в противном случае:

BOOL LoadMenu(LPCTSTR lpszResourceName);

BOOL LoadMenu(UINT nIDResource);

Метод LoadMenu загрузит меню, заданное именем lpszResourceName или идентификатором nIDResource, и свяжет его с соответствующим объектом класса CMenu. Теперь вы можете использовать для управления загруженным меню другие методы класса CMenu.

После того как меню загружено, его можно “подключить” к окну. Для этого следует воспользоваться методом SetMenu входящим в класс CWnd.



Метод OnAppAbout класса CDaterApp


Метод OnAppAbout класса CDaterApp вызывается для обработки командного сообщения с идентификатором ID_APP_ABOUT, которое посылается при выборе из меню Help строки About. Этот метод совместно с классом CAboutDlg предназначен для отображения информационной диалоговой панели About (в файле ресурсов она имеет идентификатор IDD_ABOUTBOX). Мы не будем рассматривать этот метод и класс CAboutDlg, так как они не используются для взаимодействия с базой данных.



Метод OnCommand класса CMultiMenuWindow


Когда пользователь выбирает строку Process из меню File (для укороченного варианта меню) или из меню Mission (для полного варианта меню), или просто нажимает комбинацию клавиш <Ctrl+P>, приложению поступает командное сообщение, которое имеет идентификатор ID_MISSION_PROCESS. Для обработки этого сообщения вызывается метод CMultiMenuWindow класса CMultiMenuWindow. Данный метод отображает на экране сообщение Command not implemented.



Метод OnConstruct класса CMultiMenuWindow


Когда пользователь выбирает из меню Mission строку Construction, приложению поступает командное сообщение с идентификатором ID_MISSION_CONSTRUCT. Для обработки этого сообщения вызывается метод OnConstruct класса CMultiMenuWindow. Метод OnConstruct изменяет состояние флага bRadio, меняя значение bRadio с TRUE на FALSE и наоборот:

bRadio = !bRadio;

Флаг bRadio управляет отображением символа · около строки Construction меню Mission. Флаг bRadio проверяется методом OnUpdateConstruct, который является обработчиком команд обновления от этой строки меню.



Метод OnContextMenu класса CMultiView


Когда пользователь нажимает правую кнопку мыши в окне, макрокоманда ON_WM_CONTEXTMENU вызывает метод-обработчик OnContextMenu из класса этого окна. Методу OnContextMenu передаются два параметра:

afx_msg void OnContextMenu(CWnd* pWnd, CPoint pos);

Параметр pWnd содержит указатель на объект класса CWnd. Он представляет окно, в котором находился указатель мыши, когда была нажата правая кнопка мыши. Это может быть окно класса к которому принадлежит таблица сообщений или его дочернее окно.

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

Реализация метода OnContextMenu добавляется в файле MultiView.cpp:

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

// Метод OnContextMenu класса CMultiView

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

void CMultiView::OnContextMenu(CWnd*, CPoint point)

{

   // Объект menu будет представлять контекстное меню

   CMenu menu;

   // Загружаем меню CG_IDR_POPUP_MULTI_VIEW

   VERIFY(menu.LoadMenu(CG_IDR_POPUP_MULTI_VIEW));

   // Получаем указатель на всплывающее меню

   CMenu* pPopup = menu.GetSubMenu(0);

   ASSERT(pPopup != NULL);

   // Получаем указатель на объект CWnd, представляющий окно

   //   для которого надо отобразить контекстное меню

   CWnd* pWndPopupOwner = this;

   while (pWndPopupOwner->GetStyle() & WS_CHILD)

      pWndPopupOwner = pWndPopupOwner->GetParent();

   // Отображаем контекстное меню

   pPopup->TrackPopupMenu(

      TPM_LEFTALIGN | TPM_RIGHTBUTTON,

      point.x, point.y,

      pWndPopupOwner);

}

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

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


BOOL TrackPopupMenu(

   UINT nFlags,

   int x,

   int y,

   CWnd* pWnd,

   LPCRECT lpRect = 0

);

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

Если в качестве nFlags указан атрибут TPM_CENTERALIGN, то контекстное меню отображается по центру относительно координаты, указанной параметром x. Если в параметре nFlags установлен атрибут TPM_LEFTALIGN, то параметр x определяет координату левой стороны меню, а если установлен атрибут TPM_RIGHTALIGN - правой.

Кроме атрибутов TPM_CENTERALIGN, TPM_LEFTALIGN или TPM_RIGHTALIGN в параметре nFlags можно установить атрибут TPM_LEFTBUTTON или TPM_RIGHTBUTTON. Атрибут TPM_LEFTBUTTON говорит, что выбор из меню осуществляется нажатием левой, а TPM_RIGHTBUTTON - правой кнопкой мыши.

Назначение параметра x зависит от атрибутов, установленных в параметре nFlags. Параметр y во всех случаях указывает расположение верхней стороны меню. Координаты x и y указываются в экранных координатах.

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

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

В случае успешного завершения, метод TrackPopupMenu ненулевое значение, а в противном случае нуль.


Метод OnCreate класса CDlgBarWindow


Метод OnCreate класса CDlgBarWindow сначала вызывает метод OnCreate базового класса CFrameWnd:

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

   return -1;

Затем мы создаем диалоговую панель управления. Для этого вызываем метод Create для объекта m_wndDialogBar, входящего в класс CDlgBarWindow, и представляющего панель управления:

if (!m_wndDialogBar.Create(this, IDD_DIALOG_BAR,

   CBRS_TOP|CBRS_TOOLTIPS,

   IDD_DIALOG_BAR))

   {

      TRACE0("Failed to create dialog bar\n");

      return -1;     

   }

   return 0;

}

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

Второй параметр метода указывает идентификатор шаблона диалоговой панели, которая будет отображаться как диалоговая панель управления приложения. Мы указали идентификатор шаблона диалоговой панели IDD_DIALOG_BAR.

В качестве третьего параметра метода Create мы привели стиль CBRS_TOP. Стиль CBRS_TOP устанавливает расположение диалоговой панели управления в верхней части окна приложения.



Метод OnCreate класса CMainFrame


Метод OnCreate класса CMainFrame создает и отображает на экране панели управления и состояния:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

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

      return -1;

  

   if (!m_wndToolBar.Create(this)

      !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

   {

      // Ошибка создания панели управления

      TRACE0("Failed to create toolbar\n");

      return -1;   

   }

   if (!m_wndStatusBar.Create(this)

      !m_wndStatusBar.SetIndicators(indicators,

        sizeof(indicators)/sizeof(UINT)))

   {

      // Ошибка создания панели состояния

      TRACE0("Failed to create status bar\n");

      return -1;     

   }

   m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |

      CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

   m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

   EnableDocking(CBRS_ALIGN_ANY);

   DockControlBar(&m_wndToolBar);

   return 0;

}

Структура indicators, описывающая индикаторы панели состояния, определена в файле MainFrm.h следующим образом:

static UINT indicators[] =

{

   ID_SEPARATOR,

   ID_INDICATOR_CAPS,

   ID_INDICATOR_NUM,

   ID_INDICATOR_SCRL,

};

Сейчас мы не станем подробно останавливаться на процедуре создания панелей состояния и управления. Во первых, в 24 томе мы уже рассматривали метод OnCreate однооконного приложения Single. Он фактически полностью повторяет метод OnCreate приложения Multi. Во вторых мы посвятили проблеме использования меню, панелей состояния и панелей управления отдельный раздел “Меню, панели управления и панели состояния”. Прочитав его, вы полностью поймете как устроен метод OnCreate класса CMainFrame.


Метод OnCreate создает главное окно приложения и отображает в нем панели управления и состояния. Описание метода OnCreate класса CMainFrame вы можете посмотреть в разделе “Приложение Multi”.

Во время добавления компонента Splash Screen метод OnCreate класса CMainFrame модифицируется. К нему добавляется вызов метода ShowSplashScreen класса CSplashWnd.

Метод ShowSplashScreen класса CSplashWnd, который создает и отображает на экране окно заставки, будет описан нами позже:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

   // Вызываем метод OnCreate базового класса

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

      return -1;

  

   // Создаем панель управления toolbar

   if (!m_wndToolBar.Create(this)

      !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))

   {

      // Ошибка при создании панели управления toolbar

      TRACE0("Failed to create toolbar\n");

      return -1;

   }

   // Создаем панель состояния status bar

   if (!m_wndStatusBar.Create(this)

      !m_wndStatusBar.SetIndicators(indicators,

        sizeof(indicators)/sizeof(UINT)))

   {

      // Ошибка при создании панели состояния status bar

      TRACE0("Failed to create status bar\n");

      return -1;

   }

   // TODO: вы можете изменить характеристики панели

   // управления, убрав некоторые флаги CBRS_

   m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |

      CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

   // TODO: вы можете запретить перемещение панели управления,

   // если удалите следующие три строки программы

   m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

   EnableDocking(CBRS_ALIGN_ANY);

   DockControlBar(&m_wndToolBar);

   // CG: The following line was added by the Splash Screen

   // component.

   CSplashWnd::ShowSplashScreen(this);

   return 0;

}




Метод OnCreate класса CMainFrame создает главное окно приложения, и размещает в нем панель управления IDR_MAINFRAME и стандаартную панель состояния.



Метод OnCreate класса CMultiBarWindow


Метод OnCreate класса CMultiBarWindow сначала вызывает метод OnCreate базового класса CFrameWnd.

Чтобы разрешить перемещение панелей управления, вызываем метод EnableDocking для главного окна приложения.  Чтобы разрешить присоединение панелей управления ко всем сторонам окна, передаем методу EnableDocking значение CBRS_ALIGN_ANY:

// Разрешаем присоединение панелей управления ко

// всем сторонам окна CMultiBarWindow

EnableDocking(CBRS_ALIGN_ANY);

¨     Создание панели управления Player

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

Чтобы создать панель управления Player, вызывается метод Create объекта m_wndPlayerBar. Ему передаются набор флагов, определяющий характеристики панели управления. Флаг CBRS_SIZE_DYNAMIC определяет, что пользователь сможет менять форму панели управления Player. Флаг CBRS_BOTTOM задает начальное положение панели - вверху окна приложения. Флаг CBRS_TOOLTIPS разрешает отображение кратких подсказок для тех кнопок панели управления, которые имеют соответствующие строковые ресурсы:

if (!m_wndPlayerBar.Create(this, WS_CHILD | WS_VISIBLE |

   CBRS_SIZE_DYNAMIC | CBRS_BOTTOM  |

   CBRS_TOOLTIPS, ID_Player))

{

   // Ошибка при создании панели управления

   TRACE0("Failed to create toolbar\n");

   return -1;

}

После создания панели управления загружаем ресурс IDR_PLAYER, описывающий кнопки панели управления:

if (!m_wndPlayerBar.LoadToolBar(IDR_PLAYER))

{

   // Ошибка при загрузке ресурса панели управления

   TRACE0("Failed to load toolbar\n");

   return -1;

}

Когда панель управления отображается в мини-окне, она имеет заголовок. Чтобы установить текст в этих заголовках, вызываем метод SetWindowText:

m_wndPlayerBar.SetWindowText("Player");     

Теперь мы указываем, что кнопки панели управления с идентификаторами ID_TYPE, ID_CD_DRV и ID_WAVE составляют трехпозиционный переключатель с зависимой фиксацией. Для этого мы последовательно определяем стиль каждой из этих кнопок и добавляем к ним стиль TBBS_CHECKGROUP:


nIndex = m_wndPlayerBar.CommandToIndex(ID_TYPE);

nBarStyle = m_wndPlayerBar.GetButtonStyle(nIndex) |

            TBBS_CHECKGROUP;

m_wndPlayerBar.SetButtonStyle(nIndex, nBarStyle);

nIndex = m_wndPlayerBar.CommandToIndex(ID_CD_DRV);

nBarStyle =  m_wndPlayerBar.GetButtonStyle(nIndex) |

             TBBS_CHECKGROUP;

m_wndPlayerBar.SetButtonStyle(nIndex, nBarStyle);

nIndex = m_wndPlayerBar.CommandToIndex(ID_WAVE);

nBarStyle =  m_wndPlayerBar.GetButtonStyle(nIndex) |

             TBBS_CHECKGROUP;

m_wndPlayerBar.SetButtonStyle(nIndex, nBarStyle);

Далее кнопку с идентификатором ID_PAUSE мы превращаем в переключатель. Для этого определяем стиль этой кнопки и добавляем к нему стиль TBBS_CHECKBOX:

nIndex = m_wndPlayerBar.CommandToIndex(ID_PAUSE);

nBarStyle =  m_wndPlayerBar.GetButtonStyle(nIndex) |

             TBBS_CHECKBOX;

m_wndPlayerBar.SetButtonStyle(nIndex, nBarStyle);

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

m_wndPlayerBar.EnableDocking(CBRS_ALIGN_ANY);

Последним шагом в процессе создания панели управления Player является вызов метода DockControlBar для окна приложения. Этот метод пристывковывает панель управления Player к родительскому окну:

DockControlBar(&m_wndPlayerBar);

¨     Создание панели управления Style

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

Чтобы создать панель управления Style вызывается метод Create объекта m_wndStyleBar. Ему передается набор флагов, определяющий характеристики панели управления. Флаг CBRS_SIZE_FIXED указывает, что панель управления имеет фиксированную форму, которую пользователь не сможет изменить. Флаг CBRS_TOP задает начальное положение панели - вверху окна приложения. Флаг CBRS_TOOLTIPS разрешает отображение кратких подсказок для тех кнопок панели управления, которые имеют соответствующие строковые ресурсы.



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

if (!m_wndStyleBar.Create(this, WS_CHILD | WS_VISIBLE |

   CBRS_SIZE_FIXED | CBRS_TOP | CBRS_TOOLTIPS, ID_Style))

{

   // Ошибка при создании панели управления

   TRACE0("Failed to create toolbar\n");

   return -1;

}

После создания панели управления загружаем ресурс IDR_STYLE, описывающий кнопки панели управления:

if (!m_wndStyleBar.LoadToolBar(IDR_STYLE))

{

   // Ошибка при загрузке ресурса панели управления

   TRACE0("Failed to load toolbar\n");

   return -1;

}

Когда панель управления создана, вызываем метод SetWindowText, чтобы установить текст в ее заголовке:

m_wndStyleBar.SetWindowText("Style");  

Панель управления Style задумана нами как панель управления, которая все время отображается в отдельном мини-окне. Поэтому мы запрещаем пристывковывать панель управления Player к родительскому окну. Для этого вызываем метод EnableDocking, указав ему в качестве параметра нулевое значение:

m_wndStyleBar.EnableDocking(0);

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

nIndex = m_wndStyleBar.CommandToIndex(ID_SUBSCRIPT);

nBarStyle =  m_wndStyleBar.GetButtonStyle(nIndex) |

             TBBS_WRAPPED;

m_wndStyleBar.SetButtonStyle(nIndex, nBarStyle);

 

nIndex = m_wndStyleBar.CommandToIndex(ID_TEXT_JUSTIFY);

nBarStyle =  m_wndStyleBar.GetButtonStyle(nIndex) |

             TBBS_WRAPPED;

m_wndStyleBar.SetButtonStyle(nIndex, nBarStyle);

Когда стили всех кнопок установлены, вызываем метод FloatControlBar главного окна приложения, чтобы вывести панель управления Style в отдельном мини-окне. В качестве координат, в которых отображается панель Style, произвольно выбираем точку (100,100):

CPoint pointStyleBar(100, 100);

FloatControlBar(&m_wndStyleBar, pointStyleBar);



¨     Создание панели управления Extended

Панель управления Extended содержит дополнительные органы управления - текстовый редактор и список combo-box.

Чтобы создать панель управления Extended вызывается метод Create объекта m_wndExtendedBar. Ему передаются набор флагов, определяющий характеристики панели управления. Флаг CBRS_SIZE_DYNAMIC указывает, что пользователь может изменить форму панели управления. Флаг CBRS_TOP задает начальное положение панели - вверху окна приложения. Флаг CBRS_TOOLTIPS разрешает отображение кратких подсказок для тех кнопок панели управления, которые имеют соответствующие строковые ресурсы:

if(!m_wndExtendedBar.Create(this,

   WS_CHILD | WS_VISIBLE | CBRS_SIZE_DYNAMIC |

   CBRS_TOP | CBRS_TOOLTIPS, ID_Extended))

{

   // Ошибка при создании панели управления

   TRACE0("Failed to create toolbar\n");

   return -1;

}

После создания панели управления загружаем ресурс IDR_ EXTENDED, описывающий кнопки панели управления:

if(!m_wndExtendedBar.LoadToolBar(IDR_EXTENDED))

{

   // Ошибка при загрузке ресурса панели управления

   TRACE0("Failed to load toolbar\n");

   return -1;

}

Когда панель управления создана, вызываем метод SetWindowText, чтобы установить текст в ее заголовке:

m_wndExtendedBar.SetWindowText("Extended");     

Теперь мы приступаем к созданию дополнительных органов управления - текстового редактора и списка combo-box. Эти органы управления размещаются в панелях управления на месте разделителей.

¨     Отображаем текстовый редактор

По умолчанию разделитель имеет слишком маленький размер, чтобы разместить на его месте какой-либо орган управления. Поэтому сначала мы увеличиваем его размер. Для этого используем метод SetButtonInfo:

m_wndExtendedBar.SetButtonInfo(2, IDW_EDIT,

                               TBBS_SEPARATOR, 130);

Этот метод увеличивает размер первого разделителя, имеющего индекс 2, до 130 пикселов в ширину. Теперь надо определить координаты прямоугольной области разделителя в которых будет размещен текстовый редактор:



CRect rectEdit;

m_wndExtendedBar.GetItemRect(2, &rectEdit);

Метод GetItemRect записывает в rectEdit координаты разделителя. Чтобы отделить текстовый редактор от соседних кнопок, уменьшаем ширину прямоугольника rectEdit, делая отступ по 6 пикселов с правой и с левой стороны:

rectEdit.left += 6;

rectEdit.right -= 6;

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

if(!m_wndExtendedBar.m_edit.Create(WS_CHILD |

   ES_AUTOHSCROLL|WS_VISIBLE|WS_TABSTOP|WS_BORDER,

   rectEdit, &m_wndExtendedBar, IDW_EDIT))

{

   // Ошибка при создании текстового редактора

   TRACE0("Failed to create edit-box\n");

   return FALSE;

}

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

Стиль ES_AUTOHSCROLL позволяет вводить в текстовом редакторе длинные строки. Если строка не помещается в окне редактора, она сдвигается.

Стиль WS_VISIBLE устанавливается, чтобы текстовый редактор появился на экране сразу после создания. Если его не указать, то текстовый редактор останется невидимым.

Мы установили для текстового редактора стиль WS_BORDER, чтобы лучше выделить его на фоне панели управления. Этот стиль отображает вокруг текстового редактора тонкую рамку.

Панель управления не позволяет использовать клавишу <Tab> для перемещения фокуса ввода между кнопками. Однако если вы размещаете на панели управления дополнительные органы управления, для них можно установить стиль WS_TABSTOP. Тогда вы получите возможность перемещать фокус ввода между ними, нажимая клавишу <Tab>. Мы установили стиль WS_TABSTOP для двух дополнительных органов управления - текстового редактора и списка combo-box.



¨     Отображаем список combo-box

Теперь, когда текстовый редактор появился в панели управления, мы повторяем проделанные шаги и отображаем список combo-box.

Увеличиваем размер второго разделителя панели управления, который имеет индекс 4 до 150 пикселов:

m_wndExtendedBar.SetButtonInfo(4, IDW_COMBO,

   TBBS_SEPARATOR, 150);

Определяем координаты прямоугольной области панели управления, занимаемой этим разделителем, и уменьшаем ее ширину на 6 пикселов с каждой стороны:

CRect rectComboBox;

m_wndExtendedBar.GetItemRect(4, &rectComboBox);

rectComboBox.left += 6;

rectComboBox.right -= 6;

Список combo-box раскрывается вниз. Отводим для него дополнительно 80 пикселов. Если не увеличить вертикальные размеры прямоугольной области, предназначенной для размещения списка combo-box, то вы не сможете его открыть. Для этого просто не хватит высоты панели управления:

rectComboBox.bottom = rectComboBox.top + 80;

Для создания списка combo-box вызываем метод Create для объекта m_combo_box. Он размещает список в прямоугольной области rectComboBox:

if(!m_wndExtendedBar.m_combo_box.Create(

   CBS_DROPDOWN | WS_CHILD | WS_VISIBLE | WS_VSCROLL |

   ES_AUTOHSCROLL | CBS_DISABLENOSCROLL,

   rectComboBox, &m_wndExtendedBar, IDW_COMBO))

{

   // Ошибка при создании списока с полем редактирования

   TRACE0("Failed to create combo-box\n");

   return FALSE;

}

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

Так как список размещается в панели управления, то он является его дочерним окном. Поэтому мы указали для него стиль WS_CHILD. Вы можете опустить стиль WS_CHILD. В этом случае он будет установлен автоматически в процессе создания списка combo-box.

Стиль WS_VISIBLE устанавливается, чтобы список появился на экране сразу после создания. Если его не указать, список останется невидимым.

Стиль WS_VSCROLL добавляет к списку combo-box вертикальную полосу просмотра, если в списке слишком много строк. Мы также добавили стиль CBS_DISABLENOSCROLL, означающий что вертикальная полоса просмотра отображается, даже если все строки помещаются в списке. В этом случае, однако, полоса просмотра отображается серым цветом и не доступна для использования.



Внешний вид списка combo- box определяется стилем CBS_DROPDOWN, который означает, что список будет открываться в случае нажатия на кнопку 
.

Мы также установили для списка стиль WS_TABSTOP, который позволяет использовать клавишу <Tab> для передачи ему фокуса ввода. Напомним, что этот стиль также установлен для текстового редактора.

Сразу после создания списка combo-box мы записываем в него три строки: One, Two и Third. Вы увидите эти строки если откроете список combo-box в панели управления приложения.

Для добавления новых строк к списку нами используется метод AddString класса CComboBox:

m_wndExtendedBar.m_combo_box.AddString("One");

m_wndExtendedBar.m_combo_box.AddString("Two");

m_wndExtendedBar.m_combo_box.AddString("Third");

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

m_wndExtendedBar.EnableDocking(CBRS_ALIGN_ANY );

Последним шагом в процессе создания панели управления Extended является вызов метода DockControlBar для окна приложения. Этот метод пристывковывает панель управления Extended к родительскому окну:

DockControlBar(&m_wndExtendedBar);