Классы обертки для структур RECT POINT и SIZE

Пример к статье
Автор: Куковинец А.В

Операционная система дает возможность программам определять размер окна, размер клиентской области, позицию указателя мыши на экране и многое другое, используя структуры 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()
А этот макрос реализует то же, что и предыдущий, только вместо использования координат правой и нижней сторон используются ширина и высота прямоугольника.
Ниже приведен листинг всех классов.
//==========Предотвращение многократного включения заголовочного файла==========
#ifndef TRECT_H
#define TRECT_H
//==============================================================================
#include <windows.h>
/*==============================================================================
Класс
    TSize
Назначение
    Обертка системного класса 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()
    {}

    // Сравниваем два размера.
    inline BOOL IsEqual( const SIZE& sz ) const
    { return ( sz.cx == m_Size.cx && sz.cy == m_Size.cy ); }

    // Добавляет переданные размеры к существующим
    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; }

    // Возвращает сx или сy координату.
    inline int& CX() const
    { return ( int& )m_Size.cx; }
    inline int& CY() const
    { return ( int& )m_Size.cy; }

    // Перегруженные операторы преобразования.
    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; }

protected:
    SIZE    m_Size;
};
/*==============================================================================
Класс
    TPoint
Назначение
    Обертка системного класса PIONT
Примечания
==============================================================================*/

class TPoint
{
public:
    /// Инициализируем TPoint переданными значениями или 0
    TPoint( LONG x = 0, LONG y = 0 )
    { m_Point.x = x; m_Point.y = y; }

    // Инициализируем TPoint значениями из другой структуры POINT
    TPoint( const POINT& pt )
    { m_Point = pt; }

    // Виртуальный деструктор, не делает ничего.
    virtual ~TPoint()
    {}

    // Сравниваем две точки
    inline BOOL IsEqual( const POINT& pt ) const
    { return ( pt.x == m_Point.x && pt.y == m_Point.y ); }

    // Возвращаем TRUE если координаты 0,0
    inline BOOL IsEmpty() const
    { return ( m_Point.x == 0 && m_Point.y == 0 ) ? TRUE : FALSE; }

    // учищаем координаты точки.
    inline void Empty()
    { m_Point.x = m_Point.y = 0; }

    // Добавляет переданные координаты к существующим
    inline void Add( LONG x, LONG y )
    { m_Point.x += x; m_Point.y += y; }
    inline void Add( const POINT& pt )
    { m_Point.x += pt.x; m_Point.y += pt.y; }
    inline void AddX( LONG x )
    { m_Point.x += x; }
    inline void AddY( LONG y )
    { m_Point.y += y; }

    // Вычитает переданные координаты из существующих
    inline void Subtract( LONG x, LONG y )
    { m_Point.x -= x; m_Point.y -= y; }
    inline void Subtract( const POINT& pt )
    { m_Point.x -= pt.x; m_Point.y -= pt.y; }
    inline void SubtractX( LONG x )
    { m_Point.x -= x; }
    inline void SubtractY( LONG y )
    { m_Point.y -= y; }

    // Возвращает x или y координату.
    inline LONG& X() const
    { return ( LONG& )m_Point.x; }
    inline LONG& Y() const
    { return ( LONG& )m_Point.y; }

    // Перегруженные операторы преобразования.
    inline operator POINT*()
    { return &m_Point; }
    inline operator POINT() const
    { return m_Point; }

    // Перегруженные операторы присваивания
    inline void operator=( const POINT& pt )
    { m_Point = pt; }
    inline void operator=( LPPOINT pt )
    { m_Point = *pt; }

    // Перегруженные операторы сравнения
    inline BOOL operator==( const POINT& pt ) const
    { return IsEqual( pt ); }
    inline BOOL operator!=( const POINT& pt ) const
    { return !IsEqual( pt ); }

    // Перегруженные операторы сложения
    inline void operator+=( const POINT& pt )
    { Add( pt ); }
    inline TPoint operator+( const POINT& pt ) const
    { TPoint ptTmp( *this ); ptTmp += pt; return ptTmp; }

    // Перегруженные операторы вычитания
    inline void operator-=( const POINT& pt )
    { Subtract( pt ); }
    inline TPoint operator-( const POINT& pt ) const
    { TPoint ptTmp( *this ); ptTmp -= pt; return ptTmp; }

protected:
    POINT   m_Point;
};
/*==============================================================================
Класс
    TRect
Назначение
    Обертка системного класса 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()
    {}

    // Нормализуем прямоугольник. Удостоверимся что верхняя/левая координаты 
    // меньше чем нижняя/правая координата.
    void Normalize()
    {
        // Меняем местами левую и правую координату при необходимости
        if ( m_Rect.left > m_Rect.right )
        {
            LONG    temp = m_Rect.left;
            m_Rect.left  = m_Rect.right;
            m_Rect.right = temp;
        }
        //  Меняем местами верхнюю и нижнюю координату при необходимости
        if ( m_Rect.top > m_Rect.bottom )
        {
            LONG    temp  = m_Rect.top;
            m_Rect.top    = m_Rect.bottom;
            m_Rect.bottom = temp;
        }
    }

    // Получить/установить  левую координату.
    inline LONG& Left() const
    { return ( LONG& )m_Rect.left; }

    // Получить/установить  правую координату.
    inline LONG& Right() const
    { return ( LONG& )m_Rect.right; }

    // Получить/установить  верхнюю координату.
    inline LONG& Top() const
    { return ( LONG & )m_Rect.top; }

    // Получить/установить  нижнюю координату.
    inline LONG& Bottom() const
    { return ( LONG& )m_Rect.bottom; }

    // Возвращаем  ширину прямоугольника.
    inline LONG Width() const
    { return m_Rect.right - m_Rect.left; }

    // Возвращаем  высоту прямоугольника.
    inline LONG Height() const
    { return m_Rect.bottom - m_Rect.top; }

    // Возвращаем  размер прямоугольника.
    inline TSize Size() const
    { return TSize( Width(), Height()); }

    // Возвращаем  верхнюю/левую координату прямоугольника.
    inline TPoint TopLeft() const
    { return TPoint( m_Rect.left, m_Rect.top ); }

    // Возвращаем  нижнюю правую координату прямоугольника.
    inline TPoint BottomRight() const
    { return TPoint( m_Rect.right, m_Rect.bottom ); }

    // Возвращаем  центр прямоугольника.
    inline TPoint CenterPoint() const
    { return TPoint( (( m_Rect.left + m_Rect.right ) / 2 ), (( m_Rect.top + m_Rect.bottom ) / 2 )); }

    // Определяем высота или ширина прямоугольника <= 0.
    inline BOOL IsEmpty() const
    { return ::IsRectEmpty( &m_Rect ) ? TRUE : FALSE; }

    // Определяем что не все координаты в прямоугольнике равны 0
    inline BOOL IsNull() const
    { return ( m_Rect.left == 0 && m_Rect.top == 0 && m_Rect.right == 0 && m_Rect.bottom == 0 ) ? TRUE : FALSE; }

    // Определяем что два прямоугольника совпадают
    inline BOOL IsEqual( const RECT& rc ) const
    { return ::EqualRect( &m_Rect, &rc ) ? TRUE : FALSE; }

    // Определяем что точка находится в пределах прямоугольника
    inline BOOL PtInRect( const POINT& pt )
    { return ::PtInRect( &m_Rect, pt ) ? TRUE : FALSE; }

    // Сдвигаем прямоугольник.
    inline BOOL Offset( int dx, int dy )
    { return ::OffsetRect( &m_Rect, dx, dy ) ? TRUE : FALSE; }
    inline BOOL Offset( const POINT& pt )
    { return ::OffsetRect( &m_Rect, pt.x, pt.y ) ? TRUE : FALSE; }

    // Раздвигаем прямоугольник.
    inline BOOL Inflate( int dx, int dy )
    { return ::InflateRect( &m_Rect, dx, dy ) ? TRUE : FALSE; }
    inline BOOL Inflate( const SIZE& sz )
    { return ::InflateRect( &m_Rect, sz.cx, sz.cy ) ? TRUE : FALSE; }

    // Раздвигаем прямоугольник.
    inline BOOL Deflate( int dx, int dy )
    { m_Rect.left += dx; m_Rect.top += dy; m_Rect.right -= dx; m_Rect.bottom -= dy; return TRUE; }
    inline BOOL Deflate( const SIZE& sz )
    { m_Rect.left += sz.cx; m_Rect.top += sz.cy; m_Rect.right -= sz.cx; m_Rect.bottom -= sz.cy; return TRUE; }

    // делаем этот прямоугольник из пересечения двух других прямоугольников
    inline BOOL Intersect( const RECT& rc1, const RECT& rc2 )
    { return ::IntersectRect( &m_Rect, &rc1, &rc2 ) ? TRUE : FALSE; }

    // делаем этот прямоугольник из вычитания двух других прямоугольников
    inline BOOL Subtract( const RECT& rc1, const RECT& rc2 )
    { return ::SubtractRect( &m_Rect, &rc1, &rc2 ) ? TRUE : FALSE; }

    // делаем этот прямоугольник из объединения двух других прямоугольников
    inline BOOL Union( const RECT& rc1, const RECT& rc2 )
    { return ::UnionRect( &m_Rect, &rc1, &rc2 ) ? TRUE : FALSE; }

    // Очищаем заначения прямоугольника
    inline BOOL Empty()
    { return ::SetRectEmpty( &m_Rect ) ? TRUE : FALSE; }

    // Перегруженные операторы преобразования.
    inline operator LPRECT()
    { return &m_Rect; }
    inline operator RECT() const
    { return m_Rect; }

    // Перегруженные операторы присваивания
    inline void operator=( const RECT& rc )
    { m_Rect = rc; }
    inline void operator=( LPRECT rc )
    { m_Rect = *rc; }

    // Перегруженные операторы сравнения
    inline BOOL operator==( const RECT& rc ) const
    { return IsEqual( rc ); }
    inline BOOL operator!=( const RECT& rc ) const
    { return !IsEqual( rc ); }

protected:
    RECT    m_Rect;
};
//==============================================================================
#define EMPTY_POINT             TPoint(0,0)
#define BREAK_POINT(p)          p.X(), p.Y()
#define EMPTY_SIZE              TSize(0,0)
#define BREAK_SIZE(p)           p.CX(), p.CY()
#define EMPTY_RECT              TRect(0,0,0,0)
#define BREAK_RECT (r)          r.Left(), r.Top(), r.Right(), r.Bottom()
#define BREAK_WIDTH_HEIGHT_RECT (r) r.Left(), r.Top(), r.Width(), r.Height()

#endif



Опубликовал admin
8 Сен, Среда 2004г.



Программирование для чайников.