Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Microsoft Visual C++ и MFC. Программирование для Windows 95 и Windows NT (часть 2)

© Александр Фролов, Григорий Фролов
Том 28, М.: Диалог-МИФИ, 1996, 288 стр.

[Назад] [Содеожание] [Дальше]

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

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

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

Чтобы выйти из этого положения, создают несколько отдельных панелей управления, которые можно открывать или закрывать по своему усмотрению. Такая организация панелей управления используется очень часто. Достаточно взглянуть на любое офисное приложение Microsoft - Microsoft Word или Microsoft Excel, или даже на среду Microsoft Visual C++.

Редактор панели управления

Начиная с версии 4.0 Microsoft Visual C++, панель управления является отдельным ресурсом, таким же как меню или шаблон диалоговой панели. Редактор ресурсов Microsoft Visual C++ позволяет создать новую панель управления или изменить уже существующую. В редакторе вы не только можете нарисовать новые кнопки, вы сразу можете присвоить им идентификаторы и вызвать ClassWizard, чтобы добавить программный код, вызываемый при нажатии на данную кнопку. В самом простом случае процедура добавления новой кнопки к уже существующей панели управления займет у вас всего несколько минут.

Создайте с помощью MFC AppWizard новый проект или откройте проект, созданный ранее, например, проект Multi. В окне Project Workspace откройте страницу ResourceView. Откройте папку ресурсов Toolbar. В ней располагается только один ресурс этого типа, имеющий идентификатор IDR_MAINFRAME. Загрузите этот ресурс в редактор ресурсов (рис. 3.7).

Рис. 3.7. Редактор ресурсов toolbar

В верхней части окна редактора ресурсов типа toolbar отображается редактируемая панель управления. С помощью мыши можно выбирать кнопки этой панели, которые вы желаете изменить. Редактирование изображения кнопок выполняется в нижней части окна редактора, разделенной на две области, в которых отображается кнопка в нормальном и увеличенном масштабе. Для редактирования предназначены инструменты, представленные в панели Graphics. Вы также можете задавать цвета из палитры Colors.

Редактор ресурсов позволяет присвоить идентификаторы отдельным кнопкам панели управления. Для этого сделайте двойной щелчок по изображению кнопки в верхней части окна редактора. На экране появится диалоговая панель Toolbar Button Properties (рис. 3.8).

Рис. 3.8. Диалоговая панель Toolbar Button Properties

Идентификатор кнопки вводится в списке ID. По умолчанию в списке ID отображается идентификатор, который кнопка имеет в данный момент. Вы можете заменить его другим идентификатором, выбрав его из списка или введя его вручную. Если кнопке, идентификатор еще не присвоен и поле ID пустое, то когда вы закроете панель Toolbar Button Properties, идентификатор будет создан автоматически.

В полях Width и Height выводятся, соответственно, ширина и высота кнопок панели управления в пикселах. Эти два значения относятся ко всем кнопкам панели, а не только к кнопке, выбранной для редактирования в данный момент.

В поле Prompt отображается текстовая строка, описывающая кнопку панели управления. Строка состоит из двух частей, разделенных символом \n. Первая часть содержит описание кнопки, отображаемое в панели состояния когда кнопка выбрана (или соответствующей строки меню, если в меню есть строка с таким же идентификатором). Во второй части строки находится короткое описание кнопки. Оно отображается в окне подсказки tooltips, если вы поместите указатель мыши над кнопкой и некоторое время подождете.

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

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

Каждый ресурс, представляющий панель управления в редакторе ресурсов 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 XE "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 XE "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 для однооконных и многооконных приложений, имеют соответствие в меню приложения.

Новая кнопка в панели управления

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

Вместе с Microsoft Visual C++ поставляются несколько изображений кнопок панелей управления, которые можно использовать в разрабатываемых приложениях. Откройте файл ресурсов Common.res, записанный на компакт диске Microsoft Visual C++, и просмотрите записанные в нем ресурсы типа toolbar. Если вы обнаружите подходящие вам изображение, скопируйте его в обменный буфер Windows clipboard и вставьте в редактируемую панель управления. Для более полного описания файла Common.res обратитесь к разделу “Ресурсы Microsoft”.

Введите идентификатор новой кнопки панели управления. Для этого, выполните двойной щелчок по изображению этой кнопки в верхней части окна редактирования. В поле ID, открывшейся диалоговой панели Toolbar Button Properties, введите идентификатор ID_MY_BUTTON (рис. 3.8).

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

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

Чтобы воспользоваться ClassWizard, сначала надо выбрать кнопку, к которой вы желаете привязать код, а затем нажать кнопку ClassWizard из панели Standard. ClassWizard откроет страницу Message Map и сразу предложит создать методы для выбранной кнопки (рис. 3.10).

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

По умолчанию, в списке Object IDs будет отображаться идентификатор кнопки, выбранной в редакторе панели управления - ID_MY_BUTTON. В списке Class name выбран класс CMainFrame - класс главного окна приложения. Вы можете выбрать и любой другой класс приложения, если желаете чтобы он обрабатывал команды от данной кнопки.

Теперь выберите из списка Messages идентификатор сообщения, подлежащего обработке. Вам доступны два варианта - COMMAND и UPDATE_COMMAND_UIё.

Выберите из списка Messages идентификатор COMMAND и нажмите кнопку Add Function. ClassWizard добавит к таблице сообщений класса CMainFrame новую макрокоманду для обработки команды от кнопки и запросит имя метода для обработки этой команды. По умолчанию будет предложено имя OnMyButton. Вы можете согласиться с предложением и нажать кнопку OK. ClassWizard добавит к классу CMainFrame метод OnMyButton.

Чтобы сразу перейти к редактированию данного метода, достаточно нажать на кнопку Edit Code. В окне редактирования появится файл с исходными текстами методов класса CMainFrame, а курсор будет установлен на метод OnMyButton:


//////////////////////////////////////////////////////////////
// Метод OnMyButton класса CMainFrame 

void CMainFrame::OnMyButton() 
{
	// TODO: Здесь вы можете добавить собственный 
	// программный код
}

