Creating an Add-in-自定义工作间或工作台

摘要

本文演示如何创建一个外接程序。

本用例将让你学到什么

  • CAAAfrGeoOperationAdn

    • 用例CAAAfrGeoOperationAdn 的功能

    • CAAAfrGeoOperationAdn 的启动方法

    • CAAAfrGeoOperationAdn 代码所在位置

  • 分步实现

  • 故障排除

  • 简要总结

  • 参考资料

本用例将使您学到的内容

本用例旨在演示如何为指定工作台创建外接程序(Add-in)。外接程序是一种对象,它可将用于操作文档的各类命令整合起来,并将这些命令布置在一个或多个工具栏及菜单项中。命令头(Command Header) 用于实现外接程序与对应命令之间的关联。

 

CAAAfrGeoOperationAdn 用例

CAAAfrGeoOperationAdn 是 CAAApplicationFrame.edu 框架的一个用例,用于演示应用框架(ApplicationFrame)的各项功能。

CAAAfrGeoOperationAdn 的功能

CAAAfrGeoOperationAdn 用例为 CAAGeometry 文档对应的 CAA 几何创建工作台创建一个外接程序。它由以下部分组成:
  • 一个单独的工具栏。

    图片

    操作工具栏。其中包含三个命令:合并、减去和圆角。

  • 菜单项

    图片

     它包含三个命令:合并、相减、倒圆角,以及紧跟在 “会议” 命令之后的分隔符

如何运行 CAAAfrGeoOperationAdn

有关本用例详细的运行说明,请参阅《CAAGeometry 示例》用例中题为 “如何运行 CAAGeometry 用例” 的章节。
请勿在命令行中输入模块名称,而是输入 CNEXT。程序启动完成后,执行以下操作:
    1. 选择 文件 → 新建
    2. 在 “新建” 对话框中,选择 CAAGeometry 并单击确定
    3. 如果操作工具栏未显示,在任意工具栏上单击鼠标右键,在右键菜单中选中该工具栏使其显示
    4. 若在菜单中找不到该工具栏,选择 开始 → 基础结构 → CAA V5:几何创建,以重置工作台。

CAAAfrGeoOperationAdn 代码查找位置

CAAAfrGeoOperationAdn 用例由一个名为 CAAAfrGeoOperationAdn 的单一类构成,该类位于 CAAApplicationFrame.edu 框架的 CAAAfrGeoCreationWkbAddin.m 模块中:
  • Windows 系统
    InstallRootDirectory\CAAApplicationFrame.edu\CAAAfrGeoCreationWkbAddin.m\
  • Unix 系统
    InstallRootDirectory/CAAApplicationFrame.edu/CAAAfrGeoCreationWkbAddin.m/

其中,InstallRootDirectory 指 CAA 光盘的安装根目录。

分步操作

要创建此加载项(add-in),需先创建模块目录用于存放加载项代码,同时创建其下的两个子目录:LocalInterfacessrc。在本示例中,该目录命名为 CAAAfrGeoOperationAdn.m,位于 CAAApplicationFrame.edu 框架内。随后需要创建以下文件:
CAAAfrGeoOperationAdn.m\LocalInterfaces 目录下:
  • CAAAfrGeoOperationAdn.h:加载项描述类的头文件

CAAAfrGeoOperationAdn.m\src 目录下:

  • CAAAfrGeoOperationAdn.cpp:加载项描述类的源文件

在字典目录(即 CNext\code\dictionary 目录,运行时通过 CATDictionaryPath 环境变量引用)中,创建或更新以下文件:

  • CAAApplicationFrame.edu.dico:接口字典文件

CNext\resources\msgcatalog 目录(运行时通过 CATMsgCatalogPath 环境变量引用)下:

  • CAAAfrGeoOperationAdn.CATNls:加载项消息文件
  • CAAAfrGeoOperationAdnHeader.CATNls
    CAAAfrGeoOperationAdnHeader.CATRsc:命令头资源文件

要创建 CAA 几何创建工作台,需完成以下四个步骤:

步骤 | 操作位置

1 | 创建加载项描述类 | LocalInterfaces 与 src 目录

2 | 创建命令头 | CreateCommands 方法

3 | 创建加载项并排列命令 | CreateToolbars 方法

4 | 提供资源文件 | 资源文件

创建加载项描述类

  1. 创建 CAAAfrGeoOperationAdn.h 文件

 

#include "CATBaseUnknown.h"  // 继承CATBaseUnknown类所需依赖的头文件

class CATCmdContainer;       // CreateToolbars方法所需的前置声明类

class CAAAfrGeoOperationAdn : public CATBaseUnknown
{
  CATDeclareClass;  // 声明类宏(CAA组件必需)
  public:
     CAAAfrGeoOperationAdn();  // 构造函数
     virtual ~CAAAfrGeoOperationAdn();  // 析构函数

     void CreateCommands();  // 创建命令方法
     CATCmdContainer * CreateToolbars();  // 创建工具栏方法
};
  1. 创建 CAAAfrGeoOperationAdn.cpp 文件
// 本地框架
#include "CAAAfrGeoOperationAdn.h"

// 应用程序框架
#include <CATCreateWorkshop.h>    // 用于使用 NewAccess - SetAccess - SetAccessChild 等方法

// 新命令头类的声明
#include "CATCommandHeader.h"        // 参考《创建命令头》相关文档
MacDeclareHeader(CAAAfrGeoOperationAdnHeader);  

// 实现CAA组件类:数据扩展,基类为CATBaseUnknown,扩展自CAAAfrGeoOperationAddin
CATImplementClass(CAAAfrGeoOperationAdn, DataExtension,
                  CATBaseUnknown, CAAAfrGeoOperationAddin);

// 接口绑定声明
#include <TIE_CAAIAfrGeoCreationWkbAddin.h>
TIE_CAAIAfrGeoCreationWkbAddin(CAAAfrGeoOperationAdn);

// 构造函数
CAAAfrGeoOperationAdn::CAAAfrGeoOperationAdn()
{}

// 析构函数
CAAAfrGeoOperationAdn::~CAAAfrGeoOperationAdn()
{}

// 创建工作台命令
void CAAAfrGeoOperationAdn::CreateCommands()
{
  ... // 参考《创建命令头》相关文档
}

// 创建工具栏并布置命令
CATCmdContainer * CAAAfrGeoOperationAdn::CreateToolbars()
{
  ... // 参考《创建工具栏及布置命令》相关文档
}

CAAAfrGeoOperationAdn 类通过 TIE_CAAIAfrGeoCreationWkbAddin 宏声明其实现了 CAAIAfrGeoCreationWkbAddin 接口。CATImplementClass 宏借助 DataExtension 关键字,声明 CAAAfrGeoOperationAdn 类是一个数据扩展,用于扩展 CAAAfrGeoOperationAddin。对于任何类型的扩展,该宏的第三个参数必须始终设置为 CATBaseUnknownCATNull。CATImplementClass 宏的第四个参数,即后期类型(latetype)名称,不能与已有的 C++ 类名或已存在的后期类型名称相同。

  1. 更新字典文件

更新接口字典接口字典是一个名为(例如)CAAApplicationFrame.dico 的文件,其所在目录路径在运行时会被拼接进 CATDictionaryPath 环境变量中。在该文件中添加如下声明,用以指明 CAAAfrGeoOperationAddin 组件实现了 CAAIAfrGeoCreationWkbAddin 接口,且其代码位于 libCAAAfrGeoCreationWkbAddin 共享库或 DLL 中。

CAAAfrGeoOperationAddin CAAIAfrGeoCreationWkbAddin libCAAAfrGeoCreationWkbAddin

注意:在接口字典中引用组件时,使用的是组件主类名,而非扩展类名。另外,与该「组件 / 接口」配对关联的共享库或 DLL,应是包含由 TIE 宏调用所生成代码的库文件。(由于 TIE 宏通常包含在扩展类的源文件中,该库一般与包含接口实现代码的库为同一个库。)原因在于:当客户端向组件请求接口指针时,会先实例化 TIE 类,该类会获取对应扩展类的现有实例,若无则创建其实例。

创建命令头

这一步通过 CreateCommands 方法完成。加载项中提供的每个命令都必须对应一个命令头。

命令头是命令头类的一个实例,不同的命令可以使用同一个命令头类来创建各自的命令头。更多详细信息,请参考《命令头》相关文档。

为这些命令创建了一个命令头类,使用 MacDeclareHeader 宏将其命名为 CAAAfrGeoOperationAdnHeader

  1. 创建 CAAAfrGeoOperationAdnHeader 命令头类。为此,请在 CAAAfrGeoOperationAddin.cpp 中添加如下代码:
#include "CATCommandHeader.h"
MacDeclareHeader(CAAAfrGeoOperationAdnHeader);


MacDeclareHeader 宏会为 CAAAfrGeoOperationAdnHeader 类自动生成头文件和源文件,并将资源文件 CAAAfrGeoOperationAdnHeader.CATNls 和 CAAAfrGeoOperationAdnHeader.CATRsc 与该类关联。详见 “提供资源” 部分。

  1. 在空的 CreateCommands 方法中创建命令头。该方法中,每个命令头都应包含一条对应命令头类的实例化语句。每条语句格式如下,以 ** 联合(Union)** 命令为例:
void CAAAfrGeoOperationAdn::CreateCommands()
{
  ...
  new CAAAfrGeoOperationAdnHeader("Union", "CommandLib",
                                  "UnionCmd", (void *)NULL);
  ...
}


命令头构造函数的参数说明如下:

  • Union为该命令头分配的标识符,后续将用于:
    • 将你定义的命令启动器与该命令头相关联,从而把命令添加到菜单和工具栏中。此加载项的相关操作将在《创建工具栏并布置命令》一节中完成。
    • 构建用于定义命令头资源的变量,例如最终用户看到的本地化帮助提示信息,或是在工具栏上显示的图标。相关内容将在《提供资源》一节中说明。
  • CommandLib包含 Union 命令代码的共享库或 DLL 名称,不带前缀 lib,也不带不同操作系统对应的后缀。
  • UnionCmdUnion 命令类的类名。
  • 最后一个参数 执行命令时可传递给命令的对象指针,通常为 NULL。该参数常为字符串,用于在同一个命令类可根据当前激活文档与数据执行多种操作时,指定具体要执行的动作,例如 "update""update all""cut""copy"
创建工具栏并布置命令
最后,我们将创建工具栏并对命令进行布局排列。这是 CreateToolbars 方法的功能。
  • 创建工具栏
    CATCmdContainer * CAAAfrGeoOperationAdn::CreateToolbars()
    {
      // 创建工具栏容器
      NewAccess(CATCmdContainer,pCAAAfrOperationTlb,CAAAfrOperationTlb);
    
          // 创建联合命令启动器,并关联到工具栏容器
          NewAccess(CATCmdStarter,pCAAAfrTUnionStr,CAAAfrTUnionStr);
          SetAccessCommand(pCAAAfrTUnionStr,"CAAAfrUnionHdr");
          SetAccessChild(pCAAAfrOperationTlb,pCAAAfrTUnionStr);
    
          // 创建减运算命令启动器,追加到上一个启动器后方
          NewAccess(CATCmdStarter,pCAAAfrTSubstractStr,CAAAfrTSubstractStr);
          SetAccessCommand(pCAAAfrTSubstractStr,"CAAAfrSubstractHdr");
          SetAccessNext(pCAAAfrTUnionStr,pCAAAfrTSubstractStr);
    
          // 创建圆角命令启动器,追加到上一个启动器后方
          NewAccess(CATCmdStarter,pCAAAfrTFilletStr,CAAAfrTFilletStr);
          SetAccessCommand(pCAAAfrTFilletStr,"CAAAfrFilletHdr");
          SetAccessNext(pCAAAfrTSubstractStr,pCAAAfrTFilletStr);
    
      // 添加工具栏视图:默认隐藏,停靠在右侧
      AddToolbarView(pCAAAfrOperationTlb,-1,Right); // 不可见工具栏
    		 
      ...
    }
    • 具体过程如下:
      • 使用 NewAccess 宏创建运算工具栏,它是 CATCmdContainer 类的一个实例。  
        • pCAAAfrOperationTlb 是用于管理该运算工具栏命令容器实例指针的变量; 
        • CAAAfrOperationTlb 是在加载项资源文件中引用该工具栏的标识符。
           该标识符在应用程序内所有工具栏标识符中必须唯一[1]。  

 

      •  使用 AddToolbarView 宏定义运算工具栏的默认位置: 
        • 参数 -1 表示工具栏默认隐藏1 表示默认显示);  
        • Right 表示工具栏停靠在应用程序窗口的右侧
      • 每个命令都需要使用三个宏,以 ** 联合(Union)** 命令为例:
        • 首先,使用 NewAccess 宏创建命令启动器,它是 CATCmdStarter 实例。
          pCAAAfrTUnionStr 是管理该实例指针的变量,CAAAfrTUnionStr 是其标识符。
        • 然后,使用 SetAccessCommand 宏将联合命令头与该命令启动器关联。
          第二个参数为联合命令头的标识符,即创建命令头时构造函数的第一个参数,详见《创建命令头》部分。
        • 最后,将联合命令启动器设置为布尔运算工具栏的子项。

其他命令按同样方式处理,只是它们之间使用 SetAccessNext 宏依次排列,形成前后相邻的按钮顺序。

  • 创建菜单项
    CATCmdContainer * CAAAfrGeoOperationAdn::CreateToolbars()
    {
      ...
      // 创建加载项菜单容器
      NewAccess(CATCmdContainer,pCAAAfrOperationMbr,CAAAfrOperationMbr);
    
           // 创建工具子菜单,并挂载到上级菜单容器
           NewAccess(CATCmdContainer,pCAAAfrOperationToolsMnu,CATAfrToolsMnu);
           SetAccessChild(pCAAAfrOperationMbr,pCAAAfrOperationToolsMnu);
    
             // 创建菜单分隔线
             NewAccess(CATCmdSeparator,pCAAAfrOperationToolsSep,CAAAfrOperationToolsSep);
             SetAccessChild(pCAAAfrOperationToolsMnu,pCAAAfrOperationToolsSep);
    
             // 创建【联合】命令菜单项
             NewAccess(CATCmdStarter,pCAAAfrMUnionStr,CAAAfrMUnionStr);
             SetAccessCommand(pCAAAfrMUnionStr,"CAAAfrUnionHdr");
             SetAccessNext(pCAAAfrOperationToolsSep,pCAAAfrMUnionStr);
    
             // 创建【减运算】命令菜单项
             NewAccess(CATCmdStarter,pCAAAfrMSubstractStr,CAAAfrMSubstractStr);
             SetAccessCommand(pCAAAfrMSubstractStr,"CAAAfrSubstractHdr");
             SetAccessNext(pCAAAfrMUnionStr,pCAAAfrMSubstractStr);
    
             // 创建【圆角】命令菜单项
             NewAccess(CATCmdStarter,pCAAAfrMFilletStr,CAAAfrMFilletStr);
             SetAccessCommand(pCAAAfrMFilletStr,"CAAAfrFilletHdr");
             SetAccessNext(pCAAAfrMSubstractStr,pCAAAfrMFilletStr);
    
      // 将菜单关联到当前加载项
      SetAddinMenu(pCAAAfrOperationTlb,pCAAAfrOperationMbr);
      ...
    }

    • 具体过程如下:  
      • 创建一个容器用于承载所有菜单:pCAAAfrOperationMbr  
      • 为了修改标识符为 CATAfrToolsMnu 的 “工具” 菜单,需要创建一个同名容器。
      • 分隔线通过 NewAccess 宏并使用 CATCmdSeparator 关键字创建。
      • 每个命令都需要使用三个宏,以 “联合” 命令为例:
        • 首先,使用 NewAccess 宏创建命令启动器,作为 CATCmdStarter 实例。pCAAAfrMUnionStr 是管理该实例指针的变量,CAAAfrMUnionStr 是其标识符。  
        • 然后,使用 SetAccessCommand 宏将联合命令头与该命令启动器关联。第二个参数为联合命令头的标识符,即命令头构造函数的第一个参数,详见《创建命令头》部分。
        • 最后,将联合命令启动器设置为布尔运算工具栏的子项。
          其他命令按同样方式处理,只是它们之间通过 SetAccessNext 宏依次排列。
    • 容器 pCAAAfrOperationMbr 通过 SetAddinMenu 方法被声明为菜单。该方法的第一个参数 pCAAAfrOperationTlb 是第一个链式工具栏,即该方法返回的对象(详见下一节);第二个参数为容器自身 pCAAAfrOperationMbr。 
  • 返回工具栏 
CATCmdContainer * CAAAfrGeoOperationAdn::CreateToolbars()
{
  ...
		 
  return pCAAAfrOperationTlb;
}

该方法返回第一个链式工具栏 pCAAAfrOperationTlb

提供资源

你需要为工具栏、菜单及其所有命令提供相应的资源。这些资源分为以下几类:
  • 工具栏标题。《为工作台和工作间创建资源》一文详细说明了所有资源相关内容 [2]。
  • 命令头资源文件中的命令头资源:与各命令关联的标题、提示信息、图标以及快捷键。相关内容在《为命令头创建资源》中进行了说明 [3]。
有关国际化与资源的更多内容,可参阅《客户端应用程序国际化》。

 

故障排除

加载项不可用或发生系统故障

现象
我创建了一个工作台加载项,但它不可用,或者出现系统故障。

解决方法

检查 CATImplementClass 宏中的后期类型(latetype)名称。该后期类型名称不能与已有的 C++ 类名或已存在的后期类型名称重复。

命令未显示在菜单栏或工具栏中

现象
我为某个命令创建了命令启动器,并将其布置在菜单栏或工具栏中,但该命令并未出现在我放置的位置。

诊断

命令启动器未与命令头关联,因此不会显示 —— 因为没有命令头,命令将无法被启动。

解决方法

检查你的 CreateToolbars 方法。必须通过 SetAccessCommand 宏,将命令启动器与你想要显示的命令所对应的命令头进行关联。

小结

加载项用于整合命令,以定制工作间(Workshop)工作台(Workbench),而无需修改其原有代码。

你只需实现该工作间或工作台为加载项开放的对应接口即可。

References

[1] Checklist for CAA V5 C++ Naming Rules
[2] Creating Resources for Workshops and Workbenches 
[3] Creating Resources for Command Headers 
posted @ 2026-04-12 11:09  Breadss  阅读(4)  评论(0)    收藏  举报