Опубликован: 10.03.2009 | Доступ: свободный | Студентов: 2297 / 280 | Оценка: 4.31 / 4.07 | Длительность: 09:23:00
Лекция 2:

Библиотека классов MFC

Ресурсы

Понятие ресурсов

Структура EXE-файла для Windows такова, что в его конец могут быть записаны некоторые данные, совершенно не зависящие от самой программы. Они называются ресурсами. Ресурсы могут редактироваться совершенно раздельно, хотя находятся в том же файле, где код и данные. При загрузке программы на выполнение, ресурсы обычно не загружаются в память, а это делается лишь по запросу от программы. В ресурсах программа может хранить любые данные, какого угодно размера. Но есть стандартные типы ресурсов, такие как иконки, битовые образы, курсоры, диалоги, меню. Большинство диалоговых окон не создаются программным путем, а просто их шаблоны загружаются из ресурсов. Сами шаблоны, как и другие ресурсы, редактируются визуально с помощью специальных ресурсных редакторов. При сборке проекта приложения, ресурсы добавляются к EXE-файлу уже после связывания. Для описания ресурсов существует специальный язык, а сами описания хранятся в текстовых файлах с расширением rc. Раньше программисты вручную писали сценарии ресурсов на языке ресурсов, сейчас используются визуальные редакторы. Перед добавлением к исполняемому файлу, сценарии преобразуются в бинарный вид с помощью компилятора ресурсов, в результате получается файл с расширением res. Как правило, все эти шаги выполняются автоматически при работе из интегрированной среды Visual C++. Заметим, что "ручное" редактирование ресурсных сценариев требуется сейчас уже очень редко, лишь при определении нестандартных ресурсов в сложных проектах. Каждый ресурс имеет свой уникальный идентификатор. Это может быть либо строка, либо число (константа). Числа можно использовать всегда, а строки – не всегда. Редактор ресурсов из Visual C++ помещает имена констант в файл resource.h, который нужно включить в файлы программы. Стандартные идентификаторы хранятся в файле afxres.h, который обычно используется автоматически ресурсным редактором.

Меню

Меню, как правило, создаются визуально. В Visual C++ за это отвечает редактор ресурсов. Среда автоматически добавляет в проект сценарий ресурсов. При создании меню, для отдельных пунктов могут быть установлены опции выделения серым цветом (в этом случае при выполнении программы пункт меню будет недоступен), вставки разделительной горизонтальной черты, перехода на новую строку (в этом случае пункты верхнего уровня будут начинаться с новой строки, а нижнего – в новом столбце через вертикальную черту). Меню, как отдельному ресурсу, должен быть присвоен числовой или символьный идентификатор. При редактировании символьные идентификаторы заключаются в кавычки. Также, каждому пункту меню должен быть присвоен уникальный числовой идентификатор. Это позволит программе реагировать на выбор пункта в меню, и будет вызываться соответствующий обработчик. По принятому соглашению, все идентификаторы пунктов меню начинаются с IDM_. В самих названиях пунктов можно указывать ключевые клавиши, поставив перед буквой символ &. В этом случае, если меню активно, пункт можно выбрать также и с клавиатуры.

Включение меню в окно приложения

Когда ресурс меню уже создан, его можно использовать в окне программы. Это можно сделать, указывая меню при создании окна: строковый идентификатор ресурса меню нужно указать в качестве последнего параметра в функции Create():

this->Create(0, "Приложение с меню", WS_OVERLAPPEDWINDOW, rectDefault, 0, "MYMENU");

В результате будет создано окно с меню. Но, для того чтобы меню можно было использовать, необходимо создать обработчики сообщения WM_COMMAND для каждого пункта меню. Если для какого-то пункта нет обработчика, то MFC заблокирует этот пункт (он будет выделен серым цветом).

Сообщение WM_COMMAND

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

ON_COMMAND(Идентификатор, ИмяОбработчика);

Каждый обработчик для WM_COMMAND должен возвращать значение void. Обработчики не имеют параметров. Имя выбирается произвольно, обычно используется префикс On. Таким образом, можно написать обработчики для каждого пункта меню.

Акселераторы

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

BOOL CFrameWnd::LoadAccelTable(LPCSTR ResourceName);

После загрузки таблицы акселераторов, нажатие заданных в ней комбинаций клавиш приводит к автоматической генерации сообщения WM_COMMAND с идентификатором, определенным в этой таблице для данной комбинации клавиш. Акселераторы легко создавать в среде Visual C++. Для каждого элемента таблицы нужно нажать желаемую клавишу или их комбинацию, и указать числовой идентификатор. Если указать идентификаторы, которые уже использовались в меню, то мы получим клавиши быстрого доступа, дублирующие команды меню.

Окна сообщений

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

int CWnd::MessageBox(LPCSTR MessageText, LPCSTR WindowTitle = 0, UINT MessageBoxType = MB_OK);

Параметр MessageText определяет само сообщение. Параметр WindowTitle - заголовок окна сообщения. Параметр MessageBoxType задает стиль окна, иконку, отображаемую слева от сообщения, и одну, или несколько кнопок. Этот параметр задается комбинацией констант с помощью операции "|", начинающихся на префикс MB_. Все наборы кнопок заранее определены. Функция возвращает идентификатор нажатой кнопки: IDABORT, IDRETRY, IDIGNORE, IDCANCEL, IDNO, IDYES, или IDOK. Функция MessageBox(...) выполняет все действия по созданию, отображению и удалению окна, а также обработку сообщений. Программист не должен об этом заботиться.

Иконки и курсоры

Иконки и курсоры являются ресурсами и обычно хранятся в области ресурсов исполняемого файла.

Создание иконки и курсора

Для создания иконки и курсора нужно использовать ресурсный редактор. Иконки сохраняются в файлах с расширением ico, а курсоры – в файлах с расширением cur. Все курсоры имеют размер 32x32. Обычно используются монохромные курсоры. Каждый курсор имеет так называемую горячую точку, по которой определяется положение курсора на экране. Она может располагаться в любом месте курсора. Для курсоров типа "указатель" это обычно вершина указателя. Иконки могут иметь размер 16х16, 32х32 и 48х48. Последний размер обычно не используется. Иконки могут иметь 16 или 256 цветов. При использовании редактора ресурсов среды Visual C++ 4.0 и выше иконки всех размеров можно хранить в одном файле, что обычно и делается. Для современных приложений обязательно наличие иконок размером как 16х16, так и 32х32.

Загрузка иконки и курсора из ресурсов

Для загрузки иконок и курсоров удобно использовать функции Win API. Перед рассмотрением этих функций следует рассмотреть понятие дескриптора.

Дескриптор – это 32-разрядное беззнаковое целое значение, которое идентифицирует объект в Windows.

При традиционном SDK-программировании дескрипторы используются очень широко. Так, свои дескрипторы имеют иконки, курсоры и само приложение. Для дескрипторов каждого объекта существует свой тип, например, HICON, HCURSOR, HINSTANCE. Будем предполагать, что в декларировании класса основного окна (речь идет о классе С++) объявлены переменные m_hIconSmall, m_hIconBig, m_hCursor – соответственно дескрипторы иконки 16х16, иконки 32х32 и курсора. Тогда для загрузки иконок и курсора нужно выполнить следующий код:

// Получить дескриптор модуля (приложения)
HINSTANCE hInst = AfxGetInstanceHandle();
// Загрузить иконку 16х16
m_hIconSmall = (HICON) ::LoadImage(hInst,MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
// Загрузить иконку 32x32 
m_hIconBig = (HICON) ::LoadImage(hInst,MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,32,32,LR_DEFAULTCOLOR); 
// Загрузить курсор
m_hCursor = AfxGetApp()->LoadCursor(IDC_CURSOR);

Сначала мы получаем дескриптор модуля с помощью глобальной функции MFC AfxGetInstanceHandle(). Затем мы загружаем маленькую и большую иконки с помощью функции Win API LoadImage(…), и получаем их дескрипторы. Эта функция позволяет загружать изображения из ресурсов и из файлов. И, наконец, мы загружаем курсор уже с помощью функции MFC LoadCursor(…), члена класса CWinApp. Функция AfxGetApp() возвращает адрес объекта приложения.

Изменение иконки и курсора окна

После того как мы получили дескрипторы иконок и курсора, надо изменить класс окна. Класс окна надо изменять для установки курсора, а для установки иконок использовать функции MFC. Для этого используется API-функция SetClassLong(…), которая изменяет атрибут класса окна (здесь опять имеется в виду структура данных). Первый параметр этой функции – дескриптор окна. Дескриптор окна хранится в члене класса MFC CWnd под названием m_hWnd. Если главным окном приложения является диалог, то для изменения иконки и курсора потребуется следующий код (он будет работоспособен и для обычных окон):

// Устанавливаем курсор для диалогового окна.
SetClassLong(m_hWnd, GCL_HCURSOR, (long) m_hCursor);
// Делаем то же самое для всех элементов управления
for(int i = 0; i < 0xDFFF; ++i)
{
  CWnd *pCtrl = this->GetDlgItem(i); 
  if(pCtrl != 0) 
    SetClassLong(pCtrl->m_hWnd, GCL_HCURSOR, (long) m_hCursor);
}
// Устанавливаем иконки. Здесь можно использовать MFC.
this->SetIcon(m_hIconBig, TRUE);
this->SetIcon(m_hIconSmall, FALSE);

Сначала, мы модифицируем курсор в оконном классе самого окна. Затем, то же самое проделываем со всеми элементами управления, которые есть или могут быть в диалоговом окне (если их нет в окне, то ничего страшного не произойдет). Мы перебираем все возможные идентификаторы, и, если элемент присутствует, изменяем его оконный класс. И, наконец, мы изменяем большую и маленькую иконки.

Стандартные иконки и курсоры

Часто в программах необходимо использовать курсоры и иконки, уже предопределенные в Windows. Для этого можно использовать или функцию API LoadImage(…), или функции MFC LoadStandardIcon(…) и LoadStandardCursor(…). Работа со стандартными курсорами и иконками почти ничем не отличается от работы с пользовательскими курсорами и иконками. Для стандартных иконок есть предопределенные идентификаторы с префиксом IDI_, а для стандартных курсоров – с префиксом IDC_. Например, стандартный курсор в виде "песочных часов" имеет идентификатор IDC_WAIT.