Как видите, метод OnMyButton не имеет параметров. Одно то, что он вызван, служит сигналом нажатия на кнопку ID_MY_BUTTON. Добавьте после комментария TODO код, который вы желаете выполнять по нажатию кнопки. Для нашего первого тестового примера достаточно добавить вызов всего одного метода MessageBox или функции AfxMessageBox XE "AfxMessageBox" :


//////////////////////////////////////////////////////////////
// Метод OnMyButton класса CMainFrame 

void CMainFrame::OnMyButton() 
{
	// TODO: Здесь вы можете добавить собственный 
	// программный код
   MessageBox("Button is pressed");
}

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

Когда вы нажимаете на кнопку ID_MY_BUTTON, вызывается метод обработчик OnMyButton из класса CMainFrame. Он отображает на экране сообщение Button is pressed.

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

В состав библиотеки 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, которые помогут сделать панель управления еще более удобной для пользователя.

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

Во время создания панели управления вы можете указать ее характеристики через параметр dwStyle метода Create. Если вам потребовалось изменить эти характеристики уже во время работы приложения - используйте метод SetBarStyle. Метод SetBarStyle определен в классе CControlBar, который является базовым для класса CToolBar:


void SetBarStyle(DWORD dwStyle);

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

Флаг

Описание

CBRS_ALIGN_TOP

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

CBRS_ALIGN_BOTTOM

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

CBRS_ALIGN_LEFT

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

CBRS_ALIGN_RIGHT

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

CBRS_ALIGN_ANY

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

CBRS_TOOLTIPS

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

CBRS_FLYBY

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

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

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


DWORD GetBarStyle();

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

Простое приложение с панелью управления

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

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

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

Создайте новый проект под названием Bar. В качестве типа приложения выберите из списка Type строку Application. Выберите из меню Build строку Settings или нажмите комбинацию клавиш <Alt+F7>. На экране появится диалоговая панель Project Settings. В этой панели расположены несколько страниц, позволяющих настроить различные характеристики проекта.

Откройте страницу General. Выберите из списка Microsoft Foundation Classes строку Use MFC in a Shared Dll или строку Use MFC in a Static Library. Эта настройка указывает Microsoft Visual C++, что в приложении используются классы библиотеки MFC.

Наберите в редакторе исходный текст приложения и сохраните его в файле Bar.cpp (листинг 3.4). Затем включите этот файл в проект. Для простоты мы включили в один файл весь программный код приложения.

Листинг 3.4. Файл Bar.cpp


//============================================================
// Приложение Bar
// (c) Frolov G.V., 1996
// E-mail: frolov@glas.apc.org
//============================================================
// Исключаем редко используемые определения из 
// включаемых файлов
#define VC_EXTRALEAN

// Включаемый файл для MFC
#include <afxwin.h>
#include <afxext.h>
#include <acmn.h>

// Включаемый файл для ресурсов приложения
#include "resource.h"

//============================================================
// Класс CBarApp - главный класс приложения 
//============================================================
class CBarApp : public CWinApp
{
public:
   // Мы будем переопределять метод InitInstance,
   // предназначенный для инициализации приложения
   virtual BOOL InitInstance();
};
 
// Создаем объект приложение класса CBarApp
CBarApp MyBarApp;
 
//============================================================
// Класс CBarWindow - представляет главное окно 
//============================================================
class CBarWindow : public CFrameWnd
{

protected:  // control bar embedded members
   CToolBar    m_wndToolBar;
   
protected:
   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

public:
   // Объявляем конструктор класса CBarWindow
   CBarWindow();

   // Объявляем методы для обработки команд меню
   afx_msg void BarCommand();

   // Макрокоманда необходима, так как класс 
   // CBarWindow обрабатывает сообщения
   DECLARE_MESSAGE_MAP()    
}; 

//============================================================
// Метод BarCommand
// Обрабатывает команду ID_TEST_BEEP
//============================================================
void CBarWindow::BarCommand()
{
   MessageBox("Command not implemented");	
}

//============================================================
// Таблица сообщений класса CBarWindow
//============================================================
BEGIN_MESSAGE_MAP(CBarWindow, CFrameWnd)
   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()

//============================================================
// Метод InitInstance класса CBarApp
//============================================================
BOOL CBarApp::InitInstance()
{
   // Создаем объект класса CBarWindow
   m_pMainWnd = new CBarWindow();

   // Отображаем окно на экране
   m_pMainWnd -> ShowWindow(m_nCmdShow);

   // Обновляем содержимое окна
   m_pMainWnd -> UpdateWindow();
   return TRUE;
}

//============================================================
// Конструктор класса CBarWindow
//============================================================
CBarWindow::CBarWindow()
{ 
   // Создаем окно приложения, соответствующее 
   // данному объекту класса CBarWindow
   Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW,
         rectDefault, NULL ); 
}

//============================================================
// Метод OnCreate класса CBarWindow
// Вызывается во время создания окна приложения
//============================================================
int CBarWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   // Вызываем метод OnCreate базового класса
   if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
      return -1;

   // Создаем панель управления toolbar. В качестве 
   // родительского окна указываем окно CBarWindow
   if (!m_wndToolBar.Create(this))
   {
      // Ошибка при создании панели управления
      TRACE0("Failed to create toolbar\n");
      return -1;
   }

   if (!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
   {
      // Ошибка при загрузке ресурса панели управления
      TRACE0("Failed to load toolbar\n");
      return -1;
   }

   return 0;
}

Теперь необходимо создать ресурс панели управления toolbar. Вы можете сделать это несколькими способами - создать панель управления “с нуля” или скопировать уже готовую панель управления из другого приложения, например из приложения Multi, представленного в главе “Многооконное приложение”.

Перед тем как приступить к разработке панели управления, создайте файл ресурсов и включите его в проект. Для этого выберите из меню File строку New. Из открывшейся диалоговой панели New выберите строку Resource Script и нажмите на кнопку OK. Будет создан пустой файл ресурсов. Сохраните его в каталоге приложения под именем Bar.rc и включите в проект.

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

