Написание приложений Win32 с помощью одних классов C++ (часть 3) - Следующие переделанные возможности

ОГЛАВЛЕНИЕ

SRange<I> и SLimit

Добавлены bool IsEmpty() и bool IsUnit() с очевидным смыслом. compare теперь имеет псевдоним oparator&, когда один из операндов имеет тип I (шаблонный параметр).

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

struct SLimit
{
    template<class A> static A Min(const A& left, const A& right)
    {return (left<right)? left:right; }
    template<class A> static A Max(const A& left, const A& right)
    {return (right<left)? left:right; }
    template<class A> static A& OrMin(A& ref, const A& val)
    { if(val<ref) ref=val; return ref; }
    template<class A> static A& OrMax(A& ref, const A& val)
    { if(ref<val) ref=val; return ref; }
    template<class A> static A
      OrRange(A& rmin, A& rmax, const A& val)
    { OrMin(rmin, val); OrMax(rmax, val); return val; }
    template<class A> static A&
      AndRange(A& ref, const A& min, const A& max)
    { OrMax(ref, min); OrMin(ref, max); return ref; }
};

Обработчики карты сообщений

Во избежание неправильного смешения между ATL, WTL, MFC и макросами было решено снабдить их всех префиксом GE_. Все пространства имен тоже получают префикс GE_, поэтому если он не подходит вам, проведите глобальный поиск и замену во всех файлах! Нет риска путаницы с макросами с такими же именами, делающими почти то же самое, но не обязательно идентичными, особенно в проектах со смешанной средой.

Все они находятся в MessageMap.h, куда были добавлены дополнительные макросы, специализирующие разновидности WM_PARENTNOIFY.

Пересылка, отражение и автоматическое обновление команд

В предыдущей статье был введен способ управления обновлениями команд на базе NWin::ICmdState::SendQueryNoHandler и NWin::ICmdState::SendQueryUpdate.

Эти функции отправляли два закрытых сообщения GE_QUERYCOMMANDHANDLER и GE_UPDATECOMMANDUI. Так как эти сообщения связаны с командами, правильно обращаться с ними как с командами при пересылке или отражении уведомлений.

Чтобы не изменять поведение EWnd всегда, когда нужно новое уведомление, было решено переделать эту возможность (и реализовать будущие возможности на базе уведомительных сообщений) не на основе сообщения WM_USER+xxx, а на основе нового закрытого WM_NOTIFY (чтобы его можно было переслать или отразить).

Кстати, для регистрации кода уведомления использовался SNmHdr (смотрите далее). ICmdState был перемещен в NGDI и сокращен для обработки состояния команды (активно, недоступно, выбрано и текст).

Изображения загружаются из битовых массивов и хранятся с разными эффектами в SCmdImgs, также был определен новый интерфейс ICmdImage для обработки установки и извлечения связи изображений с командами.

Такие интерфейсы связаны с абстрактными структурами, порождаемыми от самих интерфейсов и от NUtil::SNmHdr<> (смотрите далее). Это позволяет отправлять уведомительные сообщения, несущие эти интерфейсы (структуры struct являются SCmdStateNotify и SCmdImageNotify).

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

Эти делается при поддержке EMenuUpdator и EMenuImager, отправляющих те сообщения. Макросы для обработки команд были изменены в соответствии с новой реализацией (серия GE_COMMAND_xx_HANDLER_U), тогда как макросы серии GE_UPDATECOMMANDUI были удалены. Обновление команды можно подключить с помощью нового GE_NOTIFY_xx_REGISTREDHANDLER(..., func, type) с использованием SCmdXxxxNotify в качестве типа при необходимости.

EMenuImager, SCmdImages

Эти классы были переделаны, чтобы сделать рисунки настраиваемыми. В частности, SCmdImgs теперь абстрактный, и SCmdImgsIDE реализует его путем обработки и прорисовки изображений команд. Можно реализовать другие SYourCmdImgs, иначе обрабатывая и рисуя эти изображения.

SCmdDraw использует новый интеллектуальный указатель NWrp::PtrCreator. Этот указатель вообще не дает сбой при разыменовании, вызывая (если NULL) заданную функцию создания. В случае SCmdDraw имеется typdef PtrCreator <SCmdImgs, SCmdImgsIDE::New> PCmdImgs, где "New" является статической функцией, возвращающей new SCmdImgsIDE.

Создание PCmdImgs извлекается с помощью функции static SCmdImgs& GetCmdImgs(). Другая функция (SetCmdImgsType(SCmdImgs* (*pfn)()) очищает PCmdImgs и присваивает его функции создания переданное значение. При следующем разыменовании указателя будет создан новый производный SCmdImgs.

В результате существует один SCmdImgs, извлекаемый с помощью SCmdDraw::GetCmdImgs(), тип которого можно установить при выполнении. То есть, если развернуть несколько "рисовальщиков", можно спроектировать интерфейс, позволяющий пользователю выбрать предпочтительный.

Продолжение следует в четвертой части набора статей по данной теме.