В данной публикации мы рассмотрим пример программного построения собственной вкладки на ленте, а также несколько проблемных вопросов, связанных с лентой.
В последнее время стало очень популярным нововведение под названием лента (Ribbon). Autodesk не стал отставать от жизни и, начиная с 2009 автокада, тоже начал использовать ленту.
Мы рассмотрим пример создания вкладки на ленте для 2010 автокада и рассмотрим несколько сопутствующих «проблемных» вопросов. Почему для него? Да потому что в 2009 лента была еще «сырая» (но там тоже можно так сделать), и потому что для последующих автокадов (2011-2013) код будет анологичен.
Вариантов добавить свою вкладку на ленту несколько:
Примечание: Я не буду углубляться в каждую мелочь и «красиво» все описывать — пример не сложный. Да и я так красиво излагать не умею.
Пример рассматривается с учетом, что вы знаете как писать (хотя бы самые простые) плагины для автокада средствами .net. Для работы я использую Microsoft Visual Studio 2010.
Итак, приступим:
1. Открываем VS2010 и создаем новый проект:
2. Далее к нашему проекту подключаем ссылки:
3. Теперь рассмотрим из чего состоит лента на примере этой картинки:
Тут в принципе и описывать нечего.
4. Добавляем в наш проект две иконки размерами 16х16 и 32х32 в формате .png. Так, как я ленивый, то использовал одинаковую картинку первую попавшеюся на просторах интернет.
Главное для этих файлов поставить значение Resource для параметра Действие при построение:
5. Переходим к коду. Открываем файл Class1.cs (или можете свой создать), удаляем класс Class1 и создаем свой собственный класс, унаследованный от IExtensionApplication. Назовем его ExampleRibbon.
Далее я хотел как-то пошагово описать все действия, но решил, что удобней и понятней будет сразу привести весь код с пояснениями:
6. Все — код готов. Компилируем его (Построение —> Построить решение), открываем автокад 2010, выполняем команду NETLOAD и выбираем наш плагин ...\ACadRibbon\ACadRibbon\bin\Debug\ACadRibbon.dll.
И сразу же после загрузки мы увидим, что у нас добавилась новая вкладка на ленте:
Данный вариант активно используется в моем плагине ModPlus и пока не вызвал нареканий.
Надеюсь, пример окажется полезным!
В последнее время стало очень популярным нововведение под названием лента (Ribbon). Autodesk не стал отставать от жизни и, начиная с 2009 автокада, тоже начал использовать ленту.
Мы рассмотрим пример создания вкладки на ленте для 2010 автокада и рассмотрим несколько сопутствующих «проблемных» вопросов. Почему для него? Да потому что в 2009 лента была еще «сырая» (но там тоже можно так сделать), и потому что для последующих автокадов (2011-2013) код будет анологичен.
Вариантов добавить свою вкладку на ленту несколько:
- создать файл АПИ (cui) со своей лентой и подгружать его. На мой взгляд самый плохой и проблемный вариант. ИМХО
- создать вкладку на ленте программно — этот вариант и рассмотрим
- создать вкладку используя технологию WPF — я не стал разбираться
Примечание: Я не буду углубляться в каждую мелочь и «красиво» все описывать — пример не сложный. Да и я так красиво излагать не умею.
Пример рассматривается с учетом, что вы знаете как писать (хотя бы самые простые) плагины для автокада средствами .net. Для работы я использую Microsoft Visual Studio 2010.
Итак, приступим:
1. Открываем VS2010 и создаем новый проект:
2. Далее к нашему проекту подключаем ссылки:
- Проект —> Добавить ссылку —> вкладка «Обзор» —> из папки с автокадом 2010 выбираем файлы: acdbmgd.dll, acmgd.dll, AdWindows.dll. Не забываем в свойствах этих файлов поставить значение false для параметра Копировать локально;
- Проект —> Добавить ссылку —> вкладка «NET» —> добавляем ссылки на следующие библиотеки: PresentationCore, PresentationFramework, WindowsBase.
3. Теперь рассмотрим из чего состоит лента на примере этой картинки:
Тут в принципе и описывать нечего.
4. Добавляем в наш проект две иконки размерами 16х16 и 32х32 в формате .png. Так, как я ленивый, то использовал одинаковую картинку первую попавшеюся на просторах интернет.
Главное для этих файлов поставить значение Resource для параметра Действие при построение:
5. Переходим к коду. Открываем файл Class1.cs (или можете свой создать), удаляем класс Class1 и создаем свой собственный класс, унаследованный от IExtensionApplication. Назовем его ExampleRibbon.
Далее я хотел как-то пошагово описать все действия, но решил, что удобней и понятней будет сразу привести весь код с пояснениями:
Весь основной код проекта
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// Acad
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.Windows;
using acadApp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace ACadRibbon
{
public class ExampleRibbon : IExtensionApplication
{
// Инициализация нашего плагина
public void Initialize()
{
/* ленту грузим с помощью обработчика событий:
* Этот вариант нужно использовать, если ваш плагин
* стоит в автозагрузке, т.к. он (плагин) инициализируется
* до построения ленты
*/
//Autodesk.Windows.ComponentManager.ItemInitialized += new EventHandler(ComponentManager_ItemInitialized);
// Т.к. мы грузим плагин через NETLOAD, то строим вкладку в ленте сразу
BuildRibbonTab();
}
// Происходит при закрытии автокада
public void Terminate()
{
// Тут в принципе ничего не требуется делать
}
/* Обработчик события
* Следит за событиями изменения окна автокада.
* Используем его для того, чтобы "поймать" момент построения ленты,
* учитывая, что наш плагин уже инициализировался
*/
void ComponentManager_ItemInitialized(object sender, Autodesk.Windows.RibbonItemEventArgs e)
{
// Проверяем, что лента загружена
if (Autodesk.Windows.ComponentManager.Ribbon != null)
{
// Строим нашу вкладку
BuildRibbonTab();
//и раз уж лента запустилась, то отключаем обработчик событий
Autodesk.Windows.ComponentManager.ItemInitialized -=
new EventHandlerRibbonItemEventArgs>(ComponentManager_ItemInitialized);
}
}
// Построение вкладки
void BuildRibbonTab()
{
// Если лента еще не загружена
if (!isLoaded())
{
// Строим вкладку
CreateRibbonTab();
// Подключаем обработчик событий изменения системных переменных
acadApp.SystemVariableChanged += new SystemVariableChangedEventHandler(acadApp_SystemVariableChanged);
}
}
// Проверка "загруженности" ленты
bool isLoaded()
{
bool _loaded = false;
RibbonControl ribCntrl = Autodesk.Windows.ComponentManager.Ribbon;
// Делаем итерацию по вкладкам ленты
foreach (RibbonTab tab in ribCntrl.Tabs)
{
// И если у вкладки совпадает идентификатор и заголовок, то значит вкладка загружена
if (tab.Id.Equals("RibbonExample_ID") & tab.Title.Equals("RibbonExample"))
{ _loaded = true; break; }
else _loaded = false;
}
return _loaded;
}
/* Удаление своей вкладки с ленты
* В данном примере не используем
*/
void RemoveRibbonTab()
{
try
{
RibbonControl ribCntrl = Autodesk.Windows.ComponentManager.Ribbon;
// Делаем итерацию по вкладкам ленты
foreach (RibbonTab tab in ribCntrl.Tabs)
{
if (tab.Id.Equals("RibbonExample_ID") & tab.Title.Equals("RibbonExample"))
{
// И если у вкладки совпадает идентификатор и заголовок, то удаляем эту вкладку
ribCntrl.Tabs.Remove(tab);
// Отключаем обработчик событий
acadApp.SystemVariableChanged -= new SystemVariableChangedEventHandler(acadApp_SystemVariableChanged);
// Останавливаем итерацию
break;
}
}
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
Autodesk.AutoCAD.ApplicationServices.Application.
DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message);
}
}
/* Обработка события изменения системной переменной
* Будем следить за системной переменной WSCURRENT (текущее рабочее пространство),
* чтобы наша вкладка не "терялась" при изменение рабочего пространства
*/
void acadApp_SystemVariableChanged(object sender, SystemVariableChangedEventArgs e)
{
if (e.Name.Equals("WSCURRENT")) BuildRibbonTab();
}
// Создание нашей вкладки
void CreateRibbonTab()
{
try
{
// Получаем доступ к ленте
RibbonControl ribCntrl = Autodesk.Windows.ComponentManager.Ribbon;
// добавляем свою вкладку
RibbonTab ribTab = new RibbonTab();
ribTab.Title = "RibbonExample"; // Заголовок вкладки
ribTab.Id = "RibbonExample_ID"; // Идентификатор вкладки
ribCntrl.Tabs.Add(ribTab); // Добавляем вкладку в ленту
// добавляем содержимое в свою вкладку (одну панель)
addExampleContent(ribTab);
// Делаем вкладку активной (не желательно, ибо неудобно)
//ribTab.IsActive = true;
// Обновляем ленту (если делаете вкладку активной, то необязательно)
ribCntrl.UpdateLayout();
}
catch (System.Exception ex)
{
Autodesk.AutoCAD.ApplicationServices.Application.
DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message);
}
}
// Строим новую панель в нашей вкладке
void addExampleContent(RibbonTab ribTab)
{
try
{
// создаем panel source
RibbonPanelSource ribSourcePanel = new RibbonPanelSource();
ribSourcePanel.Title = "RibbonExample";
// теперь саму панель
RibbonPanel ribPanel = new RibbonPanel();
ribPanel.Source = ribSourcePanel;
ribTab.Panels.Add(ribPanel);
// создаем пустую tooltip (всплывающая подсказка)
RibbonToolTip tt;
// создаем split button
RibbonSplitButton risSplitBtn = new RibbonSplitButton();
/* Для RibbonSplitButton ОБЯЗАТЕЛЬНО надо указать
* свойство Text, а иначе при поиске команд в автокаде
* будет вылетать ошибка.
*/
risSplitBtn.Text = "RibbonSplitButton";
// Ориентация кнопки
risSplitBtn.Orientation = System.Windows.Controls.Orientation.Vertical;
// Размер кнопки
risSplitBtn.Size = RibbonItemSize.Large;
// Показывать изображение
risSplitBtn.ShowImage = true;
// Показывать текст
risSplitBtn.ShowText = true;
// Стиль кнопки
risSplitBtn.ListButtonStyle = Autodesk.Private.Windows.RibbonListButtonStyle.SplitButton;
risSplitBtn.ResizeStyle = RibbonItemResizeStyles.NoResize;
risSplitBtn.ListStyle = RibbonSplitButtonListStyle.List;
/* Далее создаем две кнопки и добавляем их
* не в панель, а в RibbonSplitButton
*/
#region Кнопка-пример №1
// Создаем новый экземпляр подсказки
tt = new RibbonToolTip();
// Отключаем вызов справки (в данном примере её нету)
tt.IsHelpEnabled = false;
// Создаем кнопку
RibbonButton ribBtn = new RibbonButton();
/* В свойство CommandParameter (параметры команды)
* и в свойство Command (отображает команду) подсказки
* пишем вызываемую команду
*/
ribBtn.CommandParameter = tt.Command = "_Line";
// Имя кнопки
ribBtn.Name = "ExampleButton1";
// Заголовок кнопки и подсказки
ribBtn.Text = tt.Title = "Кнопка-пример №1";
// Создаем новый (собственный) обработчик команд (см.ниже)
ribBtn.CommandHandler = new RibbonCommandHandler();
// Ориентация кнопки
ribBtn.Orientation = System.Windows.Controls.Orientation.Horizontal;
// Размер кнопки
ribBtn.Size = RibbonItemSize.Large;
/* Т.к. используем размер кнопки Large, то добавляем
* большое изображение с помощью специальной функции (см.ниже)
*/
ribBtn.LargeImage = LoadImage("icon_32");
// Показывать картинку
ribBtn.ShowImage = true;
// Показывать текст
ribBtn.ShowText = true;
// Заполняем содержимое всплывающей подсказки
tt.Content = "Я кнопочка №1. Нажми меня и я нарисую отрезок";
// Подключаем подсказку к кнопке
ribBtn.ToolTip = tt;
// Добавляем кнопку в RibbonSplitButton
risSplitBtn.Items.Add(ribBtn);
#endregion
// Делаем текущей первую кнопку
risSplitBtn.Current = ribBtn;
// Далее создаем вторую кнопку по аналогии с первой
#region Кнопка-пример №2
tt = new RibbonToolTip();
tt.IsHelpEnabled = false;
ribBtn = new RibbonButton();
ribBtn.CommandParameter = tt.Command = "_Pline";
ribBtn.Name = "ExampleButton2";
ribBtn.Text = tt.Title = "Кнопка-пример №2";
ribBtn.CommandHandler = new RibbonCommandHandler();
ribBtn.Orientation = System.Windows.Controls.Orientation.Horizontal;
ribBtn.Size = RibbonItemSize.Large;
ribBtn.LargeImage = LoadImage("icon_32");
ribBtn.ShowImage = true;
ribBtn.ShowText = true;
tt.Content = "Я кнопочка №2. Нажми меня и я нарисую полилинию";
ribBtn.ToolTip = tt;
risSplitBtn.Items.Add(ribBtn);
#endregion
// Добавляем RibbonSplitButton в нашу панель
ribSourcePanel.Items.Add(risSplitBtn);
// Создаем новую строку
RibbonRowPanel ribRowPanel = new RibbonRowPanel();
// Создаем третью кнопку по аналогии с предыдущими.
// Отличие только в размере кнопки (и картинки)
#region Кнопка-пример №3
tt = new RibbonToolTip();
tt.IsHelpEnabled = false;
ribBtn = new RibbonButton();
ribBtn.CommandParameter = tt.Command = "_Circle";
ribBtn.Name = "ExampleButton3";
ribBtn.Text = tt.Title = "Кнопка-пример №3";
ribBtn.CommandHandler = new RibbonCommandHandler();
ribBtn.Orientation = System.Windows.Controls.Orientation.Vertical;
ribBtn.Size = RibbonItemSize.Standard;
ribBtn.Image = LoadImage("icon_16");
ribBtn.ShowImage = true;
ribBtn.ShowText = false;
tt.Content = "Я кнопочка №3. Нажми меня и я нарисую кружочек";
ribBtn.ToolTip = tt;
ribRowPanel.Items.Add(ribBtn);
#endregion
// Добавляем строку в нашу панель
ribSourcePanel.Items.Add(ribRowPanel);
}
catch (System.Exception ex)
{
Autodesk.AutoCAD.ApplicationServices.Application.
DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message);
}
}
// Получение картинки из ресурсов
// Данная функция найдена на просторах интернет
System.Windows.Media.Imaging.BitmapImage LoadImage(string ImageName)
{
return new System.Windows.Media.Imaging.BitmapImage(
new Uri("pack://application:,,,/ACadRibbon;component/" + ImageName + ".png"));
}
/* Собственный обраотчик команд
* Это один из вариантов вызова команды по нажатию кнопки
*/
class RibbonCommandHandler : System.Windows.Input.ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
if (parameter is RibbonButton)
{
// Просто берем команду, записанную в CommandParameter кнопки
// и выпоняем её используя функцию SendStringToExecute
RibbonButton button = parameter as RibbonButton;
acadApp.DocumentManager.MdiActiveDocument.SendStringToExecute(
button.CommandParameter + " ", true, false, true);
}
}
}
}
}
6. Все — код готов. Компилируем его (Построение —> Построить решение), открываем автокад 2010, выполняем команду NETLOAD и выбираем наш плагин ...\ACadRibbon\ACadRibbon\bin\Debug\ACadRibbon.dll.
И сразу же после загрузки мы увидим, что у нас добавилась новая вкладка на ленте:
Данный вариант активно используется в моем плагине ModPlus и пока не вызвал нареканий.
Надеюсь, пример окажется полезным!