Выберите из меню Insert строку Resource, а затем из открывшейся диалоговой панели Insert Resource выберите строку Toolbar и нажмите на кнопку OK.

Запустится редактор ресурсов и в нем будет загружена новая панель управления. Создайте панель управления, постепенно добавляя к ней по одной кнопке. Для каждой кнопки нарисуйте ее изображение, а также присвойте ей уникальный идентификатор и строку описания (см. раздел “Редактор панели управления”).

При создании панелей управления руководствуйтесь информацией из файла ресурсов приложения Bar (листинг 3.5) и изображениями кнопок панелей управления (рис. 3.9).

Панель управления приложения Bar должна иметь идентификатор IDR_MAINFRAME. В ней следует расположить девять кнопок с идентификаторами ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_SAVE, ID_EDIT_CUT, ID_EDIT_COPY, ID_EDIT_PASTE, ID_FILE_PRINT, ID_APP_ABOUT и ID_TOOL_EXIT.

Между кнопками ID_FILE_SAVE и ID_EDIT_CUT, ID_EDIT_PASTE и ID_FILE_PRINT, вставьте разделители. Для каждой из кнопок вы также можете ввести их текстовые описания.

Сохраните измененный файл ресурсов.

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

Чтобы ускорить процесс разработки панели управления приложения 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

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

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

Как устроено приложение 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 XE "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 - это выводит на экран сообщение, что данная команда не реализована.

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

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

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

Положение панели управления

Панель управления приложения Bar нельзя переместить с одной границы окна к другой и нельзя разместить ее в отдельном окне, независимом от главного окна приложения. Единственное, что вы можете сделать, так это выбрать начальное положение панели управления, установив в момент вызова метода Create флаг CBRS_TOP или CBRS_BOTTOM.

Чтобы вы смогли перемещать панель управления с одной границы окна к другой надо:

1.     Разрешить перемещение панели управления для окна, которое содержит панель управления. Для этого следует вызвать метод EnableDocking данного окна. Метод EnableDocking является элементом класса CFrameWnd

2.     Разрешить такое перемещение для самой панели управления. Для этого следует вызвать метод EnableDocking панели управления. Метод EnableDocking является элементом класса CControlBar

3.     Переместить панель управления к одной из сторон окна приложения или вывести ее в отдельном окне. Для этого необходимо вызвать метод DockControlBar или FloatControlBar данного окна приложения. Методы DockControlBar и FloatControlBar являются элементами класса CFrameWnd

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

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

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

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

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

void EnableDocking(DWORD dwDockStyle);

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

Флаг

Описание

CBRS_ALIGN_TOP

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

CBRS_ALIGN_BOTTOM

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

CBRS_ALIGN_LEFT

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

CBRS_ALIGN_RIGHT

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

CBRS_ALIGN_ANY

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

Метод 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.

Методы DockControlBar и FloatControlBar класса CFrameWnd

Чтобы пристыковать панель управления к границе окна, надо вызвать метод DockControlBar класса CFrameWnd:


void 
DockControlBar(
   CControlBar * pBar, 
   UINT nDockBarID = 0, 
   LPCRECT lpRect = NULL
);

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

Флаг

Описание

AFX_IDW_DOCKBAR_TOP

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

AFX_IDW_DOCKBAR_BOTTOM

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

AFX_IDW_DOCKBAR_LEFT

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

AFX_IDW_DOCKBAR_RIGHT

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

Если параметр nDockBarID равен нулю, то панель управления присоединяется к любой стороне окна.

Как видите, параметр nDockBarID может задавать несколько сторон окна одновременно. В этом случае панель управления присоединяется к той границе окна, которая одновременно указана методами CFrameWnd::EnableDocking и CControlBar::EnableDocking. Если таких границ несколько, то они выбираются в следующем порядке - сначала верхняя, а если к ней панель не может быть присоединена, тогда нижняя, левая, и правая стороны окна.

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

Если вам надо отобразить панель управления в отдельном мини-окне и не пристыковывать его к границам окна, то вместо метода DockControlBar вызовите метод FloatControlBar класса CFrameWnd:


CFrameWnd* 
FloatControlBar(
   CControlBar * pBar,
   CPoint point
);

Панель управления, указанная параметром pBar, отображается в отдельном мини-окне. Расположение окна панели управления задается параметром point, который указывает координаты верхнего левого угла панели управления. Используются экранные координаты.

Метод FloatControlBar возвращает указатель на текущее окно.

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


void SetWindowText(LPCTSTR lpszString);

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

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

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

Можно изменить форму панели управления или нет, определяется методом 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;

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

Панель управления, созданная на основе класса 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.

Недокументированные возможности класса CMainFrame

Изучая пример приложения DOCKTOOL, поставляемого вместе с Microsoft Visual C++, мы обнаружили, что для отображения и удаления с экрана панелей управления используется метод OnBarCheck.

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


BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   // Другие макрокоманды таблицы сообщений
   ON_COMMAND_EX(IDW_BROWSE_BAR, OnBarCheck)
   ON_COMMAND_EX(IDW_DEBUG_BAR, OnBarCheck)
   ON_COMMAND_EX(IDW_EDIT_BAR, OnBarCheck)
END_MESSAGE_MAP()

Таким образом, когда пользователь выбирает из меню View приложения строку с именем панели управления, выдается командное сообщение с идентификатором, соответствующим строке меню и самой панели управления (идентификаторы панелей управления идентичны идентификаторам соответствующих строк меню View). Командное сообщение обрабатывается таблицей сообщений класса CMainFrame. Для его обработки вызывается метод OnBarCheck, которому в качестве параметра передается идентификатор панели управления.

Если вы решите поискать описание метода OnBarCheck в справочной системе Microsoft Visual C++, вас ждет разочарование. Ни в класс CFrameWnd, ни в один из его базовых классов метод OnBarCheck не входит. Когда вы вернетесь к исходным текстам самого приложения, в них вы также не обнаружите определение этого метода.

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

В файле Afxwin.h, в котором объявлен класс CFrameWnd, вы можете найти объявления входящих в него методов OnUpdateControlBarMenu и OnBarCheck:


