Hello everyone,
Currently, I'm trying to create Ribbon and Menu for AutoCAD with code and have 2 problems below:
- For the Ribbon, I want AutoCAD to automatically load the custom Ribbon when opening AutoCAD if the working environment shows the Ribbon in AutoCAD, if I switch to the Classic interface, the custom Ribbon will not load (this works properly), but when I switch back to the Ribbon style, it doesn't show the custom Ribbon again. So is there a way to customize it to always load in AutoCAD without shutting down and reopening AutoCAD?
- For Menu, I have to load Menu by calling "TestMenu" command, I want AutoCAD to automatically load custom menu like in Ribbon but it can't load. So I want to auto load Menu for this case, what should I do?
Thank you.
Solved! Go to Solution.
Solved by Alexander.Rivilis. Go to Solution.
Solved by norman.yuan. Go to Solution.
Solved by norman.yuan. Go to Solution.
Solved by norman.yuan. Go to Solution.
Firstly, your code that runs in IExtensionApplication.Initialize() has crucial error that could render your add-in dll useless (i.e. after the DLL loaded, your custom command would result in "Unknown command" error). The reason is that you do not have try...catch to wrap the code on Initialize for possible error, and in your code, an error is highly likely: by the time your DLL runs the Initialize() method, there no GUARANTEE that AutoCAD has already had RibbonControl object created, thus the first line of the code in TAddRibbon() method would fail, thus the Initialize() would error out and the DLL load fails.
The usual approach of loading custom ribbon created by code is to handle Application.Idle event in Initialize(), and in the Idle event handler to check is RibbonControl is null or not. Only proceed to load custom ribbon items after RibbonControl is reachable.
Now back to your question. When you say "switch to classical..." and "switch back..." I assume it means user switch work space. You should handle event to watch workspace change (for example, handling SystemVaraibaleChanged event for system variable "WSCURRENT"): when current workspace changes, you simply check if there is RibbonControl reachable, if yes, if your ribbon items are loaded; if not load them. Of course you need to modify/update your code so that before you create your own ribbon tab/panel, you want to check if they have already exists (or there could be even ribbon tab/panel created by others that has already used the same tab/panel name. In this case you may want to name your tab/panel differently...).
As for the menu, it would be the same as ribbon loading: you can loaded in Application.Idle event handler. Just to remember, after your custom ribbon/menu loaded in the Idle event handler, you remove the event handler.
Norman Yuan
Some pseudo code:
public void Initialize()
{
Application.Idle += LoadRibbonMenuOnIdle;
}
... ...
private void LoadRibbonMenuOnIdle(object sender, EventArgs e)
{
var ribbonControl = Autodesk.Windows.ComponentManager.Ribbon;
if (ribbonControl!=null)
{
// Load custom ribbon / menu
Application.SystemVaraibaleChanged += (o, e) =>
{
if (e.Name.ToUpper()=="WSCURRENT")
{
// Load Ribbon/Menu
}
}
Application.Idle -= LoadRibbonMenuOnIdle;
}
}
As I said in previous reply, since you might need to load your ribbon multiple times due to user changing Workspace, so your ribbon loading code should check if the custom tab/panel has already existed in the ribbon control or not.
Norman Yuan
Hello @norman.yuan ,
Thank you for your response, but I'm getting the errot at event variable e in this code:
private void LoadRibbonMenuOnIdle(object sender, EventArgs e)
{
var ribbonControl = Autodesk.Windows.ComponentManager.Ribbon;
if (ribbonControl!=null)
{
// Load custom ribbon / menu
Application.SystemVaraibaleChanged += (o, e) =>
{
if (e.Name.ToUpper()=="WSCURRENT")
{
// Load Ribbon/Menu
}
};
Application.Idle -= LoadRibbonMenuOnIdle;
}
}
Thank you.
Ah, it is a typo: the variable e has already been used in the outer code, you can change it to whatever different, such as
Application.SystemVariableChanged += (o, arg) =>
{
if (arg.Name.ToUpper() == "WSCURRENT")
{
... ...
}
}
...
Norman Yuan
Hello @norman.yuan,
Thank you very much, the line of code works great.
Also, can you tell me more, is there a way to add an icon for the Menu with code? Currently my code only shows the content without the icon.
Sorry, I am not aware that one can add icon to PopupMenu with AutoCAD COM API.
Norman Yuan
@phuochung_dang wrote:
Also, can you tell me more, is there a way to add an icon for the Menu with code? Currently my code only shows the content without the icon.
There are no methods in AutoCAD COM API, which add icon(s) to menu.
Відповідь корисна? Клікніть на "ВПОДОБАЙКУ" цім повідомленням! | Do you find the posts helpful? "LIKE" these posts!
Находите сообщения полезными? Поставьте "НРАВИТСЯ" этим сообщениям!
На ваше запитання відповіли? Натисніть кнопку "ПРИЙНЯТИ РІШЕННЯ" | Have your question been answered successfully? Click "ACCEPT SOLUTION" button.
На ваш вопрос успешно ответили? Нажмите кнопку "УТВЕРДИТЬ РЕШЕНИЕ"
Alexander Rivilis / Александр Ривилис / Олександр Рівіліс
Programmer & Teacher & Helper / Программист - Учитель - Помощник / Програміст - вчитель - помічник
Facebook | Twitter | LinkedIn
Hello @norman.yuan @Alexander.Rivilis
Oh, so that's it, because there's no solution to this. So maybe for Menu, I should go back to creating Menu with CUI command and add custom command for it.
Thank you very much.
foreach (AcadMenuGroup acadAppMenuGroup in acadApp.MenuGroups)
{
doc.Editor.WriteMessage("++++++++++++++\n");
doc.Editor.WriteMessage(acadAppMenuGroup.Name);
doc.Editor.WriteMessage("\n");
foreach (AcadPopupMenu item in acadAppMenuGroup.Menus)
{
doc.Editor.WriteMessage(" " + item.Name + "\n");
}
}
Why add menu by Item(0) ? I don't understand this api and how to create a tab.
-----------
acadApp.MenuGroups.Item(0).Menus.Add("Test Menu");
hello,I just have the same question as @phuochung_dang , I have handled Application.Idle event in Initialize() but it seems not work.Here is part of my code ,would you please tell me why the ribbon plugin does not show automatically? thank u.
void IExtensionApplication.Initialize()
{
Application.Idle += LoadRibbonOnIdle;
}
private void LoadRibbonOnIdle(object sender, EventArgs e)
{
var ribbonControl = Autodesk.Windows.ComponentManager.Ribbon;
if (ribbonControl != null)
{
// Load custom ribbon
Application.SystemVariableChanged += (o, ev) =>
{
if (ev.Name.ToUpper() == "LWDISPLAY")
{
// Load Ribbon/Menu
RibbonDemo();
}
};
Application.Idle -= LoadRibbonOnIdle;
}
}
[CommandMethod("RibbonDemo")]
public void RibbonDemo()
{
// 获取程序集的加载路径
string currentDLLLocation = Path.GetDirectoryName(this.GetType().Assembly.Location) + "\\";
Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Editor editor = doc.Editor;
// 获取cad的Ribbon界面
RibbonControl ribbonCtrl = ComponentManager.Ribbon;
//while(ribbonCtrl==null) ribbonCtrl = ComponentManager.Ribbon;
if (ribbonCtrl == null) {
editor.WriteMessage("No Ribbon!");
return;
}
RibbonTab tab = new RibbonTab();
tab.Title = "myPlugin";
tab.Id = "Acad.RibbonId1";
//tab.IsActive = true;
ribbonCtrl.Tabs.Add(tab);
//AddPanel(tab);
RibbonPanelSource panelSource = new RibbonPanelSource();
panelSource.Title = "快捷操作";
RibbonPanel ribbonPanel = new RibbonPanel();
ribbonPanel.ResizeItemWidthPriority = 1;
ribbonPanel.Source = panelSource;
tab.Panels.Add(ribbonPanel);
addButton(currentDLLLocation, panelSource, "folderOpen", "打开文件", "打开文件", "打开坐标文件", "是打开文件命令,请保证目标文件是格式正确的.csv文件。", "OPENFILE");
addButton(currentDLLLocation, panelSource, "color", "修改颜色", "修改颜色", "修改线条颜色", "这是修改使用插件绘制的所有线条颜色的命令。", "CHANGECOLOR");
addButton(currentDLLLocation, panelSource, "clear", "一键清除", "一键清除", "一键清除所有线条", "这是清除使用插件绘制的所有线条色的命令。", "CLEARALL");
RibbonRowPanel row1 = new RibbonRowPanel();
row1.Width = 500;
// RibbonCombo
ribbonCombo = new RibbonCombo {
Name = "修改线宽",
ShowText = true,
Image = LoadImage("lineWidth"),
LargeImage = LoadImage("lineWidthLarge"),
Size = RibbonItemSize.Large,
ShowImage = true,
Width = 200
};
InitializeComboBox(ribbonCombo);
ribbonCombo.CurrentChanged += lineWidthCombo_SelectedIndexChanged;
row1.Items.Add(ribbonCombo);
row1.Items.Add(new RibbonRowBreak());
ribbonLineTypeCombo = new RibbonCombo {
Name = "修改线型",
ShowText = true,
Size = RibbonItemSize.Large,
Image = LoadImage("lineType"),
LargeImage = LoadImage("lineTypeLarge"),
ShowImage = true,
Width = 200,
CommandHandler = new RibbonCommandHandler()
};
List<string> stringtext = new List<string> { "实线", "虚线", "点划线" };
for (int i = 0; i < stringtext.Count; i++)
{
RibbonButton ribtext = new RibbonButton();
ribtext.Text = stringtext[i];
ribtext.ShowText = true;
ribbonLineTypeCombo.Items.Add(ribtext);
}
ribbonLineTypeCombo.CurrentChanged +=ribbonLineTypeCombo_selectedChanged;
ribbonLineTypeCombo.Current = ribbonLineTypeCombo.Items[0];
row1.Items.Add(ribbonLineTypeCombo);
row1.Items.Add(new RibbonRowBreak());
panelSource.Items.Add(row1);
}
YOur Application.Idle event handler LoadRibbonOnIdle(object, EventArgs) does not load the custom ribbon. It only add event handler to SystemVariableChanged event to load the custom ribbon ONLY WHEN "LWDISPLAY"(???) is changed. Why when Showing LineWeight is toggled on or off you want to load/reload the custom Ribbon? The system variable to watch SHOULD BE "WSCURRENT". That is, when WorkSpace changes, you want to make sure your dynamically created custom ribbon tab is still there. SO the code should be:
private void LoadRibbonOnIdle(object sender, EventArgs e)
{
var ribbonControl = Autodesk.Windows.ComponentManager.Ribbon;
if (ribbonControl != null)
{
// Load custom ribbon tab
RibbonDemo();
// make sure custom ribbon is loaded when Workspace changes
Application.SystemVariableChanged += (o, ev) =>
{
if (ev.Name.ToUpper() == "WSCURRENT")
{
// Load Ribbon/Menu
RibbonDemo();
}
};
Application.Idle -= LoadRibbonOnIdle;
}
}
Also, in the RibbonDemo() method, you SHOULD TEST whether the custom ribbon tab has already existed or not, and ONLY create the custom ribbon WHET IT DOES NOT EXISTS.
Norman Yuan
Thanks for your reply. I modified my code as you said and it did work.However, there is a new problem: when I select a combo box item, i.e. when the event lineWidthCombo_SelectedIndexChanged is triggered, all my global variables are initialized, and all the new objects that I created in the beginning become null, e.g. the variables clear,loaded, the object modalForm etc.but when I cancel the inheritation to IExtensionApplication and the code that autoloads the custom ribbon, it works normally,can you tell me how to fix that? Appreciate it.
The code I used to add the event for ribbonCombo is:
ribbonCombo.CurrentChanged += lineWidthCombo_SelectedIndexChanged;
The code for lineWidthCombo_SelectedIndexChanged is shown below:
private void lineWidthCombo_SelectedIndexChanged(object sender, RibbonPropertyChangedEventArgs args)
{
//System.Windows.Forms.MessageBox.Show($"{this.loaded}");
int weight;
RibbonButton current = (RibbonButton)ribbonCombo.Current;
string selectedItemName = current.AutomationName;
if (selectedItemName == "default") weight = -3;
else if (selectedItemName == "ByBlock") weight = -2;
else if (selectedItemName == "ByLayer") weight = -1;
else
{
weight = (int)(double.Parse(selectedItemName.Substring(0, 4)) * 100);
}
lineWeight = weight;
if (loaded == true && clear == false)
modalForm.DrawCurves();
}
Can't find what you're looking for? Ask the community or share your knowledge.