Creating Customized Command Headers-公开你的命令并管理其可用性

摘要

本文介绍如何创建自定义命令头类,以公开命令并管理其可用性

  • 本用例学习内容

  • CAAAfrDumpCommandHeader 用例

    • CAAAfrDumpCommandHeader 功能说明  
    • CAAAfrDumpCommandHeader 启动方法  
    • CAAAfrDumpCommandHeader 代码位置
  • 分步实现

  • 小结

  • 参考文献

通过本用例您将学到

本用例旨在演示如何创建自定义命令头类,以对外暴露命令并管理其可用状态。

CAAAfrDumpCommandHeader 用例

CAAAfrDumpCommandHeader 是 CAAApplicationFrame.edu 框架的一个用例,用于演示应用框架(ApplicationFrame)的各项功能。
CAAAfrDumpCommandHeader 实现了什么功能

图片

 CAAAfrDumpCommandHeader 用例通过创建命令头类,来管理 ** 元素统计(Element Count)** 命令的可用状态。元素统计命令会扫描当前活动的 CAAGeometry 文档,并在对话框中输出文档所包含对象的清单。该命令仅在文档非空时才有意义,否则会被设为不可用状态。元素统计命令的可用性正是由其对应的命令头进行管理的。

CAAAfrDumpCommandHeader 自定义命令头类承担以下作用:
  • 它与通过 MacDeclareHeader 宏创建的命令头一样,是一个标准命令头。这一点通过使该命令头类继承自 CATCommandHeader 得以实现。
  • 此外,它需要在文档至少包含一个对象时将命令设为可用状态,在其他情况下设为不可用状态。这一功能由 CATCommandHeader 类的 BecomeAvailableBecomeUnavailable 方法实现。

如何运行 CAAAfrDumpCommandHeader

有关该用例运行方式的详细说明,请参阅《CAAGeometry 示例》用例中题为 “如何运行 CAAGeometry 用例” 的章节。具体操作流程如下:
请勿在命令行中输入模块名称,而是输入 CNEXT 启动程序。应用程序加载完成后,按以下步骤操作:
  1. 文件(File)菜单中,单击新建(New)
  2. 在弹出的 “新建” 对话框中,选择 CAAGeometry 并单击确定(OK)
  3. 使用 ** 基础元素(Basic Elements)工具栏中的命令,或通过插入(Insert)** 菜单中的对应命令,创建若干几何对象,例如点、直线、平面等
  4. 工具(Tools)菜单中,单击元素统计(Element Count)。系统将弹出对话框,显示各类元素的数量统计信息

注意:如果文档为空,** 元素统计(Element Count)** 命令会呈灰色禁用状态,无法被触发执行。

CAAAfrDumpCommandHeader 代码位置

CAAAfrDumpCommandHeader 用例仅由一个名为 CAAAfrDumpCommandHeader 的类构成,该类位于 CAAApplicationFrame.edu 框架下的 CAAAfrGeometryWshop.m 模块中:
  • Windows 平台:InstallRootDirectory\CAAApplicationFrame.edu\CAAAfrGeometryWshop.m\
  • Unix 平台:InstallRootDirectory/CAAApplicationFrame.edu/CAAAfrGeometryWshop.m/

其中 InstallRootDirectory 为 CAA 光盘内容的安装根目录。

CAAAfrDumpCommandHeader 在 CAA 几何创建工作台中被实例化,是该工作台的组成部分。

分步实现

为 CAAAfrGeometryWshop 工作台的元素统计命令创建命令头,共分为七个步骤:
序号步骤实现位置
1 创建命令头类头文件 LocalInterfaces
2 声明命令头类资源 CAAAfrDumpCommandHeader.cpp
3 设置对应事件的回调并初始化命令可用状态 构造函数
4 实现拷贝构造函数、Clone 方法与析构函数 CAAAfrDumpCommandHeader.cpp
5 编写用于管理命令可用状态的回调方法 CAAAfrDumpCommandHeader.cpp
6 实例化命令头类 CAAAfrGeometryWshop.m 的 CreateCommands 方法
7 为命令头实例分配资源 资源文件
 
 
 

