Лекция 3. Меню. Панели инструментов и строки состояния
Якунин М.С

[На главную страницу сайта] [Другие темы раздела] [Содержание курса] [Лабораторная работа к лекции] [Скачать задачи] [Следующая лекция]

Методические рекомендации

  1. При работе с меню следует обратить внимание студентов на изменение меню в период выполнения программы, так на практике это очень часто применяется.
  2. Следует иллюстрировать нижеследующий материал наглядными примерами. Очень хорошо для этого подходят программы из пакета Microsoft Office.

План

  1. Меню Windows
  2. Панели элементов управления и каркас приложения
  3. Панель инструментов
  4. Строка состояния.

Меню Windows

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

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

В Visual C++ входит простой в применении редактор меню. Это средство позволяет создавать и редактировать меню в режиме WYSIWYG. Для каждой команды меню открывается диалоговое окно, в котором можно задать характеристики этой команды. Полученное определение ресурса сохраняется в RC-файле проекта. Каждой команде меню присваивается свой идентификатор, который определяется в файле Resource.h.

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

Обновление командного пользовательского интерфейса

Весьма часто приходится менять внешний вид элементов меню, чтобы отразить внутреннее состояние программы. Например, если в меню Edit присутствует команда Clear All (Очистить все), то Вы, может быть, захотите отключить ее, если очищать нечего. Без сомнения, в меню Windows-программ Вы видели отключенные и помеченные галочками команды.

При программировании в Win32 синхронизировать состояние элементов меню в соответствии с состоянием приложения не так-то просто. Каждый участок кода, изменяющий внутреннее состояние программы, должен содержать операторы, обновляющие меню. В MFC-библиотеке реализован другой подход, основанный на вызове специальной функции-обработчика, которая и обновляет командный пользовательский интерфейс при каждом открытии меню. Аргумент этой функции — объект CCmdUI, содержащий указатель на соответствующий элемент меню. Используя этот указатель, функция-обработчик может изменить внешний вид команды меню. Подобные обработчики применимы к элементам раскрывающихся меню, но не к меню верхнего уровня, постоянно присутствующим на экране. Такой обработчик нельзя использовать, например, для отключения меню File.

Требования к определению обработчиков, обновляющих командный пользовательский интерфейс, сходны с требованиями к определению обработчиков команд. Вам нужна собственно функция, специальный элемент таблицы сообщений и, конечно же, прототип функции. Идентификатор (в нашем случае IDM_ZOOM) применяется тот же, что и для команды. Вот что надо добавить к файлу кода для класса “вид”:

BEGIN_MESSAGE_MAP(CMyView, CView)

ON_UPDATE_COMMMAND_UI(IDM_ZOOM, OnUpdateZoom) END_MESSAGE_MAP()

void GMyView::OnUpdateZoom(CCmdUI* pCmdUI)

{

pCmdUI->SetCheck(m_bZoomed); // in_bZoomed - переменная-член класса

}

Класс CMenu

Объект этого класса может представлять любое меню Windows, в том числе меню верхнего уровня и связанные с ним раскрывающиеся меню. Чаще всего, когда вызывается функция Create для окна-рамки и объект СМепи явным образом не создается, ресурс меню подсоединяется прямо к этому окну. Функция-член GetMenu класса CWnd возвращает временный указатель на СМепи. Получив этот указатель, Вы получаете свободный доступ к меню и можете изменять его.

Допустим, Вы хотите переключать меню после запуска приложения. Исходное меню всегда имеет идентификатор IDR_MAINFRAME. Если Вам нужно второе меню, Вы создаете его в редакторе меню и определяете требуемый идентификатор. Затем в своей программе Вы создаете объект СМепи, загружаете меню из ресурса с помощью СМепи::.LoadMenu и вызываете CWnd::SetMenu, чтобы присоединить новое меню к окну рамке. После этого вызываете метод Detach, чтобы отсоединить от объекта описатель HMENU, тогда созданное Вами меню не будет уничтожено, когда объект СМепи выйдет из области видимости.

