Когда панель инструментов инициализирована, ее размеры устанавливаются соответственно текущим размерам родительского окна. Но если размер окна изменяется, то размер панели инструментов автоматически изменяться не будет. Особых неприятностей это не причиняет, однако при увеличении окна панель инструментов может оказаться слишком маленькой. Для решения этой проблемы необходимо посылать сообщение TB_AUTOSIZE панели инструментов каждый раз, когда изменяются размеры родительского окна. Проще всего это сделать при обработке сообщения WM_SIZE:
SendMessage(hwndToolBar. TB_AUTOSIZE. 0. 0);
Реакция панели инструментов на это сообщение определяется флагами ее стиля (см. табл. 8.7). Например, панель инструментов со стилем CCSJT0P устанавливает свое местоположение и размеры. С другой стороны, панель инструментов со стилем CCS_NORESIZE игнорирует это сообщение и требует явной установки ее местоположения и размеров.
В главном меню Visual Studio выполните команду Insert ► Resource. В появившемся диалоговом окне Insert Resource укажите тип ресурса Toolbar и нажмите кнопку New. В результате будет открыто окно редактора панели инструментов с заготовкой растрового образа панели инструментов, содержащего первую и пока единственную кнопку .
По умолчанию редактор присваивает растровому образу панели инструментов идентификатор IDR_T00LBAR1. Если вы хотите изменить назначенный идентификатор, то на вкладке ResourceView в окне Workspace сделайте щелчок правой кнопкой мыши на элементе IDR_T00LBAR1 и в появившемся контекстном меню выберите пункт Properties. В открывшемся диалоговом окне Toolbar Properties введите в окне редактирования ID нужный идентификатор.
В нашем проекте можно оставить предложенный редактором идентификатор ресурса IDRJTJOLBARl.
В верхней части окна находится изображение создаваемой панели инструментов. В левой нижней части располагается изображение растра для текущей кнопки в натуральную величину, а в правой нижней части — увеличенное изображение растра для текущей кнопки. Растр для каждой кнопки имеет размеры 16 х 15 пикселов.
Для создаваемой кнопки нужно нарисовать картинку и определить идентификатор кнопки.
Пользуясь инструментами рисования на панели Graphics, создайте нужный рисунок на кнопке так же, как это делалось для пиктограмм. После этого сделайте двойной щелчок мышью на изображении кнопки в верхней части окна редактора. В открывшемся диалоговом окне Toolbar Button Properties введите нужный идентификатор кнопки. Если кнопка дублирует некоторый пункт меню, то идентификатор кнопки должен быть таким же, как и у дублируемого пункта меню.
Допустим, что вы нарисовали на кнопке изображение прямоугольника и указали ее идентификатор ID_RECTANGLE. После выполненных операций редактор панелей инструментов автоматически создает следующую кнопку, расположенную правее от последней кнопки.
Щелкнув на новой кнопке мышью, можно перейти в режим редактирования этой кнопки, повторяя описанные выше действия.
Если текущая кнопка используется как кнопка-разделитель между группами кнопок, то изображение на ней создавать не нужно. В качестве идентификатора кнопок-разделителей в рассматриваемом примере будет использоваться именованная константа ID_SEP (вы можете использовать любое другое имя).
Если нужно изменить порядок размещения уже созданных кнопок, то это можно сделать при помощи мыши, ухватившись за перемещаемую кнопку и перетащив ее в нужную позицию. Для удаления созданной ранее кнопки просто схватите ее мышью и переместите за пределы изображения панели инструментов.
Создайте новый проект с именем ToolBar. Скопируйте из папки проекта MenuDemol (см. листинг 6.1) в папку проекта ToolBar файлы с расширениями .срр, .h и .гс, скорректировав их имена заменой MenuDemol на ToolBar. Добавьте эти файлы в состав проекта.
Укажите имя библиотеки comctl32.lib в настройках компоновщика в проекте. В среде Visual Studio 6.0 эти настройки находятся на вкладке Link диалогового окна Project Settings, которое открывается при помощи команды меню Project ► Settings.
Панель инструментов — это дочернее окно, обычно расположенное под меню приложения и содержащее одну или несколько кнопок. Когда пользователь щелкает мышью на кнопке панели инструментов, она посылает сообщение WM_C0MMAND своему родительскому окну. Традиционно кнопки панели инструментов соответствуют некоторым пунктам в меню приложения, обеспечивая более удобный способ доступа пользователя к командам меню. Следует отметить, что в простых приложениях меню может отсутствовать, а все необходимые команды могут быть реализованы с помощью панели инструментов.
Кнопки панели инструментов сами по себе не являются окнами. Они реализованы как графические объекты, нарисованные на поверхности окна панели инструментов. Изображения на кнопках поясняют их назначение. Иногда помимо изображения кнопка может содержать текстовую метку, расположенную или правее, или ниже картинки.
Панель инструментов устанавливает одинаковые размеры всех кнопок, а в случае наличия текстовых меток определяет размеры так, чтобы разместить самый длинный текст. Поэтому для текстовых меток следует выбирать короткие строки, иначе кнопки могут получиться слишком большими. В большинстве случаев кнопки на панелях инструментов содержат только растровые изображения, а назначение кнопок поясняется с помощью всплывающих окон подсказок.
Чтобы сделать интерфейс панели инструментов более удобным для пользователя, кнопки часто объединяют в группы. Кнопки, объединенные в группу, следуют одна за другой, а между группами остается небольшой промежуток. Такие промежутки реализуются при помощи кнопок стиля TBSTYLE_SEP, называемых кнопками-разделителями.
Кроме кнопок, панель инструментов может содержать и другие дочерние окна элементов управления, такие, как, например, комбинированный список {combo box). Встроенные элементы управления создаются при помощи функции CreateWindow.
Для добавления к приложению панели инструментов необходимо выполнить следующую последовательность действий:
1. Определить ресурс растрового образа панели инструментов.
2. Объявить и инициализировать массив структур типа TBBUTT0N, содержащий информацию о кнопках панели инструментов.
3. Вызвать функцию CreateToolBarEx для создания и инициализации панели инструментов.
Рассмотрим реализацию этих шагов на примере разработки приложения ToolBar, представляющего собой модифицированную версию программы MenuDemol, описанной в главе 6. В результате модификации к интерфейсу приложения будет добавлена панель инструментов, дублирующая некоторые команды меню.
После создания элемента управления общего пользования приложение управляет его действиями, посылая необходимые сообщения при помощи функции SendMessage. Для каждого типа элемента управления существуют свои специфические сообщения.
Альтернативой вызовам функции SendMessage является использование набора макросов, определенных в файле commctrl.h.
Например, для добавления элемента в дерево просмотра (Tree view) с дескриптором hwndTV необходимо послать элементу управления сообщение TVM_INSERTITEM. Это можно реализовать следующим вызовом функции SendMessage:
hltem = (HTREEITEM)SendMessage(hwndTV, TVMJNSERTITEM. 0. (LPARAMHLPTVJNSERTSTRUCT) &tvis);
Однако то же самое сообщение можно послать, используя макрос Tree View_ Insertltem:
hltem - TreeView_InsertItem (hwndTV, Stvis);
Как видно, текст с макросом выглядит значительно проще для чтения.
К сожалению, файлы Win32 содержат определения макросов не для всех элементов управления общего пользования. В файле commctrLh находятся определения макросов только для элементов управления Tab control, Tree view, List view, Animation и Header. Файл prsht.h содержит определения макросов для элемента управления Property sheet.
Как и базовые элементы управления, элементы управления общего пользования посылают своему родительскому окну уведомляющие сообщения, содержащие информацию о произошедших событиях. Но если базовые элементы управления используют сообщение WM_COMMAND, то элементы управления общего пользования обычно посылают уведомления при помощи сообщений WM_N0TIFY.
Однако не все уведомления реализуются подобным образом. Например, панель инструментов, использующая сообщение WM_N0TIFY для большинства уведомлений, посылает сообщение WM_COMMAND, когда пользователь нажимает одну из кнопок. Дело в том, что панель инструментов обычно дублирует команды меню, поэтому имеющийся код обработки сообщений WM_COMMAND от команд меню будет одновременно обрабатывать и сообщения от кнопок панели инструментов.
Еще одно исключение составляют полосы прокрутки элементов управления Slider и Spin, которые посылают сообщение WM_VSCROLL или WM_HSCROLL
Хотя каждый элемент управления общего пользования имеет свой собственный набор кодов уведомления, существует набор уведомлений, общий для всех элементов.
Независимо от способа создания — с помощью CreateWindow или специализированной функции — при вызове соответствующей функции необходимо задать набор стилей элемента управления.
Флаги стилей можно разделить на следующие четыре категории: флаги основного стиля окна (с префиксом WS_)', флаги расширенного стиля окна (WS_EX_)2, флаги основного стиля элемента управления общего пользования (CCS_) и флаги стиля, специфичные для конкретного элемента управления.
Библиотека элементов управления общего пользования поддерживает набор значений стиля с префиксом CCS_. Они применяются для панелей инструментов, строк состояния и заголовков списка просмотра.
Наиболее традиционным способом создания элемента управления общего пользования является вызов функции CreateWindow или CreateWindowEx. Например, приведенный вызов создает панель инструментов:
HWND hwndToolBar = CreateWindowCTQOLBARCLASSNAME. NULL, WS_CHILD |
WS_VISIBLE | WS_B0RDER, 0. 0. 16, 16, hwndParent. (HMENU)l. hlnst, 0);
Имя оконного класса TOOLBARCLASSNAME здесь задается без кавычек, поскольку это именованная константа, определение которой зависит от набора символов, выбранного при построении программы. Для набора символов ANSI имя TOOLBARCLASSNAME заменяется строковой константой ToolbarWindow32, для набора символов UNICODE — строковой константой L"ToolbarWindow32". Имена других оконных классов элементов управления общего пользования определяются аналогично.
Обычно элементы управления общего пользования создаются как дочерние окна, что определяется флагом WS_CHILD и передачей дескриптора родительского окна hwndParent.
Альтернативой вызову функции CreateWindow является вызов специализированной функции создания элемента управления, которая в то же время может выполнять некоторую стандартную инициализацию. Например, панель инструментов может быть создана функцией CreateToolBarEx.
Для некоторых элементов управления соответствующие оконные классы не определены. Такие элементы управления могут быть созданы только с помощью специализированных функций. В табл. 8.6 приведены сведения об оконных классах и специализированных функциях создания для элементов управления общего пользования.
Большинство элементов управления общего пользования реализовано в виде окна соответствующего предопределенного класса. С этой точки зрения элементы управления общего пользования похожи на базовые элементы управления. И те, и другие элементы могут быть созданы вызовом функции CreateWindow, которой передаются конкретные флаги стиля класса. И те, и другие элементы управляются специфичными для данного класса сообщениями и приводятся к нужному состоянию при помощи известных функций, манипулирующих окнами. Оба типа элементов управления посылают уведомляющие сообщения родительскому окну, информируя его обо всех происходящих событиях.
Разница между базовыми элементами управления и элементами управления общего пользования состоит в типе посылаемых уведомительных сообщений. Базовые элементы управления посылают сообщения WM_COMMAND, а элементы управления общего пользования почти всегда посылают сообщения WM_N0TIFY.
Каждая новая версия системы Windows предлагала улучшенный вариант пользовательского интерфейса. Чтобы упростить создание приложений, в которых используются одинаковые элементы интерфейса, Microsoft разработала библиотеку элементов управления общего пользования (common control library). Новые элементы управления, включенные в эту библиотеку, дополняют базовые элементы управления, рассмотренные в предыдущей главе, и придают программам более совершенный вид. Библиотека элементов управления общего пользования реализована в виде динамически загружаемой библиотеки comctl32.dll.
Элементы управления общего пользования можно разделить на четыре категории, в которые входят элементы управления главного окна, составные диалоговые элементы управления, элементы управления Windows Explorer и иные дополнительные элементы управления.
Одна из важнейших целей, поставленных перед разработчиками системы Windows, заключалась в том, чтобы способствовать разработке приложений со стандартизированным интерфейсом пользователя. Для многих общепринятых пунктов меню это было сделано довольно быстро. Почти все разработчики программного обеспечения стали использовать последовательность команд File ► Open (Файл ► Открыть) для вызова диалогового окна, при помощи которого пользователь мог открыть файл. Однако сами окна диалога для открытия файла часто были не очень похожи друг на друга.
Начиная с версии Windows 3.1, решение этой проблемы было реализовано в виде библиотеки диалоговых окон общего пользования {Common Dialog Box Library). Библиотека содержит несколько функций, которые вызывают стандартные окна диалога для открытия и сохранения файлов, поиска и замены, выбора цвета, выбора шрифта и другие стандартные окна.
Для каждой функции, создающей и вызывающей стандартное диалоговое окно, в заголовочном файле commdlg.h определен соответствующий тип структуры. Чтобы работать со стандартным диалогом, вы должны определить подходящую структурную переменную и инициализировать ее. После этого вызывается функция стандартного диалога, которой передается адрес этой структурной переменной. Когда пользователь закрывает окно диалога, вызванная функция возвращает управление программе. В этот момент вы можете получить требуемую информацию из указанной структурной переменной.
В демонстрационном приложении CommonDialogs, которое мы сейчас разработаем, иллюстрируется, как можно использовать стандартные диалоговые окна Open (Открыть), Save As (Сохранить как), Color (Цвет) и Font (Шрифт).
Создайте новый проект с именем CommonDialogs.