The Russian Electronic Developer Magazine | |
Русский электронный журнал разработчика | |
Зачем это все нужно? Прежде всего, эта библиотека не есть нечто всеобъемлющее. Поэтому в первую очередь она приспособлена для создания небольших программ. Кроме того, размеры в этом случае имеют немаловажное значение, из-за чего она, собственно, и была сделана на голом API без применения чего-то готового в качестве базы.
Ну а теперь по порядку. Основная идея лежащая в основе Cell Toolkit - то, что всякое окно можно разделить на два, либо по горизонтали, либо по вертикали. Затем к этой базовой идее были прицеплены шашечки в виде возможностей иметь заданые заранее пропорции частей окна, сплитбар, возможность фиксировать размер подокна, и т.д. Затем были добавлены тулбары, с возможностью парковки их на любую границу окна. Наконец, я написал несколько примеров, которые, я надеюсь, помогут разобраться с библиотекой.
+---------+ | | +---------+ | | +---------+Или так:
+----+----+ | | | | | | | | | +----+----+Если разрешить делить вложеные окна, то можно получить, например, вот такую конструкцию:
+----+----+ | | | +----+----+ | | +---------+Так, например, выглядит читалка ньюсов в Netscape 2.02. А вот так выглядит PMMail 2.0:
+---+-----+ | | | | +-----+ | | | Рис.1 +---+-----+Как не трудно догадаться это и есть те самые split view. Очень удобно для использования, но довольно редко реализуемое решение. Хотя на самом деле никаких особых сложностей нет. Заглянем вовнутрь же Cell Toolkit.
Для реализации split view был выбран следующий подход. Окно, которое должно содержать split view разбивается на ячейки, например для такого окна которое изображено на Рис.1 такая разбивка выглядит так:
+---------+ | | Главное окно | | | | +---------+ / \ / \ +-----+ верхняя панель +---+ +---+ / | | | | | | / +-----+ | | | | \ +-----+ нижняя панель | | | | \ | | +---+ +---+ +-----+ левая правая панель панельКроме того, между панелями находится сплитбар, который обеспечивает возможность пользователю изменять соотношение размеров панелей. Сами панели и есть теми целевыми окнами, в которых происходит реальная работа пользователя: редактируется текст, просматриваются списки и т.д. Исключение в данном случае представляет собой правая панель, поскольку она является фреймом для вложеного split view. Хорошо видно, что все окна можно разбить на два вида: фреймы и конечные окна.
Для реализации фреймов используется достаточно простая и хорошо зарекомендовавшая себя техника subclassing. То есть, берется какой-либо стандартный класс и ему подменяется обработчик сообщений в результате чего можно видоизменить поведение такого окна. И для фреймов, естественно ;-) наиболее подходящим кандидатом является Frame Window. Что нам от него нужно в первую очередь, так это правильно разместить вложеные окна. Для этого достаточно перехватить два сообщения:
WM_QUERYFRAMECTLCOUNTПервое сообщение возвращает количество подчиненных окон, а второе непосредственно отвечает за укладку этих элементов по площади окна. Подробности можно найти в функции CellProc.
WM_FORMATFRAME
Остается решить вопрос со сплитбаром. Как оказалось, самое простое решение это регистрация соответствующего класса и при создании фрейма в качестве класса для клиентского окна указывать этот класс. Это заметно упрощает жизнь, поскольку манипуляциями с этим окном в основном озабочен старый обработчик Frame Window. Все, что нужно - это правильно установить размер сплитбара при обработке WM_FORMATFRAME, не забыть его прорисовать и при прохождении курсора мыши над сплитбаром не забыть поменять форму курсора. Есть еще одна вещь, за которую тоже отвечает сплитбар: изменение размеров панелей. Детали этих действий можно найти в функции CellClientProc.
Теперь немножко о тулбарах. Непосредственно тулбар - это тоже фрейм, в котором расположены кнопки. Кнопки это обычные Push Button. Чего-то необычного в них нет, кроме, пожалуй, "пузырьковой" подсказки. Впрочем это сделано достаточно традиционным способом (subclassing), а техника создания такой подсказки была в деталях описана в одном из выпусков EDM/2.
Для реализации возможности присоединения/отсоединения тулбара не пришлось проделывать каких-то необычных трюков. Оказалось, что достаточно поменять окно-родитель для тулбара и он из части основного окна превратится в независомое окно или наоборот, из независимого окна станет частью окна программы.
Для сборки библиотеки и примеров понадобятся:
Сборка под другие компиляторы делается в два этапа:
typedef struct stCellDef { LONG lType; PSZ pszClass; PSZ pszName; ULONG ulStyle; ULONG ulID; struct stCellDef* pPanel1; struct stCellDef* pPanel2; PFNWP pClassProc; PFNWP pClientClassProc; LONG lSize; } CellDef;
CELL_WINDOW | Ячейка является окном (контролом) |
CELL_VSPLIT | Контейнер ячеек поделен по вертикали |
CELL_HSPLIT | Контейнер поделен по горизонтали |
CELL_SPLITBAR | Контейнер содержит splitbar |
CELL_FIXED | Размер нельзя изменять, даже при наличии splitbar |
CELL_SIZE1 | Точный размер указан для панели 1 (нижняя или левая) |
CELL_SIZE2 | Точный размер указан для панели 2 (верхняя или правая) |
CELL_SPLIT10x90 | Флаги задающие начальное отношение размеров ячеек |
CELL_SPLIT20x80 | |
CELL_SPLIT30x70 | |
CELL_SPLIT40x60 | |
CELL_SPLIT50x50 | |
CELL_SPLIT60x40 | |
CELL_SPLIT70x30 | |
CELL_SPLIT80x20 | |
CELL_SPLIT90x10 |
Например, структура CellDef, заполненая таким образом:
CellDef lPanel = { CELL_VSPLIT | CELL_SPLITBAR | CELL_SPLIT70x30, 0, "", WS_VISIBLE, ID_LPANE, &uPanel, &dPanel };создает разделенную по вертикали панель, с пропоциями левой и правой частей 70 к 30 и с описаниями внутренностей панелей в соответствующих структурах.
Примеры таких структур Вы найдете в multibar.c. Один из интересных примеров использования этой техники приведен в nbsample.c.
Затем используя описанные таким образом окна их можно создавать с помощью функции CreateCell. Кроме указателя на структуру-описатель, ей передаются два хендла окон: родитель и владелец. (Для тех, кто еще не разобрался в разнице между ними: родитель - это то окно, которое формально владеет окном, то есть отвечает за его положение на экране, поскольку координаты создаваемого окна отсчитываются от родителя, за видимость и уничтожение. Владелец - это то окно, которое будет получать сообщения, точнее уведомления от данного окна. Например, кнопка, у которой родителем указан десктоп, а владельцем окно Вашей программы, будет располагаться на десктопе, но сообщения о ее нажатии будет получать процедура обработки сообщений окна в Вашей программе). Для главного окна обычно указывают родитилем HWND_DESKTOP, а владельцем 0. Детали создания ячеек можно посмотреть в cell.c, процедура CreateCell.
typedef struct { LONG lType; // Toolbar flags ULONG ulID; // Toolbar window ID ULONG *tbItems; } TbDef;
TB_BUBBLE - Тулбар имеет пузырьковую подсказку TB_VERTICAL - Расположен вертикально TB_FLOATING - Не присоединен к окну. TB_ATTACHED_LT - Присоединен слева TB_ATTACHED_TP - -//-//-//-- сверху TB_ATTACHED_RT - -//-//-//-- справа TB_ATTACHED_BT - -//-//-//-- снизуОписание кнопок - это массив ULONG-ов, каждый из которых задает ID кнопки, и завершается 0. Специальный ID TB_SEPARATOR задает разделитель между кнопками на панели. Для каждой кнопки в файле ресурсов должен быть припасен битмап с таким же ID (смотрите примеры программ). Для TB_SEPARATOR ресурс не нужен. Если для тулбара указан флаг TB_BUBBLE, то обязательно наличие в файле ресурсов ресурса типа STRINGTABLE, и соответствующими ID.
Тулбар создается с помощью вызова CreateToolbar и становится частью окна.
Есть несколько (один) известный мне баг и одна недоработка.
Известный баг состоит в потере некоторого количества тулбаров при уменьшении
размеров окна, а также при минимизации/восстановлении. Буду рад если кто-либо
сумеет раскопать причину этой досадной проблемы и сообщит мне.
Недоработка состоит в полном отсутствии статусной строки как отдельной
сущности в библиотеке. Посмотрите на status.c и скажите, а нужно ли?
Да, пользоваться Cell Toolkit можно совершенно свободно, при условии, сохранения моего (С) и при условии, что Вы не забудете помянуть меня в credits Вашей программы.
Все замечания, пожелания, багрепорты, фиксы, пиво, коку, деньги и просто открытки можно направлять на:
e-mail: evsi@naverex.kiev.ua
FIDO : 2:463/114.69
Sergey I. Yevtushenko.
Интересные ссылки:
Комментариев к странице: 0 | Добавить комментарий
Редактор: Дмитрий Бан
Оформление: Евгений Кулешов