创建命令头类

CAAAfrDumpCommandHeader 头文件内容如下:
#include <CATCommandHeader.h>
...
class CAAAfrDumpCommandHeader : public CATCommandHeader
{
  CATDeclareClass;
  CATDeclareHeaderResources;
  public:
   
    CAAAfrDumpCommandHeader(const CATString & iHeaderName);
    virtual ~CAAAfrDumpCommandHeader();
    CATCommandHeader * Clone();
      
  private:
    CAAAfrDumpCommandHeader(CATCommandHeader *iHeaderToCopy);
    CAAAfrDumpCommandHeader(const CAAAfrDumpCommandHeader &iObjectToCopy);
    void AnalyzeFilledCB(CATCallbackEvent     iPublishedEvent,		
                         void              *  ipPublishingObject, 
                         CATNotification   *  ipPublishNotification,
                         CATSubscriberData    iUsefulData,
                         CATCallback          iCallbackId); 
    void AnalyzeEmptyCB (CATCallbackEvent     iPublishedEvent,		
                         void              *  ipPublishingObject, 
                         CATNotification   *  ipPublishNotification,
                         CATSubscriberData    iUsefulData,
                         CATCallback          iCallbackId);
  private:
    CAAISysCollection * _pCollection;
};

CAAAfrDumpCommandHeader 类继承自 CATCommandHeader。CATDeclareClass 宏用于声明该类属于一个 CAA 组件。CATDeclareHeaderResources 宏会插入用于管理命令头资源的相关方法。

关于必需的公有方法

  • 一个以 const CATString 引用为参数的构造函数
  • 析构函数
  • 从 CATCommandHeader 继承而来的 Clone 方法,用于复制该命令头实例。可参考技术文章《命令头》[2] 中的 “自定义命令头类结构” 章节,其中包含 Clone 方法的完整详细说明。

关于必需的私有方法

  • 一个以 CATCommandHeader 指针为参数的构造函数,专门供 Clone 方法使用。
  • 另外两个构造函数在私有区域声明,且不在源文件中实现。这可以避免编译器在不知情的情况下自动将其生成为公有方法。

声明了两个回调方法 AnalyzeFilledCB 和 AnalyzeEmptyCB,分别在文档包含对象或文档为空时被调用。_pCollection 是指向文档中对象集合的指针,该指针与具体文档相关联。

声明命令头类资源

CAAAfrDumpCommandHeader 源文件中包含资源声明代码:
...
CATImplementClass(CAAAfrDumpCommandHeader,Implementation, CATCommandHeader, CATNull); 
CATImplementHeaderResources(CAAAfrDumpCommandHeader,
                            CATCommandHeader,
                            CAAAfrDumpCommandHeader);
...

自定义命令头是一个 CAA 组件。CATImplementClass 宏将 CAAAfrDumpCommandHeader 类设为组件主类(Implementation),使其从 CATCommandHeader 进行 OM 派生 [1]。

CATImplementHeaderResources 宏与头文件中的 CATDeclareHeaderResources 宏配合使用。它表明:

  • CAAAfrDumpCommandHeader 类继承自 CATCommandHeader
  • 其关联的资源文件名直接使用类名,分别为 CAAAfrDumpCommandHeader.CATNls 和 CAAAfrDumpCommandHeader.CATRsc

第二个参数传入的基类名称有助于实现资源拼接。第三个参数可以设为:

  • 另一个与其资源文件关联的类的类名;
  • 或某个已存在的资源文件对的无后缀名称。

设置对应事件的回调并初始化命令可用状态

