Операционная система дает возможность программам определять размер окна,
размер клиентской области, позицию указателя мыши на экране и многое другое,
используя структуры RECT, POINT и SIZE. Но эти структуры довольно неудобно
использовать. Эта статья расскажет вам, как реализовать классы, которые позволят
использовать все возможности вышеприведенных структур, и упростят использование
функций связанных с ними. Достоинство этих классов, заключается в том, что
существует возможность их использования в любых Win32 приложениях, без
подключения каких либо других файлов. Для того чтобы использовать эти классы в
своих приложениях достаточно подключить заголовочный файл требуемого класса в
файл реализации, использующий эти классы.
Для начала определимся с
названиями. Дадим им имена TRect, TPoint и TSize. Имена обусловлены тем, что эти
классы будут являться производными от структур RECT POINT и SIZE соответственно.
Каждый из этих классов унаследуют следующие целочисленные
переменные-члены: TRect – left, top, right, bottom от структуры
RECT. TPoint – x,y от структуры POINT. TSize – cx,cy от структуры
SIZE.
Функции арифметики всех трех классов будут использовать
соответствующие функции Win32. Во всех классах, декларации структуры, оберткой
которой является класс, будут помещены в защищенный раздел класса. Это
предотвратит нежелательный доступ непосредственно к данным самой структуры.
Доступ будет реализован средствами класса.
Класс
TSize.
Члены структуры SIZE имеют тип LONG. По этому большинство
функций-членов класса будут оперировать именно с этим типом данных. Как было
сказано выше, декларация структуры будет помещена в защищенный раздел
класса. class TSize { public: protected: SIZE
m_Size; }; Добавим в этот класс конструктор и деструктор. Деструктор в
конкретном случае будет виртуальным, и ничего полезного делать не будет. Точнее
он вообще не будет ничего делать, как и в оставшихся двух классах.
Конструкторов же у этого класса будет два, как , впрочем, и у TRect и
TPoint. Первый конструктор будет конструктором по умолчанию, предназначенным
для первоначальной инициализации класса и заполнения всей структуры нулями.
Второй конструктор применяется только в том случае, если при декларации класса,
в конструктор переданы аргументы. В этом случае параметры внутренней структуры
SIZE инициализируются переданными значениями.
class TSize
{
public:
// Инициализируем TSize переданными значениями или 0
TSize( int cx = 0, int cy = 0 )
{ m_Size.cx = cx; m_Size.cy = cy; }
/// Инициализируем TSize значениями из другой структуры SIZE
TSize( const SIZE& sz )
{ m_Size = sz; }
// Виртуальный деструктор, не делает ничего.
virtual ~TSize()
{}
protected:
SIZE m_Size;
};
Пока ничего полезного этот класс не делает. Добавим ему
функциональности, которой не хватает структуре SIZE. Добавим функцию
реализующую сравнение объекта с существующей структурой SIZE.
inline BOOL IsEqual( const SIZE& sz ) const
{ return ( sz.cx == m_Size.cx && sz.cy == m_Size.cy ); }
Что мы здесь делаем? Сравниваем члены внутренней переменной SIZE класса с
переданной переменной sz.
Обеспечим класс функциями, позволяющими к
переменным внутренней структуры добавлять или вычитать некоторые значения: // Добавляет переданные размеры к существующим
inline void Add( int cx, int cy )
{ m_Size.cx += cx; m_Size.cy += cy; }
inline void Add( const SIZE& sz )
{ m_Size.cx += sz.cx; m_Size.cy += sz.cy; }
inline void AddCX( int cx )
{ m_Size.cx += cx; }
inline void AddCY( int cy )
{ m_Size.cy += cy; }
// Вычитает переданные размеры из существующих
inline void Subtract( int cx, int cy )
{ m_Size.cx -= cx; m_Size.cy -= cy; }
inline void Subtract( const SIZE& sz )
{ m_Size.cx -= sz.cx; m_Size.cy -= sz.cy; }
inline void SubtractCX( int cx )
{ m_Size.cx -= cx; }
inline void SubtractCY( int cy )
{ m_Size.cy -= cy; }
Все эти функции, в принципе, делают то же самое, что и функция IsEqual.
Только функция IsEqual сравнивает члены внутренней структуры с членами
переданной, а эти или добавляют или вычитают переданные параметры из членов
внутренней структуры. Так же введем функции, позволяющие получить значения
членов внутренней структуры SIZE. // Возвращает сx или сy координату.
inline int& CX() const
{ return ( int& )m_Size.cx; }
inline int& CY() const
{ return ( int& )m_Size.cy; }
Эти функции позволяют, и получать значения внутренней переменной и
изменять их. Реализуем четыре базовых вида перегруженных операторов,
применимых только к структуре SIZE. Операторы сложения, вычитания, присваивания,
сравнения и преобразования. // Перегруженные операторы преобразования.
inline operator SIZE*()
{ return &m_Size; }
inline operator SIZE() const
{ return m_Size; }
// Перегруженные операторы присваивания
inline void operator=( const SIZE& sz )
{ m_Size = sz; }
inline void operator=( LPSIZE sz )
{ m_Size = *sz; }
// Перегруженные операторы сравнения
inline BOOL operator==( const SIZE& sz ) const
{ return IsEqual( sz ); }
inline BOOL operator!=( const SIZE& sz ) const
{ return !IsEqual( sz ); }
// Перегруженные операторы сложения
inline void operator+=( const SIZE& sz )
{ Add( sz ); }
inline TSize operator+( const SIZE& sz ) const
{ TSize szTmp( *this ); szTmp += sz; return szTmp; }
// Перегруженные операторы вычитания
inline void operator-=( const SIZE& sz )
{ Subtract( sz ); }
inline TSize operator-( const SIZE& sz ) const
{ TSize szTmp( *this ); szTmp -= sz; return szTmp; }
Все эти операторы очень пригодятся для упрощения написания программы. Они
позволяют производить следующие манипуляции с этим классом:
Приводить класс TSize к типу SIZE* или SIZE
Сравнивать класс TSize со структурой SIZE
Приравнивать класс TSize к SIZE* или SIZE
Складывать класс TSize со структурой SIZE
Вычитать класс TSize и структуру SIZE друг из друга
Класс TPoint
Класс TPoint по реализации
ничем не отличается от класса TSize, по этому детально рассмотрен не будет. Все
названия функций идентичны. Отличие состоит в том, что класс TSize манипулирует
структурой SIZE, а класс TPoint структурой POINT.
Класс
TRect
Этот класс представляет интерес по следующим причинам.
Практически все функции, связанные с определением и изменением размеров окон,
манипулируют структурой RECT в той или иной мере. Да и функций, применяющих эту
структуру довольно много. Как и два предыдущих класса, этот класс имеет в
защищенном разделе декларацию структуры. Отличие состоит в том, что в этом
классе, объявлена структура RECT. Конструкторы и деструкторы те же, но
манипулируют структурой RECT.
class TRect
{
public:
// Инициализируем TRect переданными значениями или 0
TRect( LONG left = 0, LONG top = 0, LONG right = 0, LONG bottom = 0 )
{
m_Rect.left = left;
m_Rect.top = top;
m_Rect.right = right;
m_Rect.bottom = bottom;
}
// Инициализируем TRect значениями из другой структуры RECT
TRect( const RECT& rc )
{ m_Rect = rc; }
// Виртуальный деструктор, не делает ничего.
virtual ~TRect()
{}
protected:
RECT m_Rect;
};
Также этот класс имеет все функции для работы с
прямоугольниками:
CopyRect Копирует координаты одного
прямоугольника в другой EqualRect Определяет, являются ли
два указанных прямоугольника равными, сравнивая координаты их левых верхних и
нижних правых углов. InflateRect Увеличивает или уменьшает
ширину и высоту указанного прямоугольника. IntersectRect
Вычисляет пересечение двух исходных прямоугольников и помещает координаты
пересечения прямоугольников в прямоугольник
назначения IsRectEmpty Определяет, является ли указанный
прямоугольник пустым. OffsetRect Перемещает указанный
прямоугольник на указанное смещение PtInRect Определяет,
находится ли указанная точка в пределах указанного
прямоугольника. SetRect Устанавливает координаты указанного
прямоугольника. SetRectEmpty Создает пустой прямоугольник,
в котором все координаты установлены на ноль. SubtractRect
Определяет координаты прямоугольника, сформированного путем вычитания одного
прямоугольник из другого. UnionRect Создает объединение
двух прямоугольников.
Подробнее обо всех этих функциях вы можете
прочитать на этом сайте в разделе MSDN по-русски. Реализацию
всех функций вы можете посмотреть в предоставленном ниже листинге. В
заключение хотелось бы добавить несколько слов. При написании программ очень
сильно помогают макросы. Добавим макросы, позволяющие упростить декларацию
этих классов: Для класса TPoint:
#define EMPTY_POINT TPoint(0,0)
этот макрос упрощает декларацию класса, у которого все члены нулевые.
#define BREAK_POINT(p) p.X(), p.Y()
этот макрос делает подстановку в функцию, в которую требуется передать несколько параметров. Например:
Есть функция
func(int x, int y);
В нее требуется передать 2 параметра. Если имеется только структура TPoint то передача параметров выглядела бы так:
func(p.X(), p.Y());
Используя этот макрос это бы выглядело так:
func(BREAK_POINT(p));
Для класса TSize:
#define EMPTY_SIZE TSize(0,0)
#define BREAK_SIZE(p) p.CX(), p.CY()
Эти макросы подобны макросам класса TPoint
Для класса TRect:
#define EMPTY_RECT TRect(0,0,0,0)
#define BREAK_RECT (r) r.Left(), r.Top(), r.Right(), r.Bottom()
Эти макросы подобны макросам класса TPoint
#define BREAK_WIDTH_HEIGHT_RECT (r) r.Left(), r.Top(), r.Width(), r.Height()
А этот макрос реализует то же, что и предыдущий, только вместо использования координат правой и нижней сторон используются ширина и высота прямоугольника.
При разработке CMS S.Builder наша команда
активно использовала AJAX. Теперь вот решили поделиться накопленным
опытом. Начнем с этого хабратопика. Не буду здесь затрагивать различные
фреймворки и библиотеки. Свой код всегда роднее. Для работы с AJAX-ом в
S.Builder написана библиотека
sbAJAX. Можете качать и пользоваться :). В этом файле есть функция
sbEvalJS. Для тех, кто не знает, объясню. При подгрузке через AJAX и вставке
на страницу HTML-кода, содержащего JavaScript, JavaScript выполняться не будет
или полезут баги. Эта функция как раз решает поставленную задачу.
Хотя наш обзор немного запоздал, оригинальный Dojo 1.2 вышел в релизной
версии ещё 6-го октября, но сейчас мы наверстаем упущенное. И так, Dojo Toolkit — это самая мощная и
гибкая ajax-библиотека из всех, что есть на рынке, она активно развивается и
имеет большое комьюнити. Кстати, это самое комьюнити, совместно с компанией
Sitepen, имеет ещё несколько проектов, среди которых и Cometd и некоторые
другие, не менее интересные, о которых мы скоро вам расскажем. Сегодня же все
внимание на флагманский продукт —
Dojo
1.2.
Если вы профессиональный веб-разработчик и постоянно имеете дело с
разработкой и отладкой сложных AJAX приложений, то наверняка знаете и
используете Firebug — плагин для браузера
Firefox, предназначенный для отладки и исследования веб-приложений. Текущая его
версия, 1.2х достаточно стабильная и функциональна, чтобы помочь в 99% проблем,
которые могут возникнуть при разработке. Но и этот инструмент не лишён если не
недостатков, то некоторых фич, которые могли бы облегчить работу. И даже
идеальный инструмент можно сделать ещё более идеальным, как бы это не звучало.