Опубликован: 17.08.2010 | Доступ: свободный | Студентов: 1000 / 59 | Оценка: 4.11 / 3.89 | Длительность: 29:38:00
Самостоятельная работа 9:

Однодокументный интерфейс MFC

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

Строка состояния является еще одним элементом GUI, служащим для поддержки пользователя. Она, как правило, располагается в нижней части окна, и служит для отображения различных данных, специфичных для данного приложения. В приложениях SDI и MDI она создается автоматически мастером, и разработчику достаточно ее слегка модифицировать, в приложениях же на основе диалога ее нужно создавать самому разработчику, т.е. нам, с нуля (а этот процесс несколько сложнее). В данной лабораторной работе мы выполним только некоторую модификацию строки состояния.

Анализ кода создания строки состояния, сгенерированного мастером

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

Строка состояния MFC является окном немодального типа, наследуемым от класса CWnd, и поддерживается двумя классами:

  1. CStatusBar - в основном используется в SDI и MDI приложениях
  2. CStatusBarCtrl - более подходит для приложений на базе диалога
    Некоторые методы класса CStatusBar
    Метод Описание
    CommandToIndex() Возвращает индекс индикатора по его идентификатору
    Create() Создает строку состояния как немодальное окно
    GetItemID() Возвращает идентификатор индикатора по его индексу
    GetItemRect() Возвращает параметры прямоугольника элемента по его индексу
    GetPaneInfo() Возвращает информацию об индикаторе
    GetPaneStyle() Возвращает стиль индикатора
    GetPaneText() Возвращает текст индикатора
    GetPaneBarCtrl() Возвращает ссылку на объект класса CStatusBarCtrl
    SetIndicators() Задает идентификатор индикатора
    SetPaneInfo() Задает для индикатора идентификатор, ширину и стиль
    SetPaneStyle() Задает стиль индикатора
    SetPaneText() Задает текст индикатора
    GetTextExtent() Возвращает размер индикатора (нужна только ширина)

Когда в нашем случае мастер создал приложение SDI (или MDI ), то мы видим, что сгенерированная им строка состояния содержит 4 панели (части). Первая панель предназначена для подсказок меню (или кнопок панели инструментов) и она самая длинная. Далее следуют еще три панели <Caps Lock>, <Num Lock> и <Scroll Lock> . Соответствующий код поддержки находится в трех местах, рассмотрим его

Переменная-экземпляр класса CStatusBar - ее объявление находится в классе фреймового окна CMainFrame файла MainFrm.h

Объявление переменной-экземпляра класса CStatusBar
class CMainFrame : public CFrameWnd
{
......................................................
protected:  // control bar embedded members
  CStatusBar  m_wndStatusBar;
  CToolBar    m_wndToolBar;
......................................................
};

Массив индикаторов - массив индикаторов, представленный идентификаторами ресурсов, которые будут отображать информацию в строке состояния. Этот массив определен как глобальный статический в начале файла MainFrm.cpp сразу после карты сообщений

Массив индикаторов в файле MainFrm.cpp
static UINT indicators[] =
{
  ID_SEPARATOR,           // status line indicator
  ID_INDICATOR_CAPS,
  ID_INDICATOR_NUM,
  ID_INDICATOR_SCRL,
};

Порядок расположения идентификаторов в массиве соответствует позиции индикаторов в панели состояния. Первым в этом массиве всегда должен стоять ID_SEPARATOR, который имеет стандартное имя и сообщает среде выполнения, что с данной конкретной панелью строки состояния не связан ни один строковый ресурс. Фактически это означает, что первая панель строки состояния может принимать информацию от любых ресурсов, а в свободном состоянии отображать слово "Ready" (Готов).

Три последних идентификатора массива индикаторов можно найти в строковом ресурсе файла ресурсов DrawSDI.rc при открытии внешним редактором

Файл ресурсов DrawSDI.rc
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
  
STRINGTABLE 
BEGIN
    IDR_MAINFRAME           "DrawSDI\n\nDrawSDI\nDrawSDI Files (*.dhc)\n.dhc\nDrawSDI.Document\nDrawSDI.Document"
END
  
STRINGTABLE 
BEGIN
    AFX_IDS_APP_TITLE       "DrawSDI"
    AFX_IDS_IDLEMESSAGE     "Ready"
END
  
STRINGTABLE 
BEGIN
    ID_INDICATOR_EXT        "EXT"
    ID_INDICATOR_CAPS       "CAP"
    ID_INDICATOR_NUM        "NUM"
    ID_INDICATOR_SCRL       "SCRL"
    ID_INDICATOR_OVR        "OVR"
    ID_INDICATOR_REC        "REC"
END

Обратите внимание на текст, выделенный синим цветом. Кстати, если Вы этот текст в стороннем редакторе переместите в часть файла ресурсов String Table, поддерживающего русскую кодировку 1251, то вялое слово "Ready" можете заменить на свое, которое будет выдаваться как дежурное сообщение в первой панели строки состояния, когда эта панель простаивает.

