Глава
16. Панель управленияПанель управления обычно располагается в верхней части главного окна приложения. Она содержит ряд кнопок, дублирующих функции некоторых строк меню.
Если приложение имеет сложную систему управления, то создание для каждой строки меню отдельной кнопки в одной панели управления нецелесообразно, так как количество кнопок может быть достаточно велико. Для решения этой проблемы обычно создают несколько панелей управления, которые пользователь может открывать и закрывать по своему усмотрению.
Панель управления является отдельным ресурсом, таким же как меню или шаблон диалоговой панели. Каждая кнопка панели управления имеет свой идентификатор
ID, обычно такой же как и соответствующий пункт меню, который эта кнопка дублирует.В панели управления можно задавать разделители (
SEPARATOR), при помощи которых кнопки разделяются на группы по смыслу. Каждая кнопка и каждый разделитель в панели управления имеют свой собственный индекс. Этот индекс соответствует порядковому номеру, под которым кнопка или разделитель отображаются на экране.Ресурсы панели управления
Каждый ресурс, представляющий панель управления в редакторе ресурсов
Microsoft Visual C++, выступает как единое целое, позволяя одновременно изменять внешний вид кнопок, задавать их идентификаторы и строки описания. В исходном же файле ресурсов приложения ресурс панели управления состоит из трех частей.Первая часть описывает панель управления, например
: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 END
В данном фрагменте описывается панель управления с идентификатором
IDR+MAINFRAME. В блоке BEGIN-END при помощи ключевого слова BUTTON идет описание каждой кнопки панели управления, где задается идентификатор кнопки. Ключевое слово SEPARATOR означает, что между кнопками, разделенными строкой SEPARATOR, увеличивается расстояние. За счет этого достигается эффект разделения кнопок на группы.В первой части ресурса панели управления отсутствует изображения кнопок. Они располагаются отдельно и представляют вторую часть ресурса. Все кнопки представлены одним
bitmap-изображением, имеющим тот же идентификатор, что и соответствующий ресурс TOOLBAR, например :IDR_MAINFRAME BITMAP MOVEABLE PURE "res\Toolbar.bmp"
Все изображения кнопок расположены последовательно одна за другой в изображении
Toolbar.bmp. Порядок, в котором они расположены, должен соответствовать порядку, в котором кнопки описаны в ресурсе TOOLBAR, и порядку, в котором они будут отображаться на экране. Между отдельными изображениями кнопок должны отсутствовать промежутки, даже если в описании ресурса TOOLBAR присутствуют разделители SEPARATOR.Для каждой кнопки можно ввести описывающую ее текстовую строку. Эти строковые ресурсы и хранятся в третьей, необязательной части ресурса панели управления.
Соответствие строковых ресурсов кнопкам панели управления достигается за счет присвоения им одинаковых идентификаторов, например
:STRINGTABLE DISCARDABLE BEGIN …….. ID_FILE_NEW "Create a new documentnNew" ….…. END
Надо отметить, что строки описания некоторых кнопок могут отсутствовать или, наоборот, использоваться еще и в других ресурсах, например, в описании ресурсов меню.
Создание панели управления
Для работы с панелями управления в состав библиотеки
MFC включены два класса - CToolBar и CDialogBar . Они оба наследуются от базового класса CControlBar , реализующего основные функции панели управления. Кроме того, от базового класса наследуется еще один класс - CStatusBar . Он предназначен для работы с панелью состояния и будет рассматриваться позже.Класс
CToolBar представляет панель управления, состоящую из кнопок . При желании можно в панель управления класса CToolBar помимо кнопок включить и другие органы управления, например, списки или поля редактирования, однако такая возможность требует дополнительного программирования. Если необходимо создать панель, содержащую различные органы управления , а не только кнопки, то удобнее воспользоваться классом CDialogBar . Этот класс позволяет создать панель управления на основе шаблона диалоговой панели и будет рассматриваться позже.Кнопки панели управления могут работать как кнопки, как переключатели и как переключатели с зависимой фиксацией (радио-кнопки). Тип кнопок панели управления выбирается методами класса
CToolBa r, например, метод SetButtonStyle .Чтобы создать панель управления, необходимо сначала определить объект класса
CToolBar , который будет представлять данную панель. Можно создать объект и нового класса, наследованного от CToolBar , в котором новыми дополнительными методами расширяются возможности класса CToolBar .Обычно объект
CToolBar включают как элемент главного окна приложения, например как элемент класса, наследованного от класса CFrameWnd (или CMDIFrameWnd - в зависимости от интерфейса приложения), например :class CMainFrame : public CMDIFrameWnd { protected: CToolBar m_wndToolBar; // панель управления // другие описания класса ....... };
После того, как объект класса
CToolBar образован, следует вызвать для него метод Create , который создает панель управления :BOOL Create( CWnd* pParentWnd, DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP, UINT nID = AFX_IDW_TOOLBAR );
В качестве параметров методу
Create указываются различные характеристики создаваемой панели. Только первый параметр является обязательным - в нем указывается идентификатор родительского окна для панели управления.Необязательный параметр
dwStyle определяет, как будет отображаться панель управления. Рассмотрим некоторые флаги, комбинации которых можно использовать для задания характеристик панели :- 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” используется метод OnUpdateControlBarMenu класса CFrameWnd. Причем этот метод может управлять отображением панели управления, если только она имеет идентификатор AFX_IDW_TOOLBAR.После создания панели управления методом
Create , необходимо загрузить ресурс панели управления. Для этого предназначен метод LoadToolBar . В качестве параметра этому методу следует указать или имя ресурса панели управления, либо идентификатор ресурса панели управления.Во время создания панели управления можно указать ее характеристики. Эти характеристики можно изменить прямо во время работы приложения с помощью метода
SetBarStyle класса CControlBar. Параметр этого метода задает новые характеристики панели управления. В качестве этого параметра можно использовать комбинации флагов, некоторые из которых описаны ниже :- CBRS_ALIGN_TOP - панель можно отобразить в верхней части окна.
- CBRS_ALIGN_BOTTOM - панель можно отобразить в нижней части окна.
- CBRS_ALIGN_LEFT - панель можно отобразить в левой части окна.
- CBRS_ALIGN_RIGHT - панель можно отобразить в правой части окна.
- CBRS_ALIGN_ANY - панель можно отобразить в любой части окна.
- CBRS_TOOLTIPS - краткое описание кнопки отображается в окне tool tips.
- CBRS_FLYBY - панель состояния отображает краткое описание выбранной кнопки.
Для определения текущих характеристик панели управления используется метод GetBarStyle класса CControlBar.
Форм а панели и режимы работы кнопок
Панель управления может иметь постоянную форму, которую пользователь не в состоянии изменить, или может быть динамически изменяемой. В этом случае пользователь может менять форму панели управления с помощью мыши.
Возможность или невозможность изменить форму панели управления определяется методом
Create класса CToolBar . Флаг CBRS_SIZE_DYNAMIC позволяет изменять форму панели, а флаг CBRS_SIZE_FIXED запрещает это делать. Изменить эти характеристики можно динамически при помощи метода SetBarStyle.В состав класса
CToolBar входит метод SetButtonStyle . Этот метод позволяет установить режим работы кнопок панели управления, сгруппировав несколько кнопок вместе. Через первый параметр передается индекс кнопки или разделителя в панели управления, а второй параметр позволяет установить новый режим работы. Индекс кнопки или разделителя соответствует их порядковому номеру в панели управления. В качестве второго параметра можно указать комбинацию нескольких флагов :- TBBS_BUTTON - стандартная кнопка.
- TBBS_SEPARATOR - разделитель.
- TBBS_CHECKBOX - переключатель
- TBBS_GROUP - с данной кнопки начинается группа кнопок.
- TBBS_CHECKGROUP - с данной кнопки начинается группа переключателей.
- TBBS_WRAPPED - позволяет создать панель управления, в которой кнопки расположены в несколько рядов. Рекомендуется установить этот флаг для самых последних кнопок в каждом ряду. Кнопка, следующая за кнопкой с установленным флагом TBBS_WRAPPED, отображается в новом ряду.
Определить текущий режим кнопки или разделителя можно при помощи метода GetButtonStyle класса CToolBar .
Индекс, или порядковый номер, любой кнопки панели управления можно определить по ее идентификатору. Для этого предназначен метод
CommandToIndex класса CToolBar . Обратную задачу - по индексу кнопки возвращает ее идентификатор - выполняет метод GetItemID .Полож ение панели управления
Для того, чтобы пользователь мог сам перемещать панель управления с одной границы экрана на другую или разместить ее в отдельном окне, необходимо сделать следующие действия
:- Разрешить перемещение панели управление для окна, которое содержит панель управления, вызовом метода EnableDocking данного окна (этот метод является элементом класса CFrameWnd ).
- Разрешить такое перемещение для самой панели управления методом EnableDocking панели управления (этот метод является элементом класса CControlBa r).
- Переместить панель управления к одной из сторон приложения или вывести ее в отдельном окне. Для этого необходимо вызвать метод DockControlBar или FloatControlBar данного окна приложения (эти методы являются элементами класса CFrameWnd ).
Если не выполнить хотя бы один пункт из этих трех перечисленных выше, панель управления будет жестко привязана к одной из границ окна.
Пример создания панели управления
Обычно создание панели управления и разрешение перемещения панели управления производят при обработке сообщения
WM_CREATE для главного окна приложения, например :int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // вызов метода базового класса для корректного создания окна if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // разрешить присоединение панелей ко всем сторонам окна EnableDocking(CBRS_ALIGN_ANY); // создание панели управления if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) return -1; // установить характеристики панели управления m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); // разрешить присоединить панель к любой строке родительского окна m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); // присоединить панель управления к родительскому окну DockControlBar(&m_wndToolBar); // создание панели состояния (процесс создания рассматривается ниже) ……… return 0; }
Сообщения от панели управления (от ее кнопок) приходят окну приложения - родительскому окну, в котором размещена эта панель. Поэтому следует добавить в таблицу класса окна соответствующие макрокоманды для получения сообщений от кнопок и включить в класс окна методы для обработки этих сообщений.
Обычно для создания панели управления вызывается метод
Create класса CToolBar во время создания окна приложения. В принципе, панель управления можно создать и позже, когда окно уже отображено на экране. Однако, нужно отметить, что в этом случае панель управления возникает не сразу - чтобы панель появилась, необходимо еще изменить размер окна. Оказывается , метод Create класса CToolBar устанавливает нулевой размер окна панели управления. Настоящий размер панели выбирается позже, в зависимости от ее характеристик, а также размеров и характеристик родительского окна.Чтобы установить правильные размеры и расположение панели управления, следует вызвать метод
RecalcLayout . Он входит в класс CFrameWnd и вызывается автоматически, если используются методы CFrameWnd::ShowControlBar, CFrameWnd::FloatControlBar, CMDIChildWnd::Create , а также некоторые другие.Дополнительные возможности панели упра вления
Панель управления, созданная на основе класса
CToolBar, состоит из одних только кнопок или разделителей. Стандартные средства для отображения в ней других элементов управления отсутствуют.Однако, так как панель управления является не чем иным, как дочерним окном, можно самостоятельно разместить в нем другие элементы управления. Для этого предполагается сделать следующие шаги
:- В том месте ресурса панели управления TOOLBAR, где предполагается вставить дополнительный орган управления, следует вставить разделитель SEPARATOR.
- Сразу после создания панели управления необходимо изменить размер разделителя, вместо которого надо вставить другой элемент управления, и присвоить ему другой идентификатор.
- Создать на месте разделителя нужный элемент управления, указав для него в качестве родительского окна идентификатор панели управления.
В класс CToolBar входит метод SetButtonInfo . Этот метод позволяет изменить внешний вид панели управления. Используя этот метод, можно изменить идентификатор, изображение, режим работы и размер разделителей кнопок панели управления. Для определения текущих характеристик кнопок панели можно воспользоваться методом GetButtonInfo класса CToolBar .
Когда на панели создается дополнительный элемент управления, то необходимо указать координаты прямоугольной области, которую он будет занимать. Для определения этих координат следует воспользоваться методом
GetItemRect класса CToolBar . Вызов этого метода заполняет структуру типа RECT координатами прямоугольной области, занимаемой кнопкой или разделителем, с индексом nIndex.Рассмотрим пример создания панели управления с дополнительными элементами - полем редактирования и выпадающим списком. Предварительно создадим два новых идентификатора
ID_EDIT и ID_COMBO:#define ID_EDIT 101 #define ID_COMBO 102
Затем необходимо создать новый класс панелей управления на базе класса
CToolBar библиотеки MFC:class CExtendedBar : public CToolBar { public: // дополнительные элементы управления CEdit m_edit; CComboBox m_combo; };
Далее в классе главного окна приложения следует объявить объект этого нового класса
:class CMainFrame : public CMDIFrameWnd { protected: CExtendedBar m_wndToolBar; // расширенная панель управления // другие описания класса .....…. };
Затем создаем панель управления и добавляем в нее дополнительные элементы при обработке сообщения
WM_CREATE для главного окна приложения :int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // вызов метода базового класса для корректного создания окна if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // разрешить присоединение панелей ко всем сторонам окна EnableDocking(CBRS_ALIGN_ANY); // создание панели управления if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) return -1; // увеличим размер первого разделителя (его индекс 3) m_wndToolBar.SetButtonInfo(3,ID_EDIT,TBBS_SEPARATOR,130); // определяем координаты области, занимаемой разделителем CRect rEdit; m_wndToolBar.GetItemRect(3,&rEdit); rEdit.left+=6; rEdit.right-=6; // отступы // создаем и размещаем однострочный редактор текста if(!(m_wndToolBar.m_edit.Create(WS_CHILD| ES_AUTOHSCROLL|WS_VISIBLE|WS_TABSTOP| WS_BORDER,rEdit,&m_wndToolBar,ID_EDIT))) return -1; // вводим ограничение на количество вводимых символов m_wndToolBar.m_edit.SetLimitText(10); // увеличим размер второго разделителя (его индекс 7) m_wndToolBar.SetButtonInfo(7,ID_COMBO,TBBS_SEPARATOR,130); // определяем координаты области, занимаемой разделителем CRect rCombo; m_wndToolBar.GetItemRect(7,&rCombo); rCombo.left+=6; rCombo.right-=6; // отступы rCombo.bottom+=60; // для списка пунктов // создаем и размещаем выпадающий список if(!(m_wndToolBar.m_combo.Create(WS_CHILD| CBS_DROPDOWNLIST|WS_VISIBLE|WS_TABSTOP, rCombo,&m_wndToolBar,ID_COMBO))) return -1; // добавляем строки в список m_wndToolBar.m_combo.AddString("First"); m_wndToolBar.m_combo.AddString("Second"); m_wndToolBar.m_combo.AddString("Third"); // отмечаем в списке первый пункт m_wndToolBar.m_combo.SetCurSel(0); // установить характеристики панели управления m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); // разрешить присоединить панель к любой строке родительского окна m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); // присоединить панель управления к родительскому окну DockControlBar(&m_wndToolBar); // создание панели состояния (процесс создания рассматривается ниже) ……… return 0; }
Теперь добавим в класс главного окна приложения обработку сообщения
WM_COMMAND. Эту обработку будет осуществлять метод OnCommand:BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) { char str[80]; if(LOWORD(wParam)==ID_COMBO // сообщение от списка &&HIWORD(wParam)==CBN_SELCHANGE) { sprintf(str,"Item's number:%d",m_wndToolBar.m_combo.GetCurSel()); MessageBox(str); } if(LOWORD(wParam)==ID_EDIT // сообщение от поля ввода &&HIWORD(wParam)==EN_MAXTEXT) { sprintf(str,"Limit text:%d",m_wndToolBar.m_edit.GetLimitText()); MessageBox(str); } return CMDIFrameWnd::OnCommand(wParam, lParam); }