Как Вы, наверное, знаете из комментариев в блоге сейчас я работаю над объединением всех статей про Ribbon Controls в Delphi в один большой документ. Что получится в итоге — пока не известно даже мне. Может это будет простой пост на 7000+ слов с картинками, а может и целый справочник для начинающих программистов. Пока кодовое название документа «Ribbon Controls. Мышинное программирование«. Может звучит немного странно, но вполне отражает суть того, что пока изложено. Дело в том, что большинство действий, совершаемых при работе с Ribbon — это движения мышкой по экрану. Эдакое программирование для дошкольников — взял кнопочку, перетянул на панельку, выбрал мышкой в свойствах значение, ткнул мышкой 2 раза, написал 1 строчку и всё готово. Только вот, как показывают вопросы по Ribbon от читателей блога, да и собственный хоть и не большой, но опыт — иногда бывает очень не просто ухватить мышкой тот самый элемент :) Понимаю, что может звучит и немного неправдоподобно, но так и есть. Часто приходится выделывать что-то наподобие тануа с бубном, чтобы сделать запланированной. Вот я и решил, что хватит уже мучится с мышкой, пора бы перейти к более серьезной работе. А именно — работать с Ribbon Controls именно как с объектами Delphi, без всяких тасканий и перетаскиваний — только код.
Однако, перед тем как перейдем к практической реализации заявленной темы, хочу Вам сообщить одно пренеприятнейшее известие. К нам едет ревизор. В блоге теперь работает защита от копирования контента. Может это и не 100% защита, но всяким нечистоплотным копипастерам, боящимся поставить обратную ссылку на первоисточник, кровь немного попортит.
Ну, а мы пока перейдем к нашим Ribbon Controls в Delphi. Сегодня рассмотрим небольшой пример создания панелей и групп Ribbon в real-time.
Как Вы уже знаете, в основе Ribbon лежат три вида компонентов: вкладка, группа и элемент, отвечающий за выполнение какого-либо действия (Кнопки, ComboBox и т.д.). При этом элементы располагаются в группах, а те, в свою очередь на вкладках и умещается всё это хозяйство на родительском компоненте TRibbon.
Собственно, имея в руках только эту информацию, уже можно определиться с созданием вкладок и групп на Ribbon. Поэтому сразу и приступим к программированию.
Открываем Delphi, создаем новое приложение и укладываем на форму стандартный для Ribbon набор компонентов: ActionManager, ImageList и TRibbon. Создавать все элементы интерфейса будем по клику на кнопке TButton. Вид нашего будущего приложения должен быть примерно таким:
Первое, что нам необходимо — это создать новую вкладку. Вся совокупность вкладок (Tabs) является коллекцией TRibbonTabs, которая имеет следующее описание:
TRibbonTabs = class(TOwnedCollection) private FDesignerAdd: Boolean; function GetItem(Index: Integer): TRibbonTabItem; procedure SetItem(Index: Integer; const Value: TRibbonTabItem); function GetRibbon: TCustomRibbon; procedure CreatePageForItem(AItem: TRibbonTabItem); protected procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); override; public constructor Create(AOwner: TPersistent; ItemClass: TCollectionItemClass); function Add: TRibbonTabItem; function FindGroup(const GroupName: string): TControl; function GetPageFromPageCaption(const Caption: string): TCustomRibbonPage; function IndexOfCaption(const Caption: string): Integer; function TabExists(const Caption: string): Boolean; function SelectNext: Boolean; function SelectPrior: Boolean; property DesignerAdd: Boolean read FDesignerAdd write FDesignerAdd; property Ribbon: TCustomRibbon read GetRibbon; property Items[Index: Integer]: TRibbonTabItem read GetItem write SetItem; default; end;
Как можно видеть из приведенного листинга, отдельная вкладка — это объект TRibbonTabItem. Попробуем создать новую вкладку. Создаем событие onClick у Button1 и пишем :
procedure TForm5.Button1Click(Sender: TObject); var RibbonTabItem:TRibbonTabItem; begin RibbonTabItem:=TRibbonTabItem.Create(ribbon1.Tabs); end;
Теперь можете запустить приложение и убедиться, что новая вкладка создается и содержит стандартное название типа «RibbonTab1», «RibbonTab2» и т.д. Но нам-то необходимо нормальное название. Поэтому давайте немного разберемся с объектом TRibbonTabItem.
В числе прочих, TRibbonTabItem имеет следующие свойства:
BestTabWidth: Integer — оптимальная ширина вкладки, т.е. ширина вкладки не может быть больше этого значения. Свойство только для чтения.
MinTabwidth: Integer — минимальная ширина вкладки . Свойство только для чтения
Caption: string — заголовок вкладки.
Page: TCustomRibbonPage — объект, содержащий все необходимые свойства и методы для управления дочерними элементами вкладки (группами).
Таким образом, нам пригодятся сегодня два свойства: Caption и Page. Вначале изменим заголовок новой вкладки, например, воспользовавшись свойством Count у колеекции Ribbon1.Tabs :
[...] RibbonTabItem.Caption:='Tab #'+IntToStr(Ribbon1.Tabs.Count); [...]
В итоге при работе с приложением у Вас должно получиться примерно следующее:
Двигаемся дальше. Следующий шаг — добавление ной группы. Здесь в принципе тоже нет никаких сложностей — каждая группа — это дочерний элемент вкладки. Здесь при работе, нам как раз и пригодиться свойство Page: TCustomRibbonPage.
Объект TCustomRibbonPage содержит следующие полезные для нас публичные свойства и методы:
procedure AlignGroups — автоматическое выравнивание групп на вкладке
procedure AddGroup(const Group: TCustomRibbonGroup) — добавление новой группы на вкладку
function FindGroup(const GroupCaption: string): TControl — поиск группы по её заголовку
function FindGroupAt(const Pt: TPoint): TCustomRibbonGroup — поиск группы по координатам точки.
property GroupCount: Integer — количество групп на вкладке
property Groups[Index: Integer]: TCustomRibbonGroup — отдельная группа вкладки
property Index: Integer — порядковый номер вкладки на Ribbon
property Ribbon: TCustomRibbon — родительский элемент вкладки.
Для того, чтобы добавить новую группу нам необходимо воспользоваться методом AddGroup где в качестве входного параметра выступает добавляемая нами группа. Что ж, приступим. Добавляем новую переменную типа TCustomRibbonGroup в обработчик события и пишем:
[...] Group:=TRibbonGroup.Create(RibbonTabItem.page);//группа размещается на вкладке RibbonTabItem.Page.AddGroup(Group); //добавляем группу в коллекцию Group.Parent:=RibbonTabItem.Page; //указываем родительский элемент для группы Group.Caption:='Group #'+IntToStr(RibbonTabItem.Page.GroupCount);//указываем заголовок [...]
Теперь при каждом клике по кнопке в real-time создается новая вкладка и на каждой вкладке одна группа. Следует отметить, что каждая новая группа по умолчанию имеет следующие свойства:
Width := 200; Height := TCustomRibbon.cRibbonGroupHeight;//86 px Align := alNone; GroupAlign := gaVertical; Rows := 3; //количество строк
В принципе, вы всегда можете изменить некоторые из этих свойств как Вам угодно.
Теперь остался один открытый вопрос: зачем нам на форме два лишних компонента — ActionManager и ImageList?
Ответ на этот вопрос, Вы узнаете в следующем посте. Будем работать непосредственно с отдельными группами, элементами и действиями. А пока можете сохранить приложение, т.к. оно нам ещё пригодиться, подписаться на RSS и ждать новых публикаций в блоге webdelphi.ru :)
Не подскажите как сделать так что б по нажатию на кнопку открывалась нужная вкладка (например на Вкладке1 существует кнопку(Action1), после её нажатия должна открыться Вкладка2… как это сделать?)
Так это вам в ActionManager надо сделать новое событие по которому и будете перебирать вкладки
так вот в этом и вопрос… как правильно написать что б работало.. а то всё никак не получается (((
Пртведи кусок кода где пробуешь переключить вкладку
Ribbon1.ActivePage.Index:=2
или
Ribbon1.ActivePage := — этот вариант Делфи не принимает
или
RibbonPage2.Show; и все без результата
Переключение по вкладкам Ribbon’а осуществляется, например так:
Ribbon1.Tabs.SelectNext;
— переход на следующую вкладкуRibbon1.Tabs.SelectPrior;
— переход на предыдущую вкладкуСпасибо за информацию… но я так понял на конкретную страницу перейти нельзя…. либо прописывать одну и туже команду несколько раз…
Жека, я привел только пример перехода по закладкам. Думаю, что всё-таки есть способ перехода, хотя бы в том же TRibbon.Tag[x].
Спасибо, Vlad, статья, как всегда, на высоте. Отлично дополняет пример http://www.webdelphi.ru/2009/10/ribbon-controls-shag-za-shagom-shag-1-vizualnaya-razrabotka-interfejsa/#comment-1780 ! // Только не сочтите за занудство, но, коли планируете издать «справочник», перефразируйте «Часто приходится выделывать что-то наподобие тануа с бубном, чтобы сделать запланированной.»
С уважением, благодарный читатель)))
Естественно, если будет справочник таких фраз там не будет :)
Спасибо, Vlad, статья отличная.
Но у меня возникла тпкая проблема ,
При создании вкладок в цикле например что-то такое
[code]
Ribbon1.BeginUpdate;
for j := 0 to 20 do
begin
I_Loop := Length(RibonPages);
SetLength(RibonPages, I_Loop + 1);
RibonPages[I_Loop] := TRibbonPage.Create(Self);
RibonPages[I_Loop].Name := 'RP_SYSDBA'+IntToStr(j);
RibonPages[I_Loop].Parent := Ribbon1;
RibonPages[I_Loop].Caption :=GetString('SYSDBA');
Ribbon1.AddTab(RibonPages[I_Loop]);
end;
Ribbon1.EndUpdate;
[/code]
перерисовка Ribbon-а при каждой интерации создает довольнотаки неприятное впечатление
и кажется Ribbon1.BeginUpdate не работает.
Если сталкивались с подобным пожалусто напишите как с этом справиться.
Недавно столкнулся с такой проблемой: при разработке необходимо создавать вкладку(и группы в ней) динамически. Но при создании RibbonGroup цвет Caption не черный, а какой-то розоватый. На другом компьютере — голубой. Но самое интересное то, что вторая вкладка создается с нормальным цветом! Не подскажите в чем дело? И как сделать чтобы цвет был «нормальным».