В принципе вопрос о том, как создать свою «неповторимую» ленту Ribbon я частично рассматривал в одном из постов, посвященных Ribbon Controls в Delphi. Однако, ряд моментов, касающихся разработке своего скина для Ribbon все же стоит рассмотреть по-подробнее. В частности процесс отрисовки скина.
Во-первых, если Вы решили создать что-то неповторимое и уникальное в плане цветовой палитры, например, сделать ленту не голубой, а, скажем, розовой (гламур :)), то при работе с bmp-файлом скина следует очень осторожно раскрашивать все элементы — отклонение в пиксел уже может привести к тому, что на выходе в рабочей программе вы получите нечно действительно уникальное, но в плохом смысле — скин будет «кривой».
Во-вторых, если Вы решили рисовать свой скин «с нуля», то следует обратить внимание на вот этот класс:
TRibbonStyleActionBars = class(TXPStyleActionBars)
из модуля RibbonStyleActnCtrls.pas. Так как именно здесь содержатся все необходимые методы «отрисовки» скина по заданному файлу (bmp или res).
в TRibbonStyleActionBars кроме всего прочьего содержится ряд overload-методов, каждый из которых определяет границы прямоугольника в котором содержится изображаемый элемент ленты. Например, вот метод, реализующий отрисовку группы:
procedure TRibbonStyleActionBars.DrawElement(Element: TSkinRibbonGroup; Canvas: TCanvas; Rect: TRect); var LSrcRect: TRect; LDstRect: TRect; begin if Element = srgBackground then begin LSrcRect := Types.Rect(225, 504, 225 + 20, 504 + 86); DrawButton(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect, 3, 3, 255); end else if Element = srgBackgroundHover then begin LSrcRect := Types.Rect(204, 504, 204 + 20, 504 + 86); DrawButton(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect, 3, 3, 255); end else if Element = srgBackgroundDisabled then begin LSrcRect := Types.Rect(246, 504, 246 + 20, 504 + 86); DrawButton(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect, 3, 3, 255); end else if Element = srgMinimizeButton then begin LSrcRect := Types.Rect(275, 208, 275 + 40, 208 + 86); DrawButton(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect, 3, 3, 255); end else if Element = srgMinimizeButtonHover then begin LSrcRect := Types.Rect(315, 208, 315 + 40, 208 + 85); DrawButton(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect, 3, 3, 255); end else if Element = srgMinimizeButtonPressed then begin LSrcRect := Types.Rect(355, 208, 355 + 40, 208 + 85); DrawButton(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect, 3, 3, 255); end else if Element in [srgCaption, srgCaptionHover, srgCaptionDisabled] then begin if Element = srgCaptionHover then LSrcRect := Types.Rect(206, 573, 206 + 16, 573 + 11) else if Element = srgCaptionDisabled then LSrcRect := Types.Rect(248, 573, 248 + 16, 573 + 12) else LSrcRect := Types.Rect(227, 573, 227 + 16, 573 + 12); Rect.Bottom := Rect.Bottom - 4; DrawTransparentBitmap(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect); end else if Element = srgDialogButton then begin LSrcRect := Types.Rect(329, 167, 329 + 15, 167 + 14); DrawTransparentBitmap(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect); end else if Element = srgDialogButtonHover then begin LSrcRect := Types.Rect(344, 167, 344 + 15, 167 + 14); DrawTransparentBitmap(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect); end else if Element = srgDialogButtonPressed then begin LSrcRect := Types.Rect(359, 167, 359 + 15, 167 + 14); DrawTransparentBitmap(RibbonSkin.Bitmap, LSrcRect, Canvas, Rect); end else if Element = srgMinimizeButtonIcon then begin LSrcRect := Types.Rect(396, 208, 396 + 31, 208 + 31); LDstRect := Rect; LDstRect.Right := LDstRect.Left + 31; LDstRect.Bottom := LDstRect.Top + 31; DrawTransparentBitmap(RibbonSkin.Bitmap, LSrcRect, Canvas, LDstRect); end else if Element = srgMinimizeButtonPressedIcon then begin LSrcRect := Types.Rect(396, 240, 396 + 31, 240 + 31); LDstRect := Rect; LDstRect.Right := LDstRect.Left + 31; LDstRect.Bottom := LDstRect.Top + 31; DrawTransparentBitmap(RibbonSkin.Bitmap, LSrcRect, Canvas, LDstRect); end end;
Element представляет собой простой перечислитель с помощью значений которого можно указать процедуре, что именно нам необходимо нарисовать — неактивную группу, активную (когда курсор мыши находится над ней) и т.д.
Обратите также внимание на обилие констант в процедуре, когда определяется переменная LSrcRect — «исходник» изображаемого объекта. Имеено по этому следует с особой осторожностью заниматься перекраской уже готовых скинов.
Опять же, если вдруг захочется создать скин в котором элементы будут располагаться так как Вам этого хочется, то вновь придётся вернуться к DrawElement и указать что и откуда копировать.
Ну, а дальше выполняется метод DrawButton, который отрисовывает на формеэлемент ленты. При этом вначале проверяются линейные размеры исходного изображения и текущих размеров элемента и если размеры совпадают, то изображение из файла скина переносится «как есть», иначе — «исходник» растягивается (ак, например, отрисовывается основа ленты).
Таким образом, чтобы создать новый скин для Ribbon вам необходимо:
1. Иметь под рукой готовый bmp или res-файл, в котором содержаться изображения всех элементов ленты во всех состояниях (нажат, выделен, неактивен и т.д.)
2. На основании того как располагаются элементы в файле определить методы отрисовки — DrawElement.
3. Воспользоваться рекомендациями из этого поста блога.
В итоге, если всё будет сделано верно и точно получится нормальный уникальный скин для Ribbon.
Кстати, по поводу Ribbon в целом. Было время немного покопаться в Delphi XE, посмотреть, что да как. Так вот, что касается Ribbon Controls — все осталось как и прежде. Так что, если Вы хотите поставить Delphi XE в надежде на то, что Ribbon’ыстали работать лучше — можете даже и не заморачиваться.
Было бы замечательно, если вы вставите скрины в пост.
«Кстати, по поводу Ribbon в целом. Было время немного покопаться в Delphi XE, посмотреть, что да как. Так вот, что касается Ribbon Controls – все осталось как и прежде. Так что, если Вы хотите поставить Delphi XE в надежде на то, что Ribbon’ыстали работать лучше – можете даже и не заморачиваться.»
жаль… я XE только для этого и качал