class CFrameWnd : public CWnd
{
// ...
// Command Handlers
public:
   afx_msg void OnUpdateControlBarMenu(CCmdUI* pCmdUI);
   afx_msg BOOL OnBarCheck(UINT nID);
}

Определения исходных текстов методов OnUpdateControlBarMenu и OnBarCheck содержатся в файле Winfrm.cpp.

В файле Winfrm.cpp также можно найти обращения к методам OnUpdateControlBarMenu и OnBarCheck в таблице сообщений класса CFrameWnd. Приведем соответствующий фрагмент этой таблицы:


BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)

   // turning on and off standard frame gadgetry
   ON_UPDATE_COMMAND_UI(ID_VIEW_STATUS_BAR, 
                        OnUpdateControlBarMenu)
   ON_COMMAND_EX(ID_VIEW_STATUS_BAR, OnBarCheck)
   ON_UPDATE_COMMAND_UI(ID_VIEW_TOOLBAR, 
                        OnUpdateControlBarMenu)
   ON_COMMAND_EX(ID_VIEW_TOOLBAR, OnBarCheck)
END_MESSAGE_MAP()

Две пары макрокоманд ON_UPDATE_COMMAND_UI и ON_COMMAND_EX вызывают методы OnUpdateControlBarMenu и OnBarCheck для обработки командных сообщений с идентификаторами ID_VIEW_STATUS_BAR и ID_VIEW_TOOLBAR. Командные сообщения с такими идентификаторами поступают при выборе строк Toolbar и Status Bar меню View.

Меню View, содержащее строки Toolbar и Status Bar, вставляется во все приложения с оконным интерфейсом, которые созданы с использованием средств MFC AppWizard.

Рассмотрим теперь сами методы OnBarCheck и OnUpdateControlBarMenu. Метод OnBarCheck класса CFrameWnd определен следующим образом:


//////////////////////////////////////////////////////////////
// Метод OnBarCheck класса CFrameWnd
BOOL CFrameWnd::OnBarCheck(UINT nID)
{
   ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
   ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);

   CControlBar* pBar = GetControlBar(nID);
   if (pBar != NULL)
   {
      ShowControlBar(pBar, 
        (pBar->GetStyle() & WS_VISIBLE) == 0, FALSE);
      return TRUE;
   }
   return FALSE;
}

Отладочная версия метода OnBarCheck класса CFrameWnd проверяет соответствие идентификаторов ID_VIEW_STATUS_BAR, AFX_IDW_STATUS_BAR и ID_VIEW_TOOLBAR, AFX_IDW_TOOLBAR. Отметим, что эти идентификаторы определены в файле Afxres.h следующим образом:


#define AFX_IDW_TOOLBAR      0xE800
#define AFX_IDW_STATUS_BAR   0xE801 

#define ID_VIEW_TOOLBAR      0xE800
#define ID_VIEW_STATUS_BAR   0xE801

Метод GetControlBar класса CFrameWnd определяет указатель на объект класса CControlBar, который представляет панель управления или панель состояния с идентификатором nID. Идентификаторы строк меню ID_VIEW_TOOLBAR и ID_VIEW_STATUS_BAR соответствуют стандартным идентификаторам панели управления AFX_IDW_TOOLBAR и панели состояния AFX_IDW_STATUS_BAR.

При выборе из меню View строки Toolbar передается командное сообщение ID_VIEW_TOOLBAR, а при выборе строки Status bar - сообщение ID_VIEW_STATUS_BAR. Во время обработки этих сообщений, вызов метода GetControlBar определит объект класса CControlBar, соответствующий либо панели управления AFX_IDW_TOOLBAR, либо панели состояния AFX_IDW_STATUS_BAR.

Затем метод ShowControlBar отображает или закрывает соответствующую панель. Если панель была открыта, метод ShowControlBar скрывает ее и наоборот.

Аналогичным образом устроен метод OnUpdateControlBarMenu класса CFrameWnd, который обрабатывает команды обновления (по умолчанию, он обрабатывает команды обновления от строк Toolbar и Status bar меню View).

Метод OnUpdateControlBarMenu проверяет, отображается ли на экране панель управления или панель состояния с идентификатором, соответствующим идентификатору команды обновления. Если панель отображается, то строка меню отмечается символом Ö:


//////////////////////////////////////////////////////////////
// Метод OnUpdateControlBarMenu класса CFrameWnd
void CFrameWnd::OnUpdateControlBarMenu(CCmdUI* pCmdUI)
{
   ASSERT(ID_VIEW_STATUS_BAR == AFX_IDW_STATUS_BAR);
   ASSERT(ID_VIEW_TOOLBAR == AFX_IDW_TOOLBAR);

   CControlBar* pBar = GetControlBar(pCmdUI->m_nID);
   if (pBar != NULL)
   {
      pCmdUI->SetCheck((pBar->GetStyle() & WS_VISIBLE) != 0);
      return;
   }
   pCmdUI->ContinueRouting();
}

В конце метода OnUpdateControlBarMenu класса CFrameWnd вызывается метод ContinueRouting класса CCmdUI, который направляет команду обновления для дальнейшей обработки другим классам MFC (см. раздел “Обработка командных сообщений”).

Приложение MultiBar

Создайте новый проект под названием MultiBar. В качестве типа приложения выберите из списка Type строку Application. Настройте проект MultiBar, точно также как вы настраивали проект Bar - укажите, что приложение будет работать с библиотекой классов MFC.

Наберите в редакторе исходный текст приложения и сохраните его в файле MultiBar.cpp (листинг 3.7). За основу вы можете взять файл Bar.cpp приложения Bar. Включите готовый файл MultiBar.cpp в проект.

Листинг 3.7. Файл MultiBar.cpp


//============================================================
// Приложение MultiBar
// (c) Frolov G.V., 1996
// E-mail: frolov@glas.apc.org
//============================================================
// Исключаем редко используемые определения из 
// включаемых файлов
#define VC_EXTRALEAN

// Включаемый файл для MFC
#include <afxwin.h>
#include <afxext.h>
#include <afxcmn.h>

// Включаемый файл для ресурсов приложения
#include "resource.h"

//============================================================
// Класс CMultiBarApp - главный класс приложения 
//============================================================
class CMultiBarApp : public CWinApp
{
public:
   // Мы будем переопределять метод InitInstance
   virtual BOOL InitInstance();
};
 
// Создаем объект приложение класса CMultiBarApp
CMultiBarApp MultiBarApp;
 
   //============================================================
// Класс CExtendedBar - класс панели управления Extended
   //============================================================
class CExtendedBar : public CToolBar
{
public:
   // Дополнительные органы управления панели Extended
   CEdit m_edit;          // текстовый редактор
   CComboBox m_combo_box; // список с текстовым редактором
};
   //============================================================
// Класс CMultiBarWindow - представляет главное окно 
//============================================================
class CMultiBarWindow : public CFrameWnd
{
// Определяем панели управления
protected: 
   // Панель управления Player
   CToolBar       m_wndPlayerBar;
   // Панель управления Style
   CToolBar       m_wndStyleBar;
   // Панель управления Extended
   CExtendedBar   m_wndExtendedBar;
   
protected:
   // Метод OnCreate используется для создания 
   // панелей управления
   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

public:
   // Объявляем конструктор класса CMultiBarWindow
   CMultiBarWindow();

   // Объявляем методы для обработки команд от панелей 
   // управления
   afx_msg void BarCommandOne();
   afx_msg void BarCommandRange(UINT nID);
   afx_msg void AddStringToComboBox();

   // Объявляем метод для обработки команд от меню View
   afx_msg BOOL ShowStyle(UINT nID);

   // Макрокоманда необходима, так как класс 
   // CMultiBarWindow обрабатывает сообщения
   DECLARE_MESSAGE_MAP()    
}; 

//============================================================
// Метод BarCommandRange
// Обрабатывает команды от панели управления
   //============================================================
void CMultiBarWindow::BarCommandRange( UINT nID )
{
   // Обработчик не выполняет никакой работы
}
  //============================================================
// Метод BarCommand
// Обрабатывает команды от кнопок панелей управления
   //============================================================
void CMultiBarWindow::BarCommandOne()
{
   // Отображаем сообщение о том, что команда не реализована
   MessageBox("Command not implemented");	
}

//============================================================
// Метод AddStringToComboBox
// Обрабатывает команду от кнопки Add панели 
// управления Extended
   //============================================================
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);
}

//============================================================
// Метод ShowStyle
// Обрабатывает команды от меню View
   //============================================================
BOOL CMultiBarWindow::ShowStyle(UINT nID)
{
   // Определяем указатель на панель управления, 
   // соответствующую идентификатору nID
   CControlBar* pBar = GetControlBar(nID);

   // Определяем, отображается в данный момент панель 
   // управления на экране или нет
   BOOL bShow = ((pBar -> GetStyle() & WS_VISIBLE) != 0);
   
   // Изменяем состояние панели управления: если панель 
   // управления отображается на экране, удаляем ее с экрана, 
   // если нет - отображаем
   ShowControlBar( pBar, !bShow, FALSE);
      
   return TRUE;
}
  //============================================================
// Таблица сообщений класса CMultiBarWindow
   //============================================================
BEGIN_MESSAGE_MAP(CMultiBarWindow, CFrameWnd)

   // Макрокоманда вызывает метод OnCreate
   ON_WM_CREATE()

   // Обработчики команд от панели управления 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)

   // Обработчики команд от панели управления Extended
   ON_COMMAND(ID_ADD, AddStringToComboBox)
   ON_COMMAND_RANGE(ID_FOTO, ID_DISK,  BarCommandRange)

   // Обработчик команд от панели управления Style
   ON_COMMAND_RANGE(ID_UNDERLINE, ID_MARK_4, BarCommandRange)

   // Обработчики команд меню View
   ON_COMMAND_EX(ID_Style, ShowStyle)
   ON_COMMAND_EX(ID_Extended, ShowStyle)
   ON_COMMAND_EX(ID_Player, ShowStyle)

END_MESSAGE_MAP()
   //============================================================
// Метод InitInstance класса CMultiBarApp
// Создает главное окно приложения и отображает его на экране
//============================================================
BOOL CMultiBarApp::InitInstance()
{
   m_pMainWnd = new CMultiBarWindow();
   m_pMainWnd -> ShowWindow(m_nCmdShow);
   m_pMainWnd -> UpdateWindow();

   return TRUE;
}
   //============================================================
// Конструктор класса CMultiBarWindow
//============================================================
CMultiBarWindow::CMultiBarWindow()
{ 
   // Создаем окно приложения, соответствующее 
   // данному объекту класса CMultiBarWindow
   Create(NULL, "Multi Bar", WS_OVERLAPPEDWINDOW,
          rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU)); 
}

//============================================================
// Метод OnCreate класса CMultiBarWindow
// Используется для создания панелей управления
//============================================================
int CMultiBarWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   // Вызываем метод OnCreate базового класса
   if(CFrameWnd::OnCreate(lpCreateStruct) == -1)
      return -1;

   // Разрешаем присоединение панелей управления ко 
   // всем сторонам окна CMultiBarWindow
   EnableDocking(CBRS_ALIGN_ANY);
   
   //  Переменные для изменения стилей кнопок 
   UINT nBarStyle;
   int nIndex;
   //============================================================
// Создаем и отображаем панель управления Player
//============================================================
   // Создаем панель управления toolbar
   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;
   }
   
   // Загружаем ресурс панели управления Player
   if(!m_wndPlayerBar.LoadToolBar(IDR_PLAYER))
   {
      // Ошибка при загрузке ресурса панели управления 
      TRACE0("Failed to load toolbar\n");
      return -1;
   }
   
   // Устанавливаем заголовок панели управления Player
   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);
   
   // Разрешаем пристывковывать панель управления Player к 
   // любой строке родительского окна
   m_wndPlayerBar.EnableDocking(CBRS_ALIGN_ANY );

   // Пристывковываем панель управления Player к 
   // родительскому окну
   DockControlBar(&m_wndPlayerBar);