Функция OnCreate() фреймового окна-рамки - содержит код создания строки состояния и подсоединения к ней индикаторов. Вот соответствующий раздел функции в файле MainFrm.cpp

Файл ресурсов DrawSDI.rc
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...................................................
  if (!m_wndStatusBar.Create(this) ||
    !m_wndStatusBar.SetIndicators(indicators,
      sizeof(indicators)/sizeof(UINT)))
  {
    TRACE0("Failed to create status bar\n");
    return -1;      // fail to create
  }
...................................................
}

Строка состояния создается функцией Create() с единственным обязательным параметром, являющемся указателем на родительское окно ( pParentWnd ). Родительским окном для строки состояния является фреймовое окно, поэтому достаточно указать this - указатель на экземпляр класса CMainFrame фреймового окна-рамки. Вторая функция SetIndicators() присваивает массив indicators[], в котором содержаться значения идентификаторов ресурсов, состояние которых нужно отобразить.

Фактически функция Create() имеет три параметра, два из которых (последние) установлены по умолчанию.

  1. CWnd* pParentWnd - указатель на родительское окно строки состояния
  2. DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | CBRS_BOTTOM - комбинация флагов, определяющих тип, видимость, форму границ, месторасположение
  3. UINT nID = AFX_IDW_STATUS_BAR - стандартный идентификатор самой строки состояния
Добавление индикатора цвета в строку состояния

Для добавления в строку состояния нового индикатора прежде нужно создать его идентификатор в String Table файла ресурсов приложения. Идентификатор будет представлять в приложении закрепленный за ним индикатор. Чтобы в индикатор поместился любой закрепленный за ним текст, необходимо при создании соответствующего идентификатора ввести самый длинный текст из предполагаемых для отображения.

  • Вызовите на редактирование ресурс String Table и добавьте новую строку
  • В поле ID введите значение ID_INDICATOR_COLOR, поле Value оставьте по умолчанию, а в поле Caption введите строку Бирюзовый, как самую длинную из набора слов "Черный, Синий, Зеленый, Бирюзовый, Красный, Сиреневый, Желтый, Белый", подлежащих отображению
  • В массив индикаторов файла MainFrm.cpp добавьте новый идентификатор так
    Массив индикаторов в файле MainFrm.cpp
    static UINT indicators[] =
    {
      ID_SEPARATOR,           // status line indicator
      ID_INDICATOR_COLOR,
      ID_INDICATOR_CAPS,
      ID_INDICATOR_NUM,
      ID_INDICATOR_SCRL,
    };
  • Постройте приложение и убедитесь, что новый индикатор создан и в нем находится статический текст "Бирюзовый"
Связывание индикатора с обработчиком

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

  • Добавьте в класс CDrawSDIDoc новую функцию-обработчик, заполнив мастер так


    Не забудьте нажать кнопку Add перед нажатием кнопки Finish

  • Введите вручную в карту сообщений класса CDrawSDIDoc регистрацию обработчика за нашим новым индикатором с идентификатором ID_INDICATOR_COLOR
    Карта сообщений в файле DrawSDIDoc.cpp
    BEGIN_MESSAGE_MAP(CDrawSDIDoc, CDocument)
      ON_COMMAND_RANGE(ID_COLOR_BLACK, ID_COLOR_WHITE, OnColorCommand)
      ON_UPDATE_COMMAND_UI_RANGE(ID_COLOR_BLACK, ID_COLOR_WHITE, OnUpdateColorUI)
      ON_COMMAND_RANGE(ID_WIDTH_1, ID_WIDTH_32, OnWidthCommand)
      ON_UPDATE_COMMAND_UI_RANGE(ID_WIDTH_1, ID_WIDTH_32, OnUpdateWidthUI)
      ON_UPDATE_COMMAND_UI(ID_INDICATOR_COLOR, OnUpdateIndicatorColor)
    END_MESSAGE_MAP()
  • Наполните обработчик кодом
    Код обработчика в файле DrawSDIDoc.cpp
    // Обработчик обновления индикатора
    void CDrawSDIDoc::OnUpdateIndicatorColor(CCmdUI* pCmdUI)
    {
      char* str[] = {"Черный", 
              "Синий",
              "Зеленый",
              "Бирюзовый",
              "Красный",
              "Сиреневый",
              "Желтый",
              "Белый"  
              };
      pCmdUI->Enable(); // По умолчанию TRUE - доступный
      pCmdUI->SetText((LPCTSTR)str[m_iColor]);
    }
  • Постройте приложение и убедитесь, что все работает
  • Нарисуйте свой автопортрет, например, так

А он лучше оригинала...


Александр Даниленко
Александр Даниленко
Стоит Windows 8 Pro, Visual Studio 2010 Express Edition .