Функции класса MouseZoneClass

Далее в заголовочном файле расположено объявление класса MouseZoneClass. Ниже приведен его код:

class MouseZoneClass
{
private:
int m_iMaxZones;
stHotSpot *m_HotSpots;

public:
MouseZoneClass(void);
~MouseZoneClass(void);
void vInitialize(int iMaxZones);
void vFreeZones(void);
int iAddZone(char *szZoneName, short shX, short shY,
short shWidth, short shHeight, short shClickType);
int iRemoveZone(char *szZoneName);
bool bCheckZones(short shX, short shY, char *szZoneHit,
bool bLeftDown, bool bRightDown);
};

Есть только две закрытые переменные класса — m_iMaxZones и m_HotSpots. Переменная m_iMaxZones хранит количество активных зон, для которых выделена память. Это очень важные сведения, поскольку количество используемых зон может изменяться. Переменная m_HotSpots является указателем на массив структур данных stHotSpot, представляющих реально существующие активные зоны.

Функции класса MouseZoneClass
Первые две объявленные функции — это конструктор и деструктор класса. В их прототипах нет ничего необычного; это просто обычная рутина программирования.

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

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

Функция iAddZone() активирует новую зону в массиве m_HotSpots. Если свободная зона доступна, функция возвратит ее номер. Если же свободных зон больше нет, функция возвращает –1.

Функция iRemoveZone() делает указанную зону неактивной.

Функция bCheckZones() получает набор координат и состояние кнопок мыши, после чего определяет активирована ли какая-нибудь зона. Функция возвращает имя активной зоны. Если никакая зона не активирована, функция возвращает NULL.

Файл MouseZoneClass.cpp
Файл MouseZoneClass.cpp содержит код функций, объявленных в заголовочном файле. Откройте файл MouseZoneClass.cpp и пойдемте дальше.

Функция MouseZoneClass::MouseZoneClass()
Первой из функций является конструктор класса. Его код выглядит следующим образом:

MouseZoneClass::MouseZoneClass(void)
{
// Количество зон равно нулю
m_iMaxZones = 0;
}

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

Функция MouseZoneClass::~MouseZoneClass()
Следом идет деструктор класса, код которого выглядит так:

MouseZoneClass::~MouseZoneClass(void)
{
// Очистка выделенных зон
vFreeZones();
}

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

Функция MouseZoneClass::vInitialize()
Ах, наконец-то мы добрались до функции чей код занимает больше двух строк. Она получает максимальное количество активных зон, которые вы намереваетесь использовать, выделяет память для хранения их данных и присваивает начальные значения. Вот ее код:

void MouseZoneClass::vInitialize(int iMaxZones)
{
int i;
// Очистка существующих зон
vFreeZones();
// Сохранение максимального количества зон
m_iMaxZones = iMaxZones;
// Выделение памяти для указанного количества зон
m_HotSpots = new stHotSpot[m_iMaxZones];
// Очистка данных зоны
for(i = 0; i < m_iMaxZones; i++) {
m_HotSpots[i].m_shZoneXPos = 0;
m_HotSpots[i].m_shZoneYPos = 0;
m_HotSpots[i].m_shZoneWidth = 0;
m_HotSpots[i].m_shZoneHeight = 0;
m_HotSpots[i].m_shClickType = 0;
m_HotSpots[i].m_bActive = 0;
m_HotSpots[i].m_szZoneName = new char[64];
memset(m_HotSpots[i].m_szZoneName, 0x00, 64);
}
}

Сначала выполняется вызов функции vFreeZones(), которая освобождает любую выделенную ранее память.

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

Теперь выделяется память для хранения массива структур данных горячих точек. Для каждой активной зоны создается одна структура данных.

В цикле перебираются все созданные активные зоны и всем их параметрам присваиваются нулевые значения. Кроме того, в цикле выделяется 64 байта памяти для хранения имени зоны. Это максимальная длина имени зоны. (Я выбрал это значение абсолютно произвольно; если вам нужны более длинные имена зон, вы вольны изменить его.) После выделения памяти для имени зоны, я заполняю ее нулевыми значениями.

Функция MouseZoneClass::vFreeZones()
Данная функция освобождает всю выделенную для активных зон память и сбрасывает значения внутненних переменных. Вот как выглядит ее код:

void MouseZoneClass::vFreeZones(void)
{
int i;

if(m_iMaxZones) {
// Освобождение имен
for(i = 0; i < m_iMaxZones; i++) {
delete [] m_HotSpots[i].m_szZoneName;
}
// Освобождение горячих точек
delete [] m_HotSpots;
m_iMaxZones = 0;
}
}

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

Функция MouseZoneClass::iAddZone()
Эта функция активирует зону и записывает ее данные в доступный элемент массива структур данных горячих точек. Перед вызовом этой функции необходимо вызвать функцию vInitialize(). Если свободных элементов в массиве нет, функция возвращает –1. Код функции выглядит следующим образом:

int MouseZoneClass::iAddZone(char *szZoneName,
short shX, short shY,
short shWidth, short shHeight,
short shClickType)
{
int i;

for(i = 0; i < m_iMaxZones; i++) {
// Ищем неиспользуемую зону
if(m_HotSpots[i].m_bActive == 0) {
m_HotSpots[i].m_shZoneXPos = shX;
m_HotSpots[i].m_shZoneYPos = shY;
m_HotSpots[i].m_shZoneWidth = shWidth;
m_HotSpots[i].m_shZoneHeight = shHeight;
m_HotSpots[i].m_shClickType = shClickType;
// Активируем горячую точку
m_HotSpots[i].m_bActive = 1;
// Сохраняем имя
strcpy(m_HotSpots[i].m_szZoneName, szZoneName);
return(i);
}
}
// Нет свободных зон, возвращаем -1 (ошибка)
return(-1);
}

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

Функция MouseZoneClass::iRemoveZone()
Данная функция отключает активную зону. Вот ее код:

int MouseZoneClass::iRemoveZone(char *szZoneName)
{
int i;

for(i = 0; i < m_iMaxZones; i++) {
// Проверим, активна ли зона
if(m_HotSpots[i].m_bActive == 1) {
// Проверка соответствия имени зоны
if(!stricmp(m_HotSpots[i].m_szZoneName, szZoneName)) {
// Деактивация
m_HotSpots[i].m_bActive = 0;
return(1);
}
}
}
return(0);
}

Функция перебирает в цикле все зоны, для которых выделена память и сравнивает имя каждой из них с переданным параметром. Если имя найдено, зона деактивируется путем установки переменной m_bActive в 0. Чтобы сообщить об успещном завершении функция возвращает 1.

Если зона с указанным именем не найдена, функция сообщает об ошибке, возвращая 0.

Функция MouseZoneClass::bCheckZones()
Это наиболее сложная функция в классе активных зон, поскольку она обрабатывает различные типы щелчков мышью. Вот как выглядит ее код:

bool MouseZoneClass::bCheckZones(short shX, short shY, char *szZoneHit, bool
bLeftDown, bool bRightDown)
{
int i;
for(i = (m_iMaxZones-1); i >= 0; i--) {
// Проверим активна ли зона
if(m_HotSpots[i].m_bActive == 1) {
// Соответствует ли состояние кнопок требуемому?
if((bLeftDown && m_HotSpots[i].m_shClickType == 0) ||
(bRightDown && m_HotSpots[i].m_shClickType == 1) ||
((bRightDown || bLeftDown) && m_HotSpots[i].m_shClickType == 2) ||
((!bRightDown && !bLeftDown) && m_HotSpots[i].m_shClickType == 3)) {
// Проверка координат по горизонтали
if(m_HotSpots[i].m_shZoneXPos <= shX {
// Проверка координат по вертикали
if(m_HotSpots[i].m_shZoneYPos <= shY) {
// Попали ли в зону заданной ширины?
if((m_HotSpots[i].m_shZoneXPos + m_HotSpots[i].m_shZoneWidth)
>= shX) {
// Попали ли в зону указанной высоты?
if((m_HotSpots[i].m_shZoneYPos + m_HotSpots[i]
.m_shZoneHeight) >= shY) {
// Устанавливаем указатель на имя зоны
strcpy(szZoneHit, m_HotSpots[i].m_szZoneName);
// Возвращаем 1 (попадание)
return(1);
}
}
}
}
}
}
}
// Возвращаем 0 (нет попадания)
return(0);
}

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

Сперва в цикле выполняется проверка включена ли зона. Если зона включена, мы переходим к проверке соответствия текущего состояния кнопок мыши типу щелчка, активирующего зону.

Если зона активируется щелчком левой кнопкой мыши, код проверяет равен ли тип щелчка 0 и равно ли 1 значение переменной bLeftDown.

Если зона активируется щелчком правой кнопкой мыши, код проверяет равен ли тип щелчка 1 и равно ли 1 значение переменной bRightDown.

Если зона может быть активирована щелчком любой кнопки мыши, код проверяет равен ли тип щелчка 2 и равно ли 1 значение переменной bLeftDown или bRightDown.

Если зона активируется, когда на нее наведен указатель мыши, а ни одна из кнопок не нажата, код проверяет равен ли тип щелчка 3 и равно ли 0 значение переменных bLeftDown и bRightDown.

Если какое-либо из перечисленных выше правил выполнено, код копирует имя активной зоны в буфер и возвращает 1, сигнализируя об успехе. Если же для всех зон ни одно из правил не выполнено, функция возвращает 0, сообщая что ни одна из активных зон не сработала.

Вот мы и закончили обсуждение класса активных зон. Я рекомендую вам вернуться к рассмотренной программе и поэкспериментировать с ней, добавляя собственные активные зоны. Попытайтесь добавить другие меню и посмотрите, что получится.