Можно определить меню в ресурсе и потом модифицировать его в период выполнения программы. При необходимости в период выполнения можно создать и все меню целиком, не пользуясь ресурсами В любом случае для этого пригодятся такие функции-члены класса СМепи, как ModifyMenu, InsertMenu и DeleteMenu. Каждая из них работает с отдельным элементом меню, определяемому по идентификатору или по индексу его позиции в меню.

Объект меню в действительности состоит из вложенной структуры подменю. функция-член GetSubMenu возвращает указатель на объект СМепи, представляющий раскрывающееся меню в главном объекте СМепи. Функция СМепи::GetMenuString возвращает текст в элементе меню, указанному либо по индексу, либо по идентификатору команды, В последнем случае выполняется поиск по всей системе меню, включая вложенные.

Создание контекстных меню

Контекстные меню (floating pop-up menu) — одна из последних новаций в пользовательском интерфейсе Щелчок правой кнопкой мыши открывает меню с командами, которые относятся к текущему контексту. Такие меню легко создать с помощью графического редактора и MFC-функции СМепи::TrackPopupMenu. Для этого выполните следующее:

1. Откройте редактор меню и добавьте в файл ресурсов своего проекта новое пустое меню.

2. Введите какое-нибудь имя для крайнего слева элемента верхнего уровня и добавьте команды контекстного меню в получившееся раскрывающееся меню.

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

void CMyView OnContextMenu(CWnd* pMnd, CPoint point)

{

CMenu menu;

menu.LoadMenu(IDR_MYFLOATINGMENU);

menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN |

TMP_RIGHTBUTTON, point x, point y, this);

}

Команды контекстного меню можно сопоставить с обработчиками при помощи Class-Wizard тем же способом, что и команды в меню окна-рамки.

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

Панель инструментов (toolbar) — это объект класса CToolBar, а строка состояния (status bar) — объект класса CStatusBar. Оба класса производные от CControlBar, а тот, в свою очередь — от CWnd. Класс CControlBar поддерживает окна панелей элементов управления, размещаемых в окне-рамке. Окна этих панелей автоматически изменяют свои размеры и положение при масштабировании и перемещении окна-рамки. Каркас приложений создает и удаляет эти объекты и их окна. AppWizard генерирует код панелей элементов управления для производного класса окна-рамки, хранящегося в файлах MainFrm.cpp и MainFrm.h. В типичном SDI-приложении объект CToolBar находится вверху клиентской области CMainFrame, a объект CStatusBar — внизу. Между ними находится окно представления.

Начиная с версии 4.0 MFC-библиотеки, панель инструментов формируется на основе стандартного элемента управления “панель инструментов (toolbar common control), впервые появившегося в Windows 95, и поэтому поддерживает стыковку (docking) с окном-рамкой. Хотя программный интерфейс остался практически таким же, что и в предыдущих версиях MFC, работать с изображениями кнопок стало легче, поскольку редактор ресурсов поддерживает соответствующий специальный тип ресурсов. Применявшиеся ранее глобальные массивы buttons больше не требуются.

Если AppWizard сгенерировал код панелей элементов управления для данного приложения, пользователь может включать и отключать показ этих панелей командами из меню View. При отключении панель исчезает, и пересчитывается размер окна представления. Несмотря на некоторые общие (описанные выше) свойства, объекты “панель инструментов” и “строка состояния” независимы друг от друга и имеют разные характеристики.

Панель инструментов

Панель инструментов — строка горизонтально (или вертикально) расположенных графических кнопок, иногда объединенных в группы. Разбивка на группы осуществляется программным путем, в соответствии с назначением кнопок Изображения кнопок хранятся в общем растровом изображении, входящем в ресурсы приложения. Если щелкнуть кнопку, она пошлет командное сообщение, подобно меню и быстрым клавишам. Для обновления состояния кнопок служат обработчики обновления командного пользовательского интерфейса, вызываемые каркасом приложений для изменения внешнего вида кнопок

Растровое изображение панели инструментов

Может показаться, что у каждой кнопки на панели инструментов свое растровое изображение, но на самом деле растровое изображение для всей панели одно. В нем каждой кнопке выделяется ячейка высотой 15 и шириной 16 пикселов. Каркас приложений обеспечивает прорисовку границ кнопок и изменяет их вместе с цветом фона кнопки, чтобы отобразить ее текущее состояние.

Растровое изображение панели инструментов хранится в файле Toolbar.bmp в подкаталоге RES приложения. В RC-файле оно идентифицируется как IDR_MAINFRAME. Это растровое изображение напрямую не модифицируют, вместо этого пользуются специальными средствами графического редактора.

Состояния кнопок

Любая кнопка может находиться в следующих состояниях

Состояние

Описание

0

Нормальное, не “нажата”

TBSTATE_CHECKED

Помечена (“нажата”)

TBSTATE_ENABLED

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

TBSTATE_HIDDEN

Невидима

TBSTATE_INDETERMINATE

Изображается блеклой

TBSTATE_PRESSED

Выбрана (“нажата”) мышью

TBSTATE_WRAP

Кнопка является последней в строке

 

Кнопка может быть либо командной (“нажата”/“отжата”), либо флажком (“установлен”/“сброшен”). На стандартной панели инструментов, формируемой каркасом приложений, все кнопки — командные.

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

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

Чаще всего кнопка на панели инструментов дублирует команду меню. Например, кнопка с изображением дискеты на стандартной панели инструментов (формируемой каркасом приложений) эквивалентна команде Save из меню File. Обе генерируют команду ID__FILE_SAVE. A объекту, получившему командное сообщение, безразлично, сгенерировано оно щелчком кнопки на панели инструментов или выбором команды из меню.

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

С панелью инструментов связан ресурс растрового изображения и сопутствующий ресурс TOOLBAR в RC-файле, который определяет команды меню, связанные с кнопками. И растровое изображение, и ресурс TOOLBAR имеют одинаковый идентификатор — обычно это IDR_MAINFRAME. Вот содержимое ресурса TOOLBAR, сгенерирированное AppWizard:

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

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

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

Обновление пользовательского интерфейса для панелей инструментов

Обработчики сообщений обновления пользовательского интерфейса применяются, чтобы отключать команды меню или помечать их галочками. Эти же обработчики пригодны и для кнопок на панели инструментов. Если подобный обработчик вызывает функцию-член CCmdUI::Enable с параметром FALSE, соответствующая кнопка отключается (становится блеклой) и больше не реагирует на щелчки мышью.

Функция CCmdUI::SetCheck ставит рядом с командой меню галочку, а на панели инструментов реализует кнопку со свойствами флажка. После вызова SetCheck с параметром 1 кнопка “залипает” в нажатом состоянии, а с параметром 0 — возвращается в исходное, “отжатое” состояние.

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

Всплывающие подсказки

Всплывающие подсказки (ToolTips) встречаются в разных. Windows-приложениях, в том числе и в Visual C++. Если поместить курсор мыши на кнопку панели инструментов и оставит его там, то через определенный промежуток времени рядом с кнопкой появится маленькое окошко с текстом.

Чтобы создать всплывающую подсказку, просто добавьте ее в конец подсказки для меню, начав текст с символа новой строки \n. Редактор ресурсов позволяет модифицировать строку подсказки при редактировании изображений кнопок на панели инструментов. Для этого просто дважды щелкните левую кнопку мыши.

Строка состояния

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

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

Определение секций в строке состояния

Секции в строке состояния определяются статическим массивом indicators, который АррWizard создает в файле MainFrm.cpp. Константа ID_SEPARATOR задает секцию для строки сообщений, а другие константы служат идентификаторами строковых ресурсов и определяют секции индикаторов.

Функция-член CStatusBar::SetIndtcators, вызываемая в производном классе окна-рамки приложения, приводит строку состояния в соответствие с содержимым массива indicators.

Строка сообщений

В этой секции показывается строка, задаваемая (динамически) программой. Чтобы определить выводимый текст, сначала получите доступ к объекту строки состояния, после чего вызовите функцию-член CStatusBar::SetPaneText, передав ей индекс секции. Индексы начинаются с 0, нулевая секция — крайняя слева, секция 1 размещается правее и т.д.

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

CMainFrame* pFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd;

CStatusBar* pStatus = &pFrame->m_wndStatusBar;

pStatus->SetPaneText(0, "строка сообщения для первой секции");

Обычно длина секции сообщений составляет ровно четверть ширины экрана. Однако у первой секции (индекс 0) длина переменная; она не менее четверти ширины экрана и может быть увеличена, если в строке состояния есть место.

Индикатор состояния

Секция индикатора состояния связана с единственной строкой ресурса, которая показывается или скрывается в соответствии с логикой функции-обработчика. Индикатор обозначается идентификатором строкового ресурса, и тот же идентификатор применяется для распределения сообщений обновления интерфейса. Индикатор Caps Lock обрабатывается в классе окна-рамки при помощи приведенных ниже элемента таблицы сообщений и функции-обработчика (функция Enable включает индикатор, если активен режим Caps Lock):

ON_UPDATE_COMMAND_UI (ID_INDICATOR_CAPS, OnUpdateKeyCapsLock)

void CMainFrame::OnUpdateKeyCapsLock(CCmdUI* pCmdUI)

{

pCmdUI->Enable(::GetKeyState(VK_CAPITAL) & 1);

}

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

Управление строкой состояния

Стандартной строке состояния присваивается идентификатор дочернего окна AFX_IDW_STATUS_BAR. Именно его каркас приложений ищет для вывода подсказки по элементам меню. Обработчики сообщений обновления пользовательского интерфейса используют три идентификатора строковых ресурсов для индикаторов состояния клавиатуры в базовом классе окна-рамки: ID_INDICATOR_CAPS, ID_INDICATOR_NUM и ID_INDICATOR_SCRL. Чтобы самому управлять строкой состояния, нужно применить другой идентификатор дочернего окна и другие константы для индикаторов.

Идентификатор для окна строки состояния назначается вызовом CstatusBar::Create в функции-члене OnCreate производного класса окна-рамки. Эта функция содержится в файле MainFrm.cpp, генерируемом AppWizard. Идентификатор окна — третий параметр функции Create и по умолчанию равен AFX_IDW_STATUS_BAR.

Чтобы назначить свой идентификатор, замените вызов

m_wndStatusBar.Create(this);

на m_wndStatusBar.Create (this, WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, ID_MY_STATUS_BAR),

Конечно, нужно определить и константу ID_MY_STATUS_BAR в файле resource.h, применяя редактор символов.

Стандартное меню View, формируемое каркасом приложений, позволяет включать и отключать показ строки состояния. Эта логика реализуется кодом, использующим идентификатор окна AFX_IDW_STATUS_BAR, который тоже придется изменить. В своем производном классе окна-рамки напишите элементы таблицы сообщений и обработчики для команды ID_VIEW_STATUS_BAR и сообщений, связанных с обновлением пользовательского интерфейса. ID_VIEW_STATUS_BAR — это идентификатор элемента меню Status Bar. Обработчики в производном классе переопределяют стандартные обработчики из базового класса CFrameWnd.

Контрольные вопросы:

  1. Что такое меню?
  2. Какие виды меню вы знаете?
  3. Что такое панель инструментов?
  4. Что такое строка состояния?
  5. Какие секции есть в строке состояния?
  6. Какой класс отвечает за работу со строками состояния?
  7. Какой класс отвечает за работу с панелями инструментов?
  8. Какой класс отвечает за работу с меню?
  9. [На главную страницу сайта] [Другие темы раздела] [Содержание курса] [Лабораторная работа к лекции] [Скачать задачи]
    [Следующая лекция]