在 CAAAfrDumpCommandHeader 类中实现如下:
...
CAAAfrDumpCommandHeader::CAAAfrDumpCommandHeader(const CATString &iHeaderName)
                       : CATCommandHeader(iHeaderName,          // 命令头 ID
                                          "CAAAfrGeoCommands",  // 命令共享库或 DLL
                                          "CAAAfrDumpCmd",      // 命令类
                                          (void*) NULL),         // 无需向命令传递参数
                         _pCollection(NULL)
{
  ...  // 获取 _pCollection 指针
  if (NULL != _pCollection)
  {
    ::AddCallback(this,
                  _pCollection,
                  "CAASysCollectionEmptyNotif",
                  (CATSubscriberMethod)&CAAAfrDumpCommandHeader::AnalyzeEmptyCB,
                  NULL);

    ::AddCallback(this,
                  _pCollection,
                  "CAASysCollectionFilledNotif",
                  (CATSubscriberMethod)&CAAAfrDumpCommandHeader::AnalyzeFilledCB,
                  NULL);

    int nbobject = 0;
    _pCollection->GetNumberOfObjects(&nbobject);

    if (nbobject > 1)
      BecomeAvailable();
    else
      BecomeUnavailable();
  }
  else
    BecomeUnavailable();
}

CAAAfrDumpCommandHeader::~CAAAfrDumpCommandHeader()                     
{
  if (NULL != _pCollection)
  {
     RemoveSubscriberCallbacks(_pCollection);
     _pCollection->Release();
     _pCollection = NULL;
  }
...

构造函数首先获取一个集合接口指针,该接口用于管理文档中的对象,具体实现与文档自身相关。当文档被创建或变为空文档时,该集合会发送一个 CAASysCollectionEmptyNotif 通知类实例。

反之,当文档中创建第一个对象时,该集合会发送一个 CAASysCollectionFilledNotif 通知类实例。

通过全局函数 AddCallback 为这两种通知分别设置了回调。以第一次函数调用为例,其参数含义如下:

  • this:执行回调方法的对象
  • _pCollection:发送通知的对象
  • CAASysCollectionEmptyNotif:所发送通知的类名
  • AnalyzeEmptyCB:需要被回调的方法
  • NULL:可传递给该方法的附加数据(此处无)

构造函数最后通过集合接口指针判断文档是否为空(空文档至少包含一个对象:UI 激活对象)。根据判断结果,使用 BecomeAvailableBecomeUnavailable 两个方法初始化命令的可用状态。

该状态仅在命令头类实例化时生效,后续如有需要,回调会动态修改该可用状态。

不要忘记在析构函数中使用 RemoveSubscriberCallbacks 方法移除订阅。

实现拷贝构造函数、Clone 方法与析构函数

在 CAAAfrDumpCommandHeader 类中的实现代码如下:
...
CAAAfrDumpCommandHeader::CAAAfrDumpCommandHeader(CATCommandHeader * iHeaderToCopy)
                       : CATCommandHeader(iHeaderToCopy),
                         _pCollection(NULL)
{}
					  
CATCommandHeader * CAAAfrDumpCommandHeader::Clone() 
{
  return new CAAAfrDumpCommandHeader(this);
}

CAAAfrDumpCommandHeader::~CAAAfrDumpCommandHeader()                     
{
  if ( NULL != _pCollection)
  {
     RemoveSubscriberCallbacks(_pCollection);
     _pCollection->Release();
     _pCollection = NULL;
  }
...
Clone 方法通过调用拷贝构造函数来完成对象复制。

不要忘记在析构函数中使用 RemoveSubscriberCallbacks 方法移除相关订阅。

创建用于管理命令可用状态的回调方法

在 CAAAfrDumpCommandHeader 类中的实现如下:
...
void CAAAfrDumpCommandHeader::AnalyzeFilledCB(CATCallbackEvent    iPublishedEvent,
                                              void              * ipPublishingObject, 
                                              CATNotification   * ipNotif,
                                              CATSubscriberData   iUsefulData,
                                              CATCallback         iCallbackId)
{
  BecomeAvailable();
} 
	
void CAAAfrDumpCommandHeader::AnalyzeEmptyCB (CATCallbackEvent    iPublishedEvent,
                                              void              * ipPublishingObject, 
                                              CATNotification   * ipNotif,
                                              CATSubscriberData   iUsefulData,
                                              CATCallback         iCallbackId)
{
  BecomeUnavailable();
}

这两个方法采用回调方法的标准签名。根据接收到的不同通知,它们会简单地将命令设置为对应的可用或不可用状态。

实例化命令头类

要实例化该命令头,需在 CAAAfrGeometryWks 工作台类的 CreateCommands 方法中调用其构造函数,并传入命令头标识符作为参数。
void CAAAfrGeometryWks::CreateCommands()
{
  ...
  new CAAAfrDumpCommandHeader("CAAAfrDumpHdr");
  ...
}
其中 CAAAfrDumpHdr 是分配给该命令头的标识符。该标识符后续会用于:
  • 将定义好的命令启动器与该命令头关联,从而把命令添加到菜单和工具栏中
  • 构建用于定义命令头资源的变量,例如菜单中显示给用户的本地化名称、工具栏上显示的图标等。

为命令头实例分配资源

CAAAfrDumpCommandHeader 类会自动与两个资源文件关联,文件名由类名构成:
  • CAAAfrDumpCommandHeader.CATNls:用于可翻译的标题与帮助信息
  • CAAAfrDumpCommandHeader.CATRsc:用于其他资源,例如在工具栏中显示的图标

资源通过一个键名来指定,键名由命令头类名、命令头实例标识符和资源关键字以点号分隔拼接而成。CAAAfrDumpCommandHeader.CATNls 文件中对该命令的资源定义示例如下:

CAAAfrDumpCommandHeader.CAAAfrDumpHdr.Title     = "元素统计…";
CAAAfrDumpCommandHeader.CAAAfrDumpHdr.ShortHelp = "元素统计";
CAAAfrDumpCommandHeader.CAAAfrDumpHdr.Help      = "文档内容";
CAAAfrDumpCommandHeader.CAAAfrDumpHdr.LongHelp  = "元素统计(工具菜单)
该命令允许用户输出文档内容";
CAAAfrDumpCommandHeader.CAAAfrDumpHdr.Category  = "工具";

这些资源包括:

Title

图片

 该命令在工具(Tools)菜单中显示的文本

ShortHelp

图片

 当命令位于工具栏中时,鼠标悬停其上时,在提示框中显示的命令简短帮助信息。此内容不适用于菜单栏中的命令。

Help

图片

 鼠标悬停在该命令上时,在状态栏中显示的命令帮助信息。此内容不适用于仅出现在菜单栏中的命令,但适用于同时出现在菜单栏和工具栏中的命令。

Category

图片

 与命令关联的一个属性,用于在自定义窗口命令选项页中对命令进行排序。

LongHelp

图片

 当最终用户点击 “这是什么” 帮助按钮(I_WhatsThisP2.gif),鼠标指针变为问号形状后,再点击代表该命令的图标时,在提示框中显示的文本。此内容不适用于位于菜单栏中的命令。

CAAAfrGeometryWksHeader.CATRsc 文件中包含针对 Point 命令的如下配置:

CAAAfrDumpCommandHeader.CAAAfrDumpHdr.Icon.Normal  = "I_CAAFindP2";
CAAAfrDumpCommandHeader.CAAAfrDumpHdr.LongHelpId   = "CAAAfrDumpCommandHeader.CAAAfrDumpHdr";

这些是用于在工具栏中显示 “元素统计” 命令的图标文件名:
Icon.Normal

图片

 与该命令关联的图标,在命令可用时显示在工具栏中。命令不可用时显示的灰色禁用图标,是由该图标自动生成的。在 P2 界面模式下,默认状态的阴影图标、按下状态图标和焦点状态图标,也均由该常规图标自动生成。

LongHelpId

与命令关联的标识符,当该命令处于激活状态时,按下 F1 键可调用对应的命令帮助文档。

简要总结

命令头代表一个命令,可避免在最终用户无需使用该命令时加载它。命令头是命令头类的一个实例。通过继承 CATCommandHeader 类创建的自定义命令头,可以使用 BecomeAvailable 和 BecomeUnavailable 方法,根据文档内容或其他任意条件来管理命令的可用状态。
posted @ 2026-04-17 13:27  Breadss  阅读(3)  评论(0)    收藏  举报