![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Исходные тексты
Демонстрационный проект
Необходимость в создании класса рамки возникла в процессе разработки дизайнера форм и отчетов поставляемого компанией “R-Style Softlab” инструментального комплекса RS-Forms, а точнее, лежащего в его основе контейнера управляющих элементов ActiveX. Рамка является основным инструментом задания положения и размеров внедряемых в ActiveX-контейнер управляющих элементов (отсюда и название класса – CAxTracker). Проект дизайнера разрабатывался (и продолжает разрабатываться) на основе библиотек ATL/WTL, что не позволяло непосредственно использовать входящий в состав MFC класс CRectTracker. К тому же хотелось, чтобы рамка выглядела более привлекательно; предоставляла возможность управления множеством активных областей – манипуляторов, определяющих набор действий над выделенным объектом; позволяла, при необходимости, легко добавлять новые стили отображения; и, главное, способствовала удобной реализации различных стратегий выравнивания элементов.
Рис. 1. Стили отображения рамки, контур рамки, TrackLines
В конечном итоге класс CAxTracker можно использовать как в ATL/WTL – проектах, так и в проектах на основе MFC; он обеспечивает возможность реализации эффекта ожидаемогоприлипания контура рамки к узлам сетки либо другим элементам при его перемещении; поддерживает несколько стилей отображения рамки (см. рис. 1), концепцию TrackLines, а также режимы учета отступов и перекрытий.
ПРИМЕЧАНИЕ Область применения класса не ограничивается задачей размещения управляющих элементов в ActiveX-контейнере – связь с технологией ActiveX состоит исключительно в названии класса и носит исторический характер. Ряд идей, в частности, реализация функции Track с использованием цикла выборки сообщений, были позаимствованы из упомянутого выше класса CRectTracker. |
Под “ожидаемым прилипанием” подразумевается такой способ выбора точек прилипания, при котором не происходит смещения (скачков) контура рамки в сторону противоположную его движению. Без дополнительного внимания такое смещение легко может возникнуть в случае обеспечения прилипания не только верхней, левой границ, но и правой, нижней.
Вообще говоря, расчет точки прилипания контура рамки в процессе его перемещения – это отдельная интересная задача, которая выходит за границы рассматриваемого класса, однако класс предоставляет всю необходимую информацию для того, чтобы такой расчет выполнить корректно.
TrackLines – это линии, отражающие в процессе позиционирования контура рамки факт совпадения координат какой-либо из его границ с координатами границ графических объектов, находящихся в непосредственной близости от контура (см. рис. 1).
Режимы учета отступов и перекрытий позволяют, прозрачно для реализующего алгоритм расчета точек прилипания клиента класса, осуществлять выравнивание элементов на определенном расстоянии друг от друга.
Рис. 2. Выравнивание элементов друг относительно друга с учетом отступов
В режиме учета отступов вокруг контура рамки, обозначающего границы позиционируемого элемента, отображается еще один (внешний) контур, отстоящий от исходного на заданном расстоянии (см. рис. 2), для которого и ведется расчет точек прилипания. Внешний контур может учитывать отступ по горизонтали, отступ по вертикали или отступы по горизонтали и вертикали одновременно.
Режим учета перекрытий функционирует аналогично с той лишь разницей, что в нем используется не внешний, а внутренний контур. Этот режим позволяет, в частности, легко и быстро создавать аналоги табличных структур с предопределенным видом и типом границ ячеек из простых управляющих элементов (таких как Label) – например, при разработке печатных форм платежных поручений.
Включение режимов осуществляется путем нажатия и удержания соответствующих клавиш.
В большинстве случаев, объект класса рамки является полем класса окна, отвечающего за отображение графических элементов и управление их расположением. Многие настройки, регулирующие обычно не требующие изменения аспекты поведения и отображения рамки, задаются через параметры конструктора. Для взаимодействия рамки с внешним окружением определен исходящий интерфейс – интерфейс событий рамки. Этот интерфейс реализуется содержащим рамку классом окна, указатель на него передается в конструктор объекта-рамки.
Множество поддерживаемых рамкой методов можно условно разделить на две группы: сервисные методы получения и задания атрибутов рамки и методы – обработчики windows-сообщений родительского класса окна, в той их части, что касается рамки. Отображение рамки, установка курсоров для активных областей и пр. организуется посредством вызова подходящих методов рамки в обработчиках соответствующих событий класса окна. Информация о размерах графического элемента, вокруг которого необходимо отобразить рамку, запрашивается объектом-рамкой через метод исходящего интерфейса.
В целях оптимизации перерисовки и исключения эффекта мигания при смене выделенного элемента класс рамки поддерживает функцию, возвращающую занимаемый рамкой (либо некоторой ее частью) регион.
В процессе позиционирования контура рамки для каждого промежуточного положения посылается специальное событие, позволяющее это положение скорректировать (и таким образом реализовать функцию выравнивания); по окончании процесса посылается еще одно событие, предназначенное для фиксации нового расположения выделенного элемента.
CAxTracker (IAxTrackerEvents* pEv = NULL, unsignedchar width = 6, unsignedshort delay = 300, int vkHorz = 'Q', int vkVert = 'W', int vkInner = 'E'); |
pEv | указатель на исходящий интерфейс (см. далее) |
width | ширина рамки |
delay | задержка (в миллисекундах) первого появления контура рамки при старте процесса позиционирования |
vkHorz, vkVert, vkInner | виртуальные коды клавиш перехода в режим учета отступов по горизонтали, режим учета отступов по вертикали и переключения в режим учета перекрытий |
Обработчик событий может быть задан и после конструирования объекта рамки – для этого предусмотрен метод IAxTrackerEvents* SetEvHandler (IAxTrackerEvents* pEv).
По умолчанию, все манипуляторы рамки являются активными, стиль отображения – TSF_APPEALBORDER (см. рис. 1). Для изменения стилей отображения и коррекции множества манипуляторов предназначен метод void SetStyle (unsigned short uStyle).
void Draw (CDC& dc);
|
Метод рисует рамку в заданных стилях в контексте dc; предназначен для использования в обработчике сообщения WM_PAINT (в функции OnDraw). Размеры рамки определяются через событие void OnGetDrawingRect (/*[out]*/ CRect& rc) (см. далее).
void GetEraseRegion (/*[out]*/ HRGN& hRgn, unsignedshort rt = rtFull) const; |
В общем случае метод возвращает занимаемый (затираемый) рамкой регион. По завершении работы с регионом его необходимо освободить посредством вызова функции Win32 API DeleteObject (HGDIOBJ hRgn).
bool SetCursor (HWND hWnd, UINT hitTest) const; bool SetCursor (TrackerHit hitTest) const; |
hWnd | описатель содержащего рамку окна |
hitTest | в первом случае – hit-test код, приходящий в сообщение WM_SETCURSOR; во втором – идентификатор области рамки |
Методы предназначены для сопоставления областям рамки различных курсоров мыши; используются в обработчике сообщения WM_SETCURSOR.
Для определения области рамки, соответствующей заданным координатам, предусмотрена функция TrackerHit HitTest (const CPoint& pt) const; множество областей определяется перечислением TrackerHit, во многом повторяющим одноименное перечисление, используемое в классе CRectTracker.
bool Track (HWND hWnd, const CPoint& pt, bool bRubberBand = false, unsignedshort OuterIndentX = 0, unsignedshort OuterIndentY = 0, unsignedshort InnerIndentX = 0, unsignedshort InnerIndentY = 0, bool bDraw = true) const; |
hWnd | описатель содержащего рамку окна |
pt | текущее положение курсора мыши в клиентских координатах |
bRubberBand | требуется отображение резинового контура без привязки к текущему положению рамки |
OuterIndentX, OuterIndentY | отступы внешнего track-контура по ширине и высоте |
InnerIndentX, InnerIndentY | отступы внутреннего track-контура по ширине и высоте |
bDraw | требуется ли отображение контура в процессе его позиционирования |
В этом методе инкапсулирована вся работа с контуром рамки: первичное, возможно отложенное, появление контура, изменение его положения или размеров в зависимости от области, которой соответствует точка pt, переход в режим учета отступов или перекрытий.
Метод осуществляет захват мыши, запускает собственный цикл выборки сообщений, является генератором большинства событий класса; обычно используется в обработчике события WM_LBUTTONDOWN.
void OnChangingRect (/*[in][out]*/ CRect& rc, CAxTracker::TrackerHit hitTest, const CRect& rcPrev, bool bMoveLeft, bool bMoveTop, long IndentX, long IndentY, CAxTracker::ITrackLines* lpTrackLines); |
rc | новое (следующее) положение контура рамки |
hitTest | идентификатор области рамки |
rcPrev | предыдущее положение контура рамки |
bMoveLeft, bMoveTop | направление движения по горизонтали, по вертикали |
IndentX, IndentY | величины текущих отступов |
lpTrackLines | указатель на коллекцию TrackLines |
Событие предназначено для коррекции нового положения контура рамки перед его перемещением в это положение. Именно оно обеспечивает возможность реализации эффекта прилипания контура к границам графических объектов или узлам сетки, а также формирования множества линий, показывающих равенство координат границ контура и графических элементов.
Все то множество параметров, которое передается в этот метод, служит цели более точного расчета точки прилипания в условиях наличия достаточно большого количества таких точек.
void OnChangedRect (const CRect& rcNew); |
Событие генерируется по завершении процесса позиционирования контура; предназначено для фиксации нового положения выделенного посредством рамки объекта.
void OnGetDrawingRect (/*[out]*/ CRect& rc); |
Вызывается из методов Draw и Track для определения размеров графического объекта, вокруг которого необходимо отобразить рамку.
void OnDrawTrackerRect (CDC& dc, const CRect& rc); |
Генерируется перед отображением/стиранием контура рамки.
Реализовать выделение группы графических элементов (см. рис. 1) можно посредством сопоставления (через объект некоторого промежуточного класса) каждому элементу этой группы собственного ассоциированного с ним (через метод исходящего интерфейса OnGetDrawingRect) объекта класса CAxTracker.
Кроме того, можно поддержать синхронное отображение контуров рамок в процессе позиционирования одной из них – специально для этого предусмотрены событие OnDrawTrackerRect и метод DrawTrackerRect (CDC& dc, const CRect& rc).
ATL/WTL – проекты, в которых предполагается использование класса CAxTracker, требуют дополнительной настройки. Необходимо:
Все аспекты использования класса CAxTracker и достигаемые при этом результаты иллюстрируются дизайнером форм и отчетов, входящим в состав инструментального комплекса RS-Forms – продукта компании “R-Style Softlab”, предназначенного для создания расширяемых распределенных приложений с графическим интерфейсом пользователя. Демо-версия RS-Forms доступна по адресу: members.softlab.ru/kubrin/rsforms.htm.
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |