Вот почему мне нравится вести блог, так это за то, всегда находятся люди, которые не только берут что-то для себя , например ту же информацию по Ribbon Controls, но и безвозмездно делятся своими соображениями, идеями, советуют как сделать лучше и т.д. Получая такие письма от читателей как-то даже интереснее становится про что-то писать. Даже, если не собирался этого делаь, например, как я сейчас буду рассказывать снова про Ribbon. Не хотел начинать новый пост, думал, наконец-то дособираю в кучу всё что знаю и выложу в pdf. Но, один читатель в своем письме привел ряд моментов о которых я в принцпе и не подозревал, а также задал один небольшой, но довольно интересный вопрос:
Как разместить в группу кнопку с рисунком в виде квадрата с заданным цветом и как менять этот цвет? (как в MS Paint в Win7)
Ну, чтож, Павел - этот пост, можно сказать, посвещается Вам :). Заодно и другим может сообща поможем разобраться с этим вопросом.
Итак,начнем.
Прежде всего определимся с задачей. Все видели Paint в Windows 7? Кто не видел - вот скрин той самой части ленты, про которую сегодня пойдет речь:

Суть такова: когда пользователь кликает по маленькому квадратику с цветом, то, в зависимости от того, какая кнопка нажата "Цвет 1" или "Цвет 2" та и принимает цвет нажатого квадрата.
Получается эдакая иллюзия "живости" интерфейса от которой неискушенный пользователь скажет "Вах!". А нам, как разработчиком восхищаться особенно не чем - нам такой механизм взаимодействия надо соорудить из подручных средств в Delphi 2010.
Начнем, как полагается в случае с Ribbon Controls - с мышевозного программирования.
Работаем мышкой.
Для этого запускаем Delphi 2010, создаем новый проект, и на главную форму укладываем следующие компоненты:
- TRibbon (1 штука)
- TActionManager (1 штука)
- TActionList (1 штука)
- TImageList (2 штуки)
Теперь оговорюсь. По натуре я ленив до ужаса, поэтому мне было влом рисовать квадратики с различными цветами и тем более лень было ковыряться в Paint'e в посках изображений его кнопок. По этому я буду работать с иконками, обозначающими типы файлов (чем богаты - тем и рады, что было - то и спёр).
У Вас уже сейчас должно быть подготовлено 2 набора картинок:
- Картинки 16х16
- Точно такие же картинки, но только размером 32х32.
Теперь у первого ImageList (назовем его il1) выставляем свойства:
- ColorDepth = cd32Bit
- Height = 32
- Width =32
Грузим в него картинки 32х32. У второго ImageList (il2) выставляем свойства:
- ColorDepth = cd32Bit
- Height = 16
- Width =16
Грузим в него картинки в том же порядке, что и в первом ImageList. Если порядок будет нарушен - получим лишнюю головную боль с определением индекса картинки - мелочь, но неприятная.
Теперь открываем свойства ActionList и в свойсве Images указываем il2. Соответственно у ActionManager в Images указываем il1.
Также у ActionManager'а в свойства LinkedActionLists добавляем наш ActionList.
Следующий шаг - настройка Action'ов. Вначале настраиваем действия в ActionList. Для этого открываем его, добавляем действие и сразу определяем новую группу для Action. У меня - это группа "Файлы". В зависимости от того скалько картинок у вас в il1 и il2 (должно быть в обоих одно и то же количесво) добавляем столько же Action'ов и назначаем каждому свое изображение. В итоге у меня получился следующий набор действий:
Теперь переходим в AсtionManager и добавляем в него два действие, назначив им изображение из il1. Должна получиться примерно такая картинка:
Теперь остается только аккуратно разложить все Action'ы на панельках и первый этап можно считать законченным. У меня получилась лента следующего вида (в запущенном приложении):
Так как мы ещё не назначили ни одного обработчика Action'ам, то, соответственно, в запущенном приложении все элменты неактивны. Также я специально не стал менять свойство Caption у элементов на ленте и Вам менять их пока не советую - проще будет понять, что мы сейчас начнем делать.
Ищем способы смены изображения элемента "на лету"
Прежде всего нам надо определиться с тем как можно сменить изображение на любом элементе управления на ленте Ribbon. Логично предположить, что надо как-то докапаться до конкретного Action'а и поменять у него свойство ImageIndex. Ведь именно так мы и действовали при работе в ActionList? Но на самом деле всё немного проще. Смотрите. У ActionManager'а есть два замечательных метода:
function FindItemByCaption(ACaption: string): TActionClientItem; function FindItemByAction(Action: TCustomAction): TActionClientItem;
Как уже понятно, с помощью них мы можем получить доступ к TActionClientItem у которого, в свою очередь имеется свойство ImageIndex - его-то мы и будем изменять. Остается тольео определиться с тем, какой из методов мы будем использовать. Я буду в качестве примера искать элемент по Caption. И выбор мой не случаен. Посмотрите на рисунок выше и попробуйте, не заглядывая в свои исходники, ответить на вопрос "Какой Caption у первого слева TActionClientItem'a?" :). Будет не верно, если Вы решили, что это actMainAction1. На самом деле для TActionClientItem свойство Caption будет равно &actMainAction1. По умолчанию свойство Caption берется таким же как и у Action, который назначается Вами для элемента, НО обязательно где-то вставляется амперсанд. Говорю "где-то", потому что встречал его и в начале и в середине и в конце строки. Вот такая небольшая особенность поиска по Caption.
Можете теперь немного потренироваться в поисках элементов на ленте по их заголовкам. А я тем временем приведу пример как можно сменить изображение на элементе:
ActionManager1.FindItemByCaption('&actMainAction1').ImageIndex:=2
или так
(ActionManager1.FindItemByCaption('&actMainAction1').Action as TAction).ImageIndex:=2
Вот так запросто мы сменили изображение на первой слева кнопке. Думаю, что на этом способе и остановимся.
Организуем "живой" интерфейс Ribbon
Остается только поработать немного со свойствами элементов на ленте и составить обработчики действий. Вначале настраиваем большие кнопки. Выделяем первую кнопку на ленте, в Object Inspector'е выбираем вкладку свойств Aсtion и вытсавояем свойства:
GroupIndex = 1
AutoCheck = true
Точно такие же свойства выставляем и у второй кнопки. Теперь определим для них действия. У меня по клику на люой из кнопок в ListBox додавлятся строка, содержащая тип файла. Обработчик получился немного корявнький, но работоспособный:
procedure TForm5.BigButtonAction(Sender: TObject); begin case (Sender as TAction).ImageIndex of 0:lst1.Items.Add('AI'); 1:lst1.Items.Add('ACC'); 2:lst1.Items.Add('ACE'); 3:lst1.Items.Add('AIFF'); 4:lst1.Items.Add('ASP'); 5:lst1.Items.Add('AVI'); end; end;
Второй обработчик будем использовать для всех мелких кнопок. Здесь нам надо будет определить какая из больших кнопок нажата в данный момент и назначить ей "свою" картинку:
procedure TForm5.SmallButtonAction(Sender: TObject); begin if (actmgr1.FindItemByCaption('&actMainAction1').Action as TAction).Checked then (actmgr1.FindItemByCaption('&actMainAction1').Action as TAction).ImageIndex:= (Sender as TAction).ImageIndex else (actmgr1.FindItemByCaption('a&ctMainAction2').Action as TAction).ImageIndex:= (Sender as TAction).ImageIndex end;
Теперь назначаем этот обработчик каждой маленькой кнопке (событие OnExcute) и остается только "причесать" наше приложение, а точнее, убрать все подписи для маленьких кнопок. И здесь банальным стиранием свойства Caption не обойтись - надо обязательно выставить у каждого ActionClientItem'a свойство ShowCaption в False:

Теперь можно запустить приложение и убедиться в его работоспособности - в зависимости от того какая большая кнопка нажата у той и меняется иконка при нажатии маленькой кнопки, а также по своему выполнеятся Action. Практически также и работает Paint - какой цвет выбрали - тем и ресуем.
На всякий случай выкладываю здесь исхдник моего приложение. Вот он.
На всякий случай, ещё раз обращаю внимание тех, кто хочет все сделать с Ribbon Controls "по-быстрому", не вникая в суть работы с лентами и всячески избегая чтения MSDN: не используйте без надобности на ленте стандартные компоненты. Я имею в виду кнопки, speedButton'ы, CheckBox'ы, ComboBox'ы и т.д. Все эти компоненты можно получить простым изменением свойств у TActionClientItem. Чрезмерное использование стандартных кнопок может изуродовать ваше приложение до безобразия. Стандартную VCL стоит использовать только тогда, когда Вам не хватает доступных возможностей и делать это надо крайне аккуратно и требуется это очень редко.
т
Нашел где почитать информацию про туры в Латвию. Интересные предложения по доступным ценам.
--------------------------------------------------------------
| Делись! | Загружай! | Плюсуй! |
| | |










19 Июл 2010 в 9:38 пп
Спасибо, Влад, за помощь. Очень помогло. Правда, вместо ActionList мне пришлось использовать ActionManager, т.к. у меня их на форме до этого было уже 3 штуки, при запуске он брал иконки из ImagesList того ActionManager, который указан в Ribbon. Добавление в linkedActionLists всех менеджеров и листа, а также танцы с бубном не помогали, поэтому я решил всё же использовать один общий ActionManager для кнопок.
Не успел дочитать, как сразу рвался проверять, поэтому свойство ShowCaption нашёл сам :). Вот только кнопочки получились мельче, чем в Paint. Пробовал увеличивать до 20 пикселей, но они «слезают» со своих мест, а также изменять свойство Margins у группы, но изображения по прежнему на небольшом расстоянии друг от друга.
Небольшой оффтоп.
Сегодня утром сел поковырять Ribbon в своём приложении и delphi 10 мне выдал ошибку, мол не могу загрузить форму — ошибка на 13356-й строке. Удивился я этому и полез в dfm-файл. Оказвается от этой строки и прям до конца (ещё столько же строк) сплошные nil-значения (notepad++ так #00 обозначает). Я аж потом на спине покрылся от страха — столько работы потеряно. Но хорошо, что быстро взял себя в руки и заменил этот файл вчерашним — опять такая же проблема, только на другой строке. То же самое на позавчерашней копии. Через буквально минуту вспоминаю твою статью по history (ещё раз спасибо, за то, что ты есть), и, о чудо, обнаруживаю целёхоньким последний изменённый файл. Восстановил быстро. Но нервы мне это попортило. +1 к ещё одним глюкам delphi 2010 (или ribbon?). Теперь делаю резервную копию после каждого серьёзного изменения.
19 Июл 2010 в 9:48 пп
Кстати, помощь в написании PDF не нужна? Мне и самому интересно не только что, там будет, но и как там будет :).
20 Июл 2010 в 12:21 пп
На счёт оффтопа — это скорее Ribbon. С такими проблемами тоже довольно часто встречался когда писал программу с RibbonControls. Причё чем больше и навороченнее интерфейс — тем разнообразнее ошибки :) Бывает, что иногда Access Violation выпадает на родном месте в design-time, не прорисовываются элементы окна и т.д. Вобщем Ribbon Controls — это красиво, но весьма рискованно.
По поводу pdf-ки. Могу скинуть на почту начало того, что сделал.
20 Июл 2010 в 4:00 пп
>По поводу pdf-ки. Могу скинуть на почту начало того, что сделал.
Да не, я потом всё почитаю. Но если в чём нужна будет помощь (проги, вёрстка, мнение со стороны, или даже (чем бог не шут) совет) — обращайся.
20 Июл 2010 в 4:01 пп
договорились :)