Ribbon是一种以面板及标签页为架构的用户界面(User Interface),它是一个收藏了命令按钮和图标的面板,就像工具栏一样。INVENTOR2020采用了Ribbon作为操作界面。INVENTOR程序根据文档打开的类型,有以下几种操作界面:
ZeroDoc 当没有任何文件打开时
Part 当打开零件文档时
Assembly 当打开装配部件文档时
Drawing 当打开工程图文档时
Presentation
iFeatures
UnknownDocument (Used for notebook and drawing view orientation environments.)
具体请看INVENTOR API帮助文档,打开帮助的方法如下:(在程序的右上部)
打开后如下:
关于Ribbon:
在以上的帮助文档中可以看到许多解释与例子,今天我们就制作一个ZeroDoc环境下的Ribbon及菜单。
关于Ribbon的结构如下:
INVENTOR2020内部有7个不同的Ribbon,主要用于每种文档类型。我们不能创建或删除这些已有的Ribbon,但我们可以通过添加或删除其中的元素来编辑七个现有的Ribbon。我们现在就是要在已有的ZeroDoc环境下的Ribbon上另外添加我们自己的Ribbon。按照上述的结构关系,我们要找到INVENTOR现有的ZeroDoc环境下的Ribbons,然后定义我们自己的Ribbon增加到其后面即可。
INVENTOR2020 ZeroDoc环境下的Ribbon形式如下:
按下“快速入门“后:
按下“工具”后:
按下“协作”后:
我们的目的是在“协作”之后增加一个彩带如下:
上面每个图中的”红色+粉色”就是一个Ribbon结构。先看看最基本的Ribbon结构组成,红色部分是它显示出来的名称,粉色部分是它包含的命令。命令又按功能分区,下图显示了一个完整的Ribbon结构,其包含的功能及命令数量可以很多,图中只标示了2个。
按照API Help的描述,Ribbon的组成如下:
下面开始创建我们的Ribbon,打开VS2017,新建一个” Autodesk Inventor 2020 Addin”类型的项目
右键单击项目,添加一个名为” MyRibbonMenu”的类:
在类中添加如下函数:
public static void AddZeroDocRibbon()
这个函数建好后放在程序入口处即可实现我们的目标。
Ribbon要使用两种像素尺寸的图标:
- StandardIcon 可选输入图片(IPictureDisp)对象,该对象指定要为使用此定义的控件使用的标准大小图标。一个标准尺寸的图标是16像素宽和16像素高。如果没有提供,该按钮将被创建为一个纯文本按钮,LargeIcon参数将被忽略,这是一个可选参数,默认值为null
- LargeIcon 可选输入图片(IPictureDisp)对象,该对象指定要为使用此定义的控件使用的大尺寸图标。大尺寸的图标是32宽32高。如果不提供LargeIcon图标,只提供了第(1)个StandardIcon,则大的图标将自动按照StandardIcon创建缩放大小的图标。因为缩放位图不一定能创建一个好的图像,所以建议您创建并提供一个大的位图。这是一个可选参数,默认值为null。
为此我们按如下创建16x16的图标资源:MyIcon16
单击创建:
创建好了,可以看到如下:
同样道理创建一个32x32的资源图标:MyIcon32
关于在C#中使用图像资源的方法请参考其他资料,此处使用如下方法:
添加应用:using InvAddIn.Properties; using System.Drawing;
则16位图像的名字是:Resources. MyIcon16 (其实是Properties.Resources. MyIcon16)
32位图像的名字是:Resources. MyIcon32 (其实是Properties.Resources. MyIcon32)
程序中可以这样引用:
Image image16 = Resources.MyIcon16;
Image image32 = Resources.MyIcon32;
但是Ribbon使用的图像格式是IPictureDisp,为了将Image格式转为IPictureDisp格式,使用AxHost类来解决:
public sealed class IPictureConverter : AxHost
{
//图标转换函数
//添加引用 System.Drawing
//若找不到stdole引用,应添加C:\Program Files\Autodesk\Inventor 2020\Bin\stdole.dll
//请将引用的stdole “嵌入互操作类型”属性设置为 false
//using System.Windows.Forms;
//using System.Drawing;
private IPictureConverter() : base("") { }
public static stdole.IPictureDisp ImageToIPictureDisp(Image image)
{
return (stdole.IPictureDisp)GetIPictureDispFromPicture(image);
}
public static Image IPictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return GetPictureFromIPictureDisp(pictureDisp);
}
}
//END public sealed class IPictureConverter:AxHost
至此,基本知识都已了解,开始在MyRibbonMenu类中创建AddZeroDocRibbon函数:
注意:如果有问题,请在INVENTOR菜单栏的”工具”下点击”+附加模块”,看看你的插件是否已加载:
模块载入后正常显示如下:
修改 StandardAddInServer.cs后:
using System;
using System.Runtime.InteropServices;
using InvAddIn;
using Inventor;
using Microsoft.Win32;
namespace MyAddIn1
{
/// <summary>
/// This is the primary AddIn Server class that implements the ApplicationAddInServer interface
/// that all Inventor AddIns are required to implement. The communication between Inventor and
/// the AddIn is via the methods on this interface.
/// </summary>
[GuidAttribute("9655d565-8ba5-4e82-a8c7-ba1276b0dfcc")]
public class StandardAddInServer : Inventor.ApplicationAddInServer
{
// Inventor application object.
public static Inventor.Application m_inventorApplication;
public StandardAddInServer()
{
}
#region ApplicationAddInServer Members
public void Activate(Inventor.ApplicationAddInSite addInSiteObject, bool firstTime)
{
// This method is called by Inventor when it loads the addin.
// The AddInSiteObject provides access to the Inventor Application object.
// The FirstTime flag indicates if the addin is loaded for the first time.
// Initialize AddIn members.
m_inventorApplication = addInSiteObject.Application;
// TODO: Add ApplicationAddInServer.Activate implementation.
// e.g. event initialization, command creation etc.
if (firstTime)
{
//在ZeroDoc环境下加入命令按钮
MyRibbonMenu.AddZeroDocRibbon();
}
}
public void Deactivate()
{
// This method is called by Inventor when the AddIn is unloaded.
// The AddIn will be unloaded either manually by the user or
// when the Inventor session is terminated
// TODO: Add ApplicationAddInServer.Deactivate implementation
// Release objects.
m_inventorApplication = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
public void ExecuteCommand(int commandID)
{
// Note:this method is now obsolete, you should use the
// ControlDefinition functionality for implementing commands.
}
public object Automation
{
// This property is provided to allow the AddIn to expose an API
// of its own to other programs. Typically, this would be done by
// implementing the AddIn's API interface in a class and returning
// that class object through this property.
get
{
// TODO: Add ApplicationAddInServer.Automation getter implementation
return null;
}
}
#endregion
}
}
MyRibbonMenu类如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using InvAddIn.Properties;
using Inventor;
using MyAddIn1;
using System.Windows.Forms;
namespace InvAddIn
{
public static class MyRibbonMenu
{
//定义命令按钮,这个不能放到函数内,否则无法工作
private static ButtonDefinition MyButtonDef101;
private static ButtonDefinition MyButtonDef102;
private static ButtonDefinition MyButtonDef201;
private static ButtonDefinition MyButtonDef202;
//唯一标识客户端的输入字符串。这是一个字符串形式的AddIn的CLSID,
//例如。“{C9A6C580 \ -3817 \ -11 d0 \ -BE4E \ -080036 e87b02}”。
//如果提供了该字符串,则在Inventor启动时使用该字符串来确定创建此ribbon面板的AddIn是否已被卸载。
//如果是,则删除该面板。当卸载关联的Add\ in时,该字符串还用于查找所有要删除的面板。
//可以指定'dummy'字符串或null字符串,但不建议使用。
//唯一标识客户端的ID
private static string strClientId = "{GLL-XJF-INV2020}";
public sealed class IPictureConverter : AxHost
{
//图标转换函数
//需要添加扩展的引用库:stdole
//若找不到stdole引用,应添加C:\Program Files\Autodesk\Inventor 2020\Bin\stdole.dll
//需要将引用的stdole “嵌入互操作类型”属性设置为 false
//需要添加引用库:System.Windows.Forms;
//需要添加引用 using System.Windows.Forms;
//需要添加引用库 System.Drawing
//需要添加引用 using System.Drawing;
private IPictureConverter() : base("") { }
public static stdole.IPictureDisp ImageToIPictureDisp(Image image)
{
return (stdole.IPictureDisp)GetIPictureDispFromPicture(image);
}
public static Image IPictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return GetPictureFromIPictureDisp(pictureDisp);
}
public static stdole.IPicture ImageToIPicture(Image image)
{
return (stdole.IPicture)GetIPictureFromPicture(image);
}
public static Image IPictureToImage(stdole.IPicture picture)
{
return GetPictureFromIPicture(picture);
}
}
//END public sealed class IPictureConverter:AxHost
public static void AddZeroDocRibbon()
{
//需要添加引用: using Inventor; using MyAddIn1;
//需要修改 StandardAddInServer.cs文件中如下定义
//private Inventor.Application m_inventorApplication;
//改为:
//public static Inventor.Application m_inventorApplication;
UserInterfaceManager oUIManager = StandardAddInServer.m_inventorApplication.UserInterfaceManager;
//创建我们的命令面板盘
//功能1区
RibbonPanel ZeroDocRibbonPanel1;
ZeroDocRibbonPanel1 = null;
//功能2区
RibbonPanel ZeroDocRibbonPanel2;
ZeroDocRibbonPanel2 = null;
//取得ZeroDoc环境下Ribbon
Ribbon ZeroDocRibbon = oUIManager.Ribbons["ZeroDoc"]; //Ribbons["ZeroDoc"] 零文档的Ribbon
if (oUIManager.InterfaceStyle == InterfaceStyleEnum.kRibbonInterface)
{
RibbonTab ZeroDocTab = ZeroDocRibbon.RibbonTabs.Add("Ribbon显示的名字", //DisplayName ---String,在Tab显示出来的名字
"MyZeroDoc000", //InternalName ---String,全局命令名,不可见
strClientId, //ClientId ---String,唯一标识客户端的ID
"", //TargetTabInternalName ---String,Optional 选项,指定一个现有的RibbonTab名字,本次新加的放在它之前或之后
true, //InsertBeforeTargetTab ---Boolean,Optional 选项,指定之前或之后
false); //Contextual ---Boolean,Optional input Boolean that specifies whether this is a contextual tab.
//加入功能1区
ZeroDocRibbonPanel1 = ZeroDocTab.RibbonPanels.Add("功能1区", //DisplayName ---String,在RibbonPanels显示出来的名字
"MySection1", //InternalName ---String,全局命令名,不可见
strClientId, //ClientId ---String,唯一标识客户端的ID
"", //TargetPanelInternalName ---String,Optional 选项,指定一个现有的RibbonPanel名字,本次新加的放在它之前或之后
true); //InsertBeforeTargetPanel --- Boolean,Optional 选项,指定之前或之后
//加入功能2区
ZeroDocRibbonPanel2 = ZeroDocTab.RibbonPanels.Add("功能2区", //DisplayName ---String,在RibbonPanels显示出来的名字
"MySection2", //InternalName ---String,全局命令名,不可见
strClientId, //ClientId ---String,唯一标识客户端的ID
"", //TargetPanelInternalName ---String,Optional 选项,指定一个现有的RibbonPanel名字,本次新加的放在它之前或之后
true); //InsertBeforeTargetPanel --- Boolean,Optional 选项,指定之前或之后
}
//Get a reference to the ControlDefinitions object.
ControlDefinitions controlDefs = StandardAddInServer.m_inventorApplication.CommandManager.ControlDefinitions;
//Get the images from the resources. They are stored as .Net images and the
//PictureConverter class is used to convert them to IPictureDisp objects, which
//the Inventor API requires.
//按钮图像,每个按钮都可以有自己的图像,这里为了简单,采用了相同的图像
Image Image16 = Resources.MyIcon16;
Image Image32 = Resources.MyIcon32;
stdole.IPictureDisp smallPicture = IPictureConverter.ImageToIPictureDisp(Image16);
stdole.IPictureDisp largePicture = IPictureConverter.ImageToIPictureDisp(Image32);
//Resources.Image32 ,其实是Properties.Resources.Image32 本项目资源 一定要添加 using InvAddIn.Properties;
功能1区的按钮 开始
//创建命令按钮
MyButtonDef101 = controlDefs.AddButtonDefinition("命令101", //DisplayName ---String,按钮显示出来的命令名字
"MyCommand101", //InternalName ---String,全局命令名,不可见
CommandTypesEnum.kEditMaskCmdType, //Classification ---CommandTypesEnum,命令类型
strClientId, //ClientId ---Variant,Optional input string that uniquely identifies the client.
"执行101命令", //DescriptionText ---String,Optional 可选的、描述
"点击执行101命令", //ToolTipText ---工具提示 String,Optional input String that specifies the tool tip text for this definition
smallPicture, //StandardIcon ---Variant,Optional input Picture (IPictureDisp),可选的标准图标
largePicture, //LargeIcon ---Variant,Optional input Picture (IPictureDisp),可选的大图标
ButtonDisplayEnum.kDisplayTextInLearningMode); //ButtonDisplay ---ButtonDisplayEnum,如何显示图标和文本
//将命令按钮放入容器
ZeroDocRibbonPanel1.CommandControls.AddButton(MyButtonDef101, true, true, "", true);//在盘里加入按钮
//实现命令的函数,这是响应"命令101"按钮的函数
MyButtonDef101.OnExecute += MyButton101_OnExecute;
//创建命令按钮
MyButtonDef102 = controlDefs.AddButtonDefinition("命令102", //DisplayName ---String,按钮显示出来的命令名字
"MyCommand102", //InternalName ---String,全局命令名,不可见
CommandTypesEnum.kEditMaskCmdType, //Classification ---CommandTypesEnum,命令类型
strClientId, //ClientId ---Variant,Optional input string that uniquely identifies the client.
"执行102命令", //DescriptionText ---String,Optional 可选的、描述
"点击执行102命令", //ToolTipText ---工具提示 String,Optional input String that specifies the tool tip text for this definition
smallPicture, //StandardIcon ---Variant,Optional input Picture (IPictureDisp),可选的标准图标
largePicture, //LargeIcon ---Variant,Optional input Picture (IPictureDisp),可选的大图标
ButtonDisplayEnum.kDisplayTextInLearningMode); //ButtonDisplay ---ButtonDisplayEnum,如何显示图标和文本
//将命令按钮放入容器
ZeroDocRibbonPanel1.CommandControls.AddButton(MyButtonDef102, true, true, "", true);//在盘里加入按钮
//实现命令的函数,这是响应"命令102"按钮的函数
MyButtonDef102.OnExecute += MyButton102_OnExecute;
功能1区的按钮 结束
功能2区的按钮 开始
//创建命令按钮
MyButtonDef201 = controlDefs.AddButtonDefinition("命令201", //DisplayName ---String,按钮显示出来的命令名字
"MyCommand201", //InternalName ---String,全局命令名,不可见
CommandTypesEnum.kEditMaskCmdType, //Classification ---CommandTypesEnum,命令类型
strClientId, //ClientId ---Variant,Optional input string that uniquely identifies the client.
"执行201命令", //DescriptionText ---String,Optional 可选的、描述
"点击执行201命令", //ToolTipText ---工具提示 String,Optional input String that specifies the tool tip text for this definition
smallPicture, //StandardIcon ---Variant,Optional input Picture (IPictureDisp),可选的标准图标
largePicture, //LargeIcon ---Variant,Optional input Picture (IPictureDisp),可选的大图标
ButtonDisplayEnum.kDisplayTextInLearningMode); //ButtonDisplay ---ButtonDisplayEnum,如何显示图标和文本
//将命令按钮放入容器
ZeroDocRibbonPanel2.CommandControls.AddButton(MyButtonDef201, true, true, "", true);//在盘里加入按钮
//实现命令的函数,这是响应"命令101"按钮的函数
MyButtonDef201.OnExecute += MyButton201_OnExecute;
//创建命令按钮
MyButtonDef202 = controlDefs.AddButtonDefinition("命令202", //DisplayName ---String,按钮显示出来的命令名字
"MyCommand202", //InternalName ---String,全局命令名,不可见
CommandTypesEnum.kEditMaskCmdType, //Classification ---CommandTypesEnum,命令类型
strClientId, //ClientId ---Variant,Optional input string that uniquely identifies the client.
"执行202命令", //DescriptionText ---String,Optional 可选的、描述
"点击执行202命令", //ToolTipText ---工具提示 String,Optional input String that specifies the tool tip text for this definition
smallPicture, //StandardIcon ---Variant,Optional input Picture (IPictureDisp),可选的标准图标
largePicture, //LargeIcon ---Variant,Optional input Picture (IPictureDisp),可选的大图标
ButtonDisplayEnum.kDisplayTextInLearningMode); //ButtonDisplay ---ButtonDisplayEnum,如何显示图标和文本
//将命令按钮放入容器
ZeroDocRibbonPanel2.CommandControls.AddButton(MyButtonDef202, true, true, "", true);//在盘里加入按钮
//实现命令的函数,这是响应"命令102"按钮的函数
MyButtonDef202.OnExecute += MyButton202_OnExecute;
功能2区的按钮 结束
}
private static void MyButton101_OnExecute(NameValueMap Context)
{
MessageBox.Show("MyRibbon 执行命令101");
}
private static void MyButton102_OnExecute(NameValueMap Context)
{
MessageBox.Show("MyRibbon 执行命令102");
}
private static void MyButton201_OnExecute(NameValueMap Context)
{
MessageBox.Show("MyRibbon 执行命令201");
}
private static void MyButton202_OnExecute(NameValueMap Context)
{
MessageBox.Show("MyRibbon 执行命令202");
}
}
}
同样道理:只要修改以下语句,就可以创建其它环境的Ribbon
//取得ZeroDoc环境下Ribbon
Ribbon ZeroDocRibbon = oUIManager.Ribbons["ZeroDoc"]; //Ribbons["ZeroDoc"] 零文档的Ribbon
修改为:
//取得Part环境下Ribbon
Ribbon PartDocRibbon = oUIManager.Ribbons["Part "]; //Ribbons["Part"] Part文档的Ribbon
修改为:
//取得Assembly环境下Ribbon
Ribbon AssemblyDocRibbon = oUIManager.Ribbons["Assembly "]; // Assembly文档的Ribbon
修改为:
//取得Drawing环境下Ribbon
Ribbon Drawing DocRibbon = oUIManager.Ribbons["Drawing "]; // Drawing文档的Ribbon
注:有以下文档环境:
ZeroDoc 当没有任何文件打开时
Part 当打开零件文档时
Assembly 当打开装配部件文档时
Drawing 当打开工程图文档时
Presentation
iFeatures
UnknownDocument (Used for notebook and drawing view orientation environments.)