//============================================================
// Создаем и отображаем панель управления Style
//============================================================
   // Создаем панель управления toolbar
   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;
   }

   // Загружаем ресурс панели управления Style
   if(!m_wndStyleBar.LoadToolBar(IDR_STYLE))
   {
      // Ошибка при загрузке ресурса панели управления
      TRACE0("Failed to load toolbar\n");
      return -1;
   }

   // Устанавливаем заголовок панели управления Style
   m_wndStyleBar.SetWindowText("Style");   

   // Запрещаем пристывковывать панель управления Player к 
   // родительскому окну
   m_wndStyleBar.EnableDocking(0);

   // Устанавливаем для кнопки ID_SUBSCRIPT стиль TBBS_WRAPPED
   nIndex = m_wndStyleBar.CommandToIndex(ID_SUBSCRIPT);
   nBarStyle = m_wndStyleBar.GetButtonStyle(nIndex) | 
               TBBS_WRAPPED;
   m_wndStyleBar.SetButtonStyle(nIndex, nBarStyle);
 
   // Устанавливаем для кнопки ID_TEXT_JUSTIFY стиль 
   // TBBS_WRAPPED
   nIndex = m_wndStyleBar.CommandToIndex(ID_TEXT_JUSTIFY);
   nBarStyle = m_wndStyleBar.GetButtonStyle(nIndex) | 
               TBBS_WRAPPED;
   m_wndStyleBar.SetButtonStyle(nIndex, nBarStyle);
 
   // Отображаем панель управления Style в мини-окне.
   // Начальные координаты панели управления определяются 
   // значением объекта pointStyleBar класса CPoint 
   CPoint pointStyleBar(100, 100);
   FloatControlBar(&m_wndStyleBar, pointStyleBar);
  
//============================================================
// Создаем и отображаем панель управления Extended
//============================================================
   // Создаем панель управления Extended
   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;
   }
   
   // Загружаем ресурс панели управления Extended
   if(!m_wndExtendedBar.LoadToolBar(IDR_EXTENDED))
   {
      // Ошибка при загрузке ресурса панели управления
      TRACE0("Failed to load toolbar\n");
      return -1;
   }

   // Устанавливаем заголовок панели управления Extended
   m_wndExtendedBar.SetWindowText("Extended");      

   // Увеличиваем размер первого разделителя. 
   // Этот разделитель имеет индекс 2
   m_wndExtendedBar.SetButtonInfo(2, IDW_EDIT, 
      TBBS_SEPARATOR, 130);

   // Определяем координаты прямоугольной области панели 
   // управления, занимаемой разделителем
   CRect rectEdit;
   m_wndExtendedBar.GetItemRect(2, &rectEdit);

   // Делаем отступ с левой и правой стороны
   rectEdit.left += 6;
   rectEdit.right -= 6;
   
   // Размещаем на панели управления Extended, в области 
   // rectEdit однострочный текстовый редактор
   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;
   }

   // Увеличиваем размер второго разделителя. 
   // Этот разделитель имеет индекс 4
   m_wndExtendedBar.SetButtonInfo(4, IDW_COMBO, 
      TBBS_SEPARATOR, 150);

   // Определяем координаты прямоугольной области панели 
   // управления, занимаемой разделителем
   CRect rectComboBox;
   m_wndExtendedBar.GetItemRect(4, &rectComboBox);

   // Делаем отступ с левой и правой стороны
   rectComboBox.left += 6;
   rectComboBox.right -= 6;

   // Увеличиваем высоту прямоугольной области, чтобы в ней 
   // можно было разместить список combo-box
   rectComboBox.bottom = rectComboBox.top + 80;

   // Размещаем на панели управления Extended, в области 
   // rectComboBox список combo-box
   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;
   }

   // Добавляем три строки в список m_combo_box
   m_wndExtendedBar.m_combo_box.AddString("One");
   m_wndExtendedBar.m_combo_box.AddString("Two");
   m_wndExtendedBar.m_combo_box.AddString("Third");
   
   // Разрешаем пристывковывать панель управления Extended к 
   // любой из строн родительского окна
   m_wndExtendedBar.EnableDocking(CBRS_ALIGN_ANY );

   // Пристывковываем панель управления Extended к 
   // родительскому окну
   DockControlBar(&m_wndExtendedBar);

   return 0;
}

Ресурсы приложения MultiBar

Создайте новый файл ресурсов и включите его в проект под именем MultiBar.rc. Теперь надо создать три панели управления toolbar и включить их в файл ресурсов. Изображения кнопок панелей управления вы можете нарисовать самостоятельно или скопировать их из файла ресурсов Common.res, поставляемого вместе с Microsoft Visual C++. Более подробная информация о файле Common.res представлена в разделе “Ресурсы Microsoft”.

При создании панелей управления руководствуйтесь информацией из файла ресурсов приложения MultiBar (листинг 3.3) и изображениями кнопок панелей управления (рис. 3.3, 3.4, 3.5).

Первая панель управления должна иметь идентификатор IDR_PLAYER и содержать девять кнопок с идентификаторами ID_LEFT, ID_PLAY, ID_RIGHT, ID_STOP, ID_PAUSE, ID_EJECT, ID_TYPE, ID_CD_DRV и ID_WAVE. Между кнопками ID_RIGHT и ID_STOP, ID_PAUSE и ID_EJECT, ID_EJECT и ID_TYPE вставьте разделители. Для каждой из кнопок вы также можете ввести их текстовые описания.

Вторая панель управления должна иметь идентификатор IDR_STYLE и содержать двенадцать кнопок с идентификаторами ID_UNDERLINE, ID_2_UNDERLINE, ID_SUPERSCRIPT, ID_SUBSCRIPT, ID_TEXT_LEFT, ID_ID_TEXT_CENTER, ID_TEXT_RIGHT, ID_TEXT_JUSTIFY, ID_MARK_1, ID_MARK_2, ID_MARK_3 и ID_MARK_4. Для первых шести кнопок введите их текстовые описания.

Третья панель управления должна иметь идентификатор IDR_EXTENDED. Определите в ней четыре кнопки с идентификаторами ID_FOTO, ID_PRINTER, ID_ADD и ID_DISK. Между кнопками ID_PRINTER и ID_ADD, а также ID_ADD и ID_DISK вставьте разделители. Введите текстовые описания кнопок.

В файл ресурсов, кроме панелей управления toolbar, включите меню IDR_MENU с тремя строками Style, Extended и Player, которые имеют идентификаторы ID_Style, ID_Extended и ID_Player. Обратите внимание, что идентификаторы строк меню соответствуют идентификаторам панелей управления.

Файл ресурсов приложения MultiBar мы привели в листинге 3.8. В нем определены ресурсы панелей управления toolbar с идентификаторами IDR_PLAYER, IDR_STYLE и IDR_EXTENDED, ресурсы изображений этих панелей управления с соответствующими идентификаторами, меню приложения, а также несколько строковых ресурсов с описаниями кнопок панелей управления. Идентификаторы строковых ресурсов соответствуют идентификаторам кнопок панелей управления, которые они описывают.

Листинг 3.8. Файл MultiBar.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

//////////////////////////////////////////////////////////////
//
// Toolbar
//

IDR_PLAYER TOOLBAR DISCARDABLE  16, 15
BEGIN
    BUTTON      ID_LEFT
    BUTTON      ID_PLAY
    BUTTON      ID_RIGHT
    SEPARATOR
    BUTTON      ID_STOP
    BUTTON      ID_PAUSE
    SEPARATOR
    BUTTON      ID_EJECT
    SEPARATOR
    BUTTON      ID_TYPE
    BUTTON      ID_CD_DRV
    BUTTON      ID_WAVE
END

IDR_STYLE TOOLBAR DISCARDABLE  16, 15
BEGIN
    BUTTON      ID_UNDERLINE
    BUTTON      ID_2_UNDERLINE
    BUTTON      ID_SUPERSCRIPT
    BUTTON      ID_SUBSCRIPT
    BUTTON      ID_TEXT_LEFT
    BUTTON      ID_ID_TEXT_CENTER
    BUTTON      ID_TEXT_RIGHT
    BUTTON      ID_TEXT_JUSTIFY
    BUTTON      ID_MARK_1
    BUTTON      ID_MARK_2
    BUTTON      ID_MARK_3
    BUTTON      ID_MARK_4
END

IDR_EXTENDED TOOLBAR DISCARDABLE  16, 15
BEGIN
    BUTTON      ID_FOTO
    BUTTON      ID_PRINTER
    SEPARATOR
    BUTTON      ID_ADD
    SEPARATOR
    BUTTON      ID_DISK
END

//////////////////////////////////////////////////////////////
//
// Bitmap
//

IDR_PLAYER              BITMAP  DISCARDABLE     "player.bmp"
IDR_STYLE               BITMAP  DISCARDABLE     "style.bmp"
IDR_EXTENDED            BITMAP  DISCARDABLE     "extended.bmp"

//////////////////////////////////////////////////////////////
//
// Menu
//

IDR_MENU MENU DISCARDABLE 
BEGIN
    POPUP "View"
    BEGIN
        MENUITEM "Style",                       ID_Style
        MENUITEM "Extended",                    ID_Extended
        MENUITEM "Player",                      ID_Player
    END
END

//////////////////////////////////////////////////////////////
//
// String Table
//

STRINGTABLE DISCARDABLE 
BEGIN
    ID_LEFT              "Rewind to begin\nRewind to begin"
    ID_RIGHT             "Rewind to end\nRewind to end"
    ID_PLAY              "Play\nPlay"
    ID_STOP              "Stop\nStop"
    ID_PAUSE             "Pause\nPause"
    ID_EJECT             "Eject\nEject"
    ID_TYPE              "Type drive\nType"
    ID_CD_DRV            "CD drive\nCD"
    ID_BUTTON40010       "Wave/nWave File"
    ID_WAVE              "Wave file\nWAWE"
    ID_UNDERLINE         "Underline\nUnderline"
    ID_2_UNDERLINE       "Double underline\nDouble underline"
    ID_SUPERSCRIPT       "Superscript\nSuperscript"
    ID_SUBSCRIPT         "Subscript\nSubscript"
END

STRINGTABLE DISCARDABLE 
BEGIN
    ID_ADD               "Add from edit-box item to combo-
                          box\nAdd item to list"
END

STRINGTABLE DISCARDABLE 
BEGIN
    ID_TEXT_LEFT         "Left text\nLeft"
    ID_ID_TEXT_CENTER    "Center text\nCenter"
    ID_TEXT_RIGHT        "Right text\nRight"
    ID_TEXT_JUSTIFY      "Justify text\nJustify"
    ID_FOTO              "Foto\nFoto"
    ID_PRINTER           "Printer\nPrinter"
    ID_DISK              "Disk\nDisk"
END

STRINGTABLE DISCARDABLE 
BEGIN
    IDW_EDIT             "Edit\nEdit"
    IDW_COMBO            "Combo box\nCombo box"
END

#endif    // Russian resources
//////////////////////////////////////////////////////////////

#ifndef APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
// Generated from the TEXTINCLUDE 3 resource.
//

//////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

Изображения кнопок панелей управления располагаются в отдельных файлах player.bmp (рис. 3.14), style.bmp (рис. 3.15) и extended.bmp (рис. 3.13) в главном каталоге проекта. Файлы изображений панелей управления содержат только изображения кнопок. В них не представлены разделители и дополнительные органы управления.

В принципе, изображения панели управления можно редактировать в любом графическом редакторе, который работает с 16-цветными изображениями в формате BMP. Примером такого приложения является графический редактор Microsoft Paint, поставляемый вместе с операционными системами Windows 95 и Windows NT версии 4.0. Однако, лучше использовать редактор ресурсов среды Microsoft Visual C++, так как он не только разрешает редактировать существующие кнопки, но также позволяет добавлять новые кнопки вместе с соответствующими идентификаторами и строковыми ресурсами.

Рис. 3.13. Изображение кнопок панели управления Extended

Рис. 3.14. Изображение кнопок панели управления Player

Рис. 3.15. Изображение кнопок панели управления Style

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

Мы привели исходный текст файла resource.h в листинге 3.9.

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


//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by MultiBar.rc
//
#define IDW_EDIT                        101
#define IDW_COMBO                       102
#define IDR_PLAYER                      103
#define IDR_STYLE                       105
#define IDR_EXTENDED                    107
#define IDR_MENU                        109
#define ID_LEFT                         40001
#define ID_RIGHT                        40002
#define ID_PLAY                         40003
#define ID_STOP                         40004
#define ID_PAUSE                        40005
#define ID_EJECT                        40007
#define ID_TYPE                         40008
#define ID_CD_DRV                       40009
#define ID_WAVE                         40011
#define ID_UNDERLINE                    40012
#define ID_2_UNDERLINE                  40013
#define ID_SUPERSCRIPT                  40014
#define ID_SUBSCRIPT                    40015
#define ID_TEXT_LEFT                    40017
#define ID_ID_TEXT_CENTER               40018
#define ID_TEXT_RIGHT                   40019
#define ID_TEXT_JUSTIFY                 40020
#define ID_MARK_1                       40021
#define ID_MARK_2                       40022
#define ID_MARK_3                       40023
#define ID_MARK_4                       40024
#define ID_FOTO                         40025
#define ID_PRINTER                      40026
#define ID_DISK                         40027
#define ID_Style                        40029
#define ID_Extended                     40030
#define ID_Buttons                      40031
#define ID_Player                       40031
#define ID_ADD                          40032

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        110
#define _APS_NEXT_COMMAND_VALUE         40033
#define _APS_NEXT_CONTROL_VALUE         1000
#define _APS_NEXT_SYMED_VALUE           103
#endif
#endif

Панели управления приложения MultiBar

Постройте приложение MultiBar и запустите его. На экране появится главное окно приложения MultiBar, в котором отображаются сразу три панели управления - Extended, Player и Slyle. Панели управления Extended и Player присоединены к верхней и нижней границам окна, а панель управления Slyle отображается в отдельном мини-окне (рис. 3.16).

Рис. 3.16. Приложение MultiBar

Приложение MultiBar имеет меню View, состоящее из названий панелей управления Extended, Player и Slyle. Выбирая из меню View названия панелей управления, вы можете убрать их с экрана и опять отобразить (закрыть и открыть).

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

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

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

При нажатии на кнопки панели управления Player на экране появляется сообщение, о том, что команда не поддерживается. Обратите внимание на кнопки Pause, Type, CD и WAVE.

Кнопка Pause работает как переключатель. Если вы на нее нажмете - она остается в нажатом положении до тех пор, пока вы не нажмете на нее еще один раз. Кнопки Type, CD и WAVE работают вместе как переключатель с зависимой фиксацией. Одновременно может быть нажата только одна из этих кнопок.

Панель управления Player можно присоединить к трем из четырех сторон главного окна приложения - к верхней, левой и нижней. К правой стороне окна панель Player не присоединяется (рис. 3.17). Вы также можете использовать для панели Player отдельное мини окно, форму которого можно изменять.

Рис. 3.17. Изменение формы панели управления Player

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

Панель Extended демонстрирует использование в панелях управления toolbar дополнительных органов управления - поля редактирования и списка combo-box. Сразу после запуска приложения MultiBar в списке combo-box содержатся три строки - First, Second и Third. В поле редактирования можно ввести новые строки для этого списка. После того, как вы наберете строку, нажмите кнопку . Введенная строка появится в конце списка combo-box.

На рисунке 3.18 мы показали внешний вид панели управления Extended с открытым списком combo-box, после того как в нее добавлена строка Fifth.

Рис. 3.18. Новая строка в списке combo-box

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

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

Панель управления Slyle отображается исключительно в отдельном мини-окне. Вы не сможете пристыковать ее ни к одной из сторон главного окна приложения MultiBar. Кнопки панели управления Slyle отображаются в три ряда по четыре кнопки в каждом ряду. В отличие от панелей управления Extended и Player, форма панели управления Slyle не изменяется.

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

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

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

Главный класс приложения 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 более подробно.

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

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

Чтобы разрешить перемещение панелей управления, вызываем метод EnableDocking для главного окна приложения. Чтобы разрешить присоединение панелей управления ко всем сторонам окна, передаем методу EnableDocking значение CBRS_ALIGN_ANY XE "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 XE "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);
Команды панелей управления

Каждый раз когда пользователь нажимает на кнопки в панели управления или работает с дополнительными органами управления (текстовым редактором и списком 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 использует этот идентификатор, чтобы определить какая строка меню была выбрана.

Методы BarCommandOne и BarCommandRange класса CMultiBarWindow

Методы BarCommandOne и BarCommandRange определены в классе главного окна приложения CMultiBarWindow и используются для обработки сообщений от кнопок панелей управления.

Фактически методы BarCommandOne и BarCommandRange не выполняют никакой полезной работы. Единственное, что делает метод BarCommandOne, - это отображает на экране сообщение о том, что выбранная вами команда не реализована. Для этого мы используем метод MessageBox:


void CMultiBarWindow::BarCommandOne()
{
   // Отображаем сообщение о том, что команда не реализована
   MessageBox("Command not implemented");	
}

Метод BarCommandRan

ge вообще не выполняет никакой полезной работы. Однако не спешите исключать его из программы. Если вы удалите методы BarCommandOne и BarCommandRange из программы и удалите соответствующие макрокоманды из таблицы сообщений класса окна, тогда все кнопки, для обработки сообщений от которых использовались эти методы, окажутся заблокированы. MFC определит, что сообщения от кнопок не обрабатываются и запретит их использование:

void CMultiBarWindow::BarCommandRange( UINT nID ) { // Обработчик не выполняет никакой работы }
Метод 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);
}
[Назад] [Содеожание] [Дальше]