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

Продолжаем разбираться в Ribbon Controls без использования мышей. Сегодня научимся создавать элементы управления и работать с механизмом действий (Actions).

В прошлый раз мы остановились на том, что создали вкладку и разместили на ней одну группу. В целом на всё про всё ушло не так уж и много времени. Сегодня задачка будет немного по сложнее, а именно научиться создавать кнопки и присваивать им выполнение определенных действий.
Для того, чтобы понять о чем в принципе будет идти речь сегодня, советую освежить свои знания и прочитать этот пост.

Как Вы уже знаете кнопки у Ribbon могут быть трёх типов: маленькие (bsSmall) с иконкой 16х16, большие (bsLarge), занимающие по высоте всю высоту группы (Ribbon Group) и большие split-кнопки выполняющие несколько действий — верхняя часть кнопки выполняет основное действие и нижняя содержит список дополнительных действие (Actions). Давайте вначале попробуем создать простую маленькую кнопку. Что нам для этого необходимо?
Во-первых, ActionManager и ImageList с хотя бы одной иконкой 16х16. Можно и без иконок, но с ними как-то по-красивее будет.
Во-вторых, нам необходимо, чтобы наша кнопка выполняла какое-либо действие. Следовательно нужен обработчик.
Т.к. ActionManager и ImageList у Вас уже должны остаться на форме от прошлой части нашей работы, то сразу перейдем к написанию обработчика, чтоб потом к нему не возвращаться. Само по себе действие Action:TBasicAction — это объект наследник от (TCompoent) у которого определено следующее свойство:

property OnExecute: TNotifyEvent read FOnExecute write SetOnExecute;

Тип TNotifyEvent это ни что иное как стандартное событие:

TNotifyEvent = procedure(Sender: TObject) of object;

Следовательно, создаем, например такую процедуру у главной формы приложения:

[...]
private
  procedure MyCustomAction(Sender: TObject);
[...]

и тело процедуры. Пусть это будет что-нибудь простое и одновременно информативное, например:

procedure TForm5.MyCustomAction(Sender: TObject);
begin
  ShowMessage('It is my Action!!!');
end;

Сразу понятно, что сработало :). Обработчик есть. Куда его теперь примостить? Создаем наш первый элемент управления Ribbon без использования мыши. Для этого в обработчике onClick у единственной кнопки нашего приложения пишем:

[...]
Ribbon1.ActionManager:=ActionManager1;//ассоциировали мэнеджер c Ribbon
ActionManager1.ActionBars.Add;//добавили новую коллекцию
ActionManager1.ActionBars[0].ActionBar:=Group;//добавили в коллекцию новую панель
with ActionManager1.ActionBars[0].Items.Add do
  begin
    action:=TAction.Create(self); //создали новое действие
    action.OnExecute:=MyCustomAction;//присвоили ему обработчик
    caption:='Caption'; //надпись
    visible:=True; //сделали видимым
end;
[...]

Теперь запускаем приложение и любуемся результатом:

Можете проверить — по клику на кнопке «Caption» сработает наш самописный обработчик. Пока вроде бы ничего особенно сложного и непонятного нет, неправда ли? Думаю, для Вас не составит никакого труда присвоить такой кнопке картинку из ImageList. А теперь попробуем создать большую кнопку. Пардон, за дурной тон, но я процитирую одну из фраз, которую сам же писал в одной из статей про Ribbon:

Для того, чтобы новая кнопка выглядела как полагается, т.е. сверху располагалась иконка 32?32 пикселя и снизу подпись, необходимо выбрать действие на панели, перейти в Object Inspector, выбрать вкладку свойств CommandProperties и указать в свойстве ButtonSize значение bsLarge. При этом ширина панели Ribbon автоматически изменится

Всё, что было сказано — чистая правда и так оно и есть. Логично предположить, что у нашего самодельного Action как минимум есть свойство ActionClients, а у него в свою очередь CommandProperties и т.д. и т.п.  Логично, что следующий код:

ActionClients[0].CommandProperties.ButtonSize:=bsLarge;

сработает? На первый взгляд логично, а на деле оказывается, что CommandProperties вообще не имеет ничего похожего на ButtonSize.

Вот всё, что есть у этого типа данных (модуль ActnMan):

TCommandProperties = class(TPersistent)
public
type
  TChangeState = (csIgnore, csRecreate, csRebuild);
protected
type
  TCommandPropertiesChangeEvent = procedure (Sender: TObject; State: TChangeState) of object;
private
  FActionClientItem: TActionClientItem;
  FOnChange: TCommandPropertiesChangeEvent;
  FChangeState: TChangeState;
  function GetControl: TCustomActionControl;
protected
  procedure InvalidateControl(const ResetBounds: Boolean); inline;
  procedure DoChanged; virtual;
public
  constructor Create(AItem: TActionClientItem); virtual;
  procedure Assign(Source: TPersistent); override;
  property Control: TCustomActionControl read GetControl;
  property ActionClientItem: TActionClientItem read FActionClientItem write FActionClientItem;
  property OnChange: TCommandPropertiesChangeEvent read FOnChange write FOnChange;
end;

Признаться, когда я увидел описание типа я немного даже растерялся. Ведь не может быть, чтоб в Инспекторе свойство есть, а у типа данных его нет :) Ну, как говориться, старость не радость. Опять же сказывается отсутствие базового образования по программированию. Секрет прост. Если вы откроете модуль  ActnMan и посмотрите его содержимое то достаточно быстро обнаружите такой тип данных:

TButtonProperties = class(TCommandProperties)
public
type
  TButtonSize = (bsSmall, bsLarge);
  TButtonType = (btNone, btDropDown, btSplit, btGallery);
  TGroupPosition = (gpNone, gpStart, gpMiddle, gpEnd, gpSingle);
  TTextAssociation = (taImage, taDropdown);
private
  FButtonSize: TButtonSize;
  FButtonType: TButtonType;
  FGroupPosition: TGroupPosition;
  FTextAssociation: TTextAssociation;
  procedure SetButtonType(const Value: TButtonType);
  procedure SetButtonSize(const Value: TButtonSize);
  procedure SetGroupPosition(const Value: TGroupPosition);
  procedure SetTextAssociation(const Value: TTextAssociation);
public
  constructor Create(AItem: TActionClientItem); override;
  procedure Assign(Source: TPersistent); override;
published
  property ButtonSize: TButtonSize read FButtonSize write SetButtonSize default bsSmall;
  property ButtonType: TButtonType read FButtonType write SetButtonType default btNone;
  property GroupPosition: TGroupPosition read FGroupPosition write SetGroupPosition default gpNone; 
  property TextAssociation: TTextAssociation read FTextAssociation write SetTextAssociation default taImage;
end;

Вот собственно, тот самый тип данных, который нам нужен для работы со всевозможными «конфигурациями» кнопок. Дописываем наш обработчик onClick:

[...]
with ActionManager1.ActionBars[0].Items.Add do
  begin
[...]
    (ActionClients[0].CommandProperties as TButtonProperties).ButtonSize:=bsLarge;
    ImageIndex:=0;
  end;
[...]

Снова запускаем приложение и на этот раз видим нормальную большую и красивую кнопку Ribbon:


Надеюсь, дальнейшая работа с простыми кнопками не составит для Вас особого труда. А мы в следующий раз начнем работу по созданию Split-Button’ов. Там, мягко говоря, неподготовленному человеку без бутылки водки не разобраться — будем разбираться вместе :)

Подписывайтесь на RSS и ждите продолжения цикла статей про Ribbon Controls в Delphi.

0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
9 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
sacha911
sacha911
13/01/2011 03:22

1. Спасибо автору за статью. Представленная информация имеет большую ценность с практической точки зрения.
2. Вопрос: кто-нибудь знает, как  в Runtime допавть на панель csComboBox? Вроде бы надо TRibbonComboBox создавать..

User
User
07/04/2011 21:41

Здравствуйте?
Так как все же работать с раздвоенной кнопкой?
Спасибо.

User
User
08/04/2011 13:26

я подумал что ты опишешь как в рантайме с ними работать :)
у меня при добавлении в сплит новых пунктов, картинка добавляемого элемента съезжает

Алексей
Алексей
26/04/2011 19:37

Здравствуйте. Не подскажите, как передать какие либо параметры в процедуру MyCustomAction?

sacha911
sacha911
26/04/2011 23:18

Можно через объект Sender

sacha911
sacha911
26/04/2011 23:27

или через глобальные переменные

Алексей
Алексей
27/04/2011 18:11

Как через Sender?

Алексей
Алексей
27/04/2011 18:37

Спасибо, сам разобрался