Creating a Combo Command Header-如何创建一个命令头类,使其在工具栏中以下拉组合框的形式呈现?

摘要

本用例说明如何创建一个专用命令头。该命令头具备自定义的图形显示样式,其在工具栏中并非以复选按钮形式呈现,而是以组合框作为图形表现形式。

  • 通过本用例您将学习到

  • CAAAfrComboColorHeader 用例

    • CAAAfrComboColorHeader 实现功能  
    • CAAAfrComboColorHeader 启动方法  
    • CAAAfrComboColorHeader 代码位置  
  • 分步实现

  • 简要总结

  • 参考资料

通过本用例您将学到

本用例演示如何创建一个自定义命令头。在工具栏中,该命令头的图形表现形式为组合框,而非默认的复选按钮。您将学习如何:
  • 创建用于表示该命令头的组件
    该组件必须继承自 CATAfrDialogCommandHeader 类。
  • 创建用于实例化图形表现形式的组件
    该组件必须继承自 CATAfrCommandHeaderRep 类,并会实例化一个 CATDlgCombo 对象。
  • 创建用于控制图形表现形式所使用数据的组件
    图形表现形式所使用的数据为组合框中当前选中的颜色值,该数据依赖于 V5 文档的实例。

您也可以阅读 CAAAfrMRUHeader 用例 [1],该用例展示了另一种自定义命令头。在该用例中,图形表现形式为菜单栏中的动态按钮项列表。与当前用例不同,其使用的数据(字符串列表)不依赖于文档。

为充分理解本文内容,建议您先阅读《命令头》技术文章 [2],尤其是 **“创建自定义命令头”** 章节。

 

CAAAfrComboColorHeader 用例

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

CAAAfrComboColorHeader 的功能

CAAAfrComboColorHeader 创建一个命令头,该命令头在工具栏中的图形表现形式为一个颜色选择组合框。下图展示了该命令头在 “自定义命令头” 工具栏中的显示效果:
图 1 组合框命令头

图片

 如果您展开该组合框的下拉列表,可在十种颜色中进行选择:

图 2 组合框的十个选项值

图片

 

该组合框需要两类信息:
  • 组合框中的可用颜色。这十种颜色为硬编码实现。
  • 当前选中的颜色。该信息由一个与 CAAGeometry 文档关联的组件维护,此组件为 CAASysGeomRootObj。有关 CAAGeometry 文档及 CAASysGeomRootObj 组件的完整详细说明,请参阅参考文章 [3]。

CAASysGeomRootObj 组件是用于控制图形显示所使用数据的组件。它通过 CAAIAfrTemporaryObjectColor 接口管理颜色的当前取值。该接口支持获取与设置当前颜色。但由于 CAAGeometry 文档不支持 “流式持久化”,因此颜色数据不会被持久保存(不会被序列化存储)。

图 3 控制图形表示所用数据的组件 — UML 图

图片

 CAASysGeomRootObj 组件扮演控制器的角色 [2]。当通过 CAAIAfrTemporaryObjectColor 接口修改当前颜色值时,其实现类 CAAEAfrTemporaryObjectColor 会发送一个通知,即 CAAAfrComboColorNotification 类的实例。

与所有拥有自定义图形表现形式的命令头一样,该组合框命令头类是一个派生自 CATAfrDialogCommandHeader 类的子类实例。

下面的 UML 图详细描述了该类的结构:

图 4 组合框命令头 — UML 图

图片

 

CAAAfrComboColorHeader 是一个组件,它必须实现 CATIAfrCommandHeaderRep 接口以提供自定义的图形表现形式。该接口包含三个方法:
  • CreateCtxMenuRep:无返回值
  • CreateMenuRep:无返回值
  • CreateToolbarRep:负责实例化 CAAAfrComboRep 类的对象。该类的结构由下面的 UML 图描述:

图 5 实例化图形表示的类 — UML 示意图

图片

 

CAAAfrComboRep 类创建一个 CATDlgCombo [4] 类实例,并设置一个回调函数,以便在当前颜色发生变化时接收通知。因此,如果在同一个文档中存在多个 CAAAfrComboColorHeader 类的实例(详见 “如何运行 CAAAfrComboColorHeader” 章节),所有显示控件都将自动更新。
该组合框命令头在 CAAGeometry 文档所在工作台的一个插件(Add-in)中被实例化。分步实现章节的最后一步会介绍该实例化过程。

如何运行 CAAAfrComboColorHeader

有关本用例运行方式的详细说明,请参阅《CAAGeometry 示例》用例中题为 **“如何运行 CAAGeometry 用例”** 的章节。
请勿在命令行中输入模块名称,而是输入 CNEXT 启动程序。应用程序就绪后,按以下步骤操作:
  • 文件菜单中,单击新建
  • 在弹出的新建对话框中选择 CAAGeometry,然后单击确定
  • 如果自定义命令头工具栏未显示,在任意工具栏上单击鼠标右键,在上下文菜单中选中该工具栏使其显示(默认当前颜色为红色)
  • 在颜色组合框中选择第一种蓝色
  • 单击并创建若干点
  • 单击方框裁剪
    • 选择ISO 选择文本  
    • 选择一个点(将显示一个蓝色三面体)
    • 移动鼠标并单击左键以定义裁剪框大小
  • 在颜色组合框中选择紫色
  • 单击方框裁剪
    • 选择ISO 选择文本
    • 选择一个点(将显示一个紫色三面体)
    • 移动鼠标并单击左键以定义裁剪框大小
  • 文件菜单中,单击新建
  • 新建对话框中选择 CAAGeometry,然后单击确定(颜色组合框中的当前颜色恢复为红色)
  • 在颜色组合框中选择蓝色
  • 单击方框裁剪
    • 选择ISO 选择文本
    • 选择一个点(将显示一个蓝色三面体)
    • 移动鼠标并单击左键以定义裁剪框大小
  • 切换回第一个 CAAGeometry 文档(颜色组合框中的当前颜色仍为紫色)
  • 工具菜单中,单击自定义
    • 选择命令选项卡
    • 所有命令类别中选择 CAAAfrComboColorHdr
    • 将该命令头拖放至图表窗口工具栏
    • 单击确定
  • 在其中一个颜色组合框实例中选择红色(另一个实例也会同步变为红色)

 

CAAAfrComboColorHeader 代码位置

CAAAfrComboColorHeader 示例由多个类组成,这些类位于 CAAApplicationFrame.edu 框架的三个模块中:
  • Windows 平台:InstallRootDirectory\CAAApplicationFrame.edu\
  • Unix 平台:InstallRootDirectory/CAAApplicationFrame.edu/

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

CAAAfrCustCommandHdrModel.m 模块

该模块包含用于定义(更新)当前颜色控制组件的相关类:
  • CAAIAfrTemporaryObjectColor.cppCAAIAfrTemporaryObjectColor.h(PublicInterfaces 目录)TIE_CAAIAfrTemporaryObjectColor.tsrc(src 目录)
    用于管理当前颜色的接口。
  • CAAEAfrTemporaryObjectColor.h(LocalInterfaces 目录)CAAEAfrTemporaryObjectColor.cpp(src 目录)
    该类是 CAASysGeomRootObj 组件上 CAAIAfrTemporaryObjectColor 接口的实现类。
  • CAAAfrComboColorNotification.h(LocalInterfaces 目录)CAAAfrComboColorNotification.cpp(src 目录)
    当当前颜色被修改时,由 CAAEAfrTemporaryObjectColor 类发送的通知类。

CAAAfrCustomizedCommandHeader.m 模块

该模块包含用于定义颜色组合框命令头的相关类:
  • CAAAfrComboRep.h(LocalInterfaces 目录)CAAAfrComboRep.cpp(src 目录)
  • CAAEAfrCommandHeaderRepForComboColor.h(LocalInterfaces 目录)CAAEAfrCommandHeaderRepForComboColor.cpp(src 目录)
  • CAAAfrComboColorHeader.cpp(src 目录)CAAAfrComboColorHeader.h(PrivateInterfaces 目录)

CAAAfrGeoWksAddin2.m 模块

该模块包含 CAAGeometry 工作台的一个插件(Add‑in):
  • CAAAfrGeoChartWindowAdn.h(LocalInterfaces 目录)CAAAfrGeoChartWindowAdn.cpp(src 目录)

分步实现

CAAAfrComboColorHeader 包含四个逻辑步骤:
  1. 创建用于表示组合框中当前颜色的组件
  2. 创建用于表示命令头的组件
  3. 创建用于实例化图形显示样式的类
  4. 实例化该组合框命令头类

创建表示组合框中当前颜色的数据模型

当前颜色由 CAASysGeomRootObj 组件维护,该组件实现了 CAAIAfrTemporaryObjectColor 接口,用于设置和获取当前颜色(图 3)。当组件上的颜色被修改(通过 Set 方法)时,会通过回调机制 [5] 发送 CAAAfrComboColorNotification 通知。
下面是 CAAIAfrTemporaryObjectColor 接口的代码,你可以在 CAAApplicationFrame.edu 框架的 PublicInterfaces 目录中找到该文件。有关该接口创建的更多细节,请参考《创建接口》用例 [6]。
...
#include <CATBaseUnknown.h>      

class ExportedByCAAAfrCustCommandHdrModel CAAIAfrTemporaryObjectColor: public CATBaseUnknown
{
  CATDeclareInterface;

  public:
      virtual HRESULT GetCurrentColor(int & oRed, int & oGreen, int & oBlue) const = 0 ;
      virtual HRESULT SetCurrentColor(int & iRed, int & iGreen, int & iBlue) = 0 ;
};
...

该接口由 CAASysGeomRootObj 组件通过扩展类 CAAEAfrTemporaryObjectColor 实现。

...
#include "TIE_CAAIAfrTemporaryObjectColor.h"              
TIE_CAAIAfrTemporaryObjectColor(CAAEAfrTemporaryObjectColor); 

CATImplementClass (CAAEAfrTemporaryObjectColor,DataExtension, 
                          CATBaseUnknown, CAASysGeomRootObj);
...
CAAEAfrTemporaryObjectColor 类通过 TIE_CAAIAfrTemporaryObjectColor 宏声明自身实现了 CAAIAfrTemporaryObjectColor 接口。该扩展类专用于此组件,而 CATImplementClass 宏通过 DataExtension 关键字声明 CAAEAfrTemporaryObjectColor 是一个数据扩展类,并指明它扩展的是主类为 CAASysGeomRootObj 的组件。第三个参数必须固定设为 CATBaseUnknown,该参数对扩展类无实际意义,也不会被使用。

在类的构造函数中可以看到,颜色默认值为红色(255,0,0)。

...
CAAEAfrTemporaryObjectColor::CAAEAfrTemporaryObjectColor(): CATBaseUnknown()
                            
{    
   _RedComp   = 255   ;
   _GreenComp = 10    ;
   _BlueComp  = 0     ; 
}

CAAEAfrTemporaryObjectColor::~CAAEAfrTemporaryObjectColor(){}
...

GetCurrentColor 方法返回代表当前颜色红、绿、蓝三个分量的成员变量。

...
HRESULT CAAEAfrTemporaryObjectColor::GetCurrentColor(int & oRed, int & oGreen, int & oBlue) const
{
   oRed   = _RedComp ;
   oGreen = _GreenComp ;
   oBlue  = _BlueComp ; 

   return (S_OK) ;
}
...

SetCurrentColor 方法通过输入参数为三个颜色分量成员变量赋值:

...
HRESULT CAAEAfrTemporaryObjectColor::SetCurrentColor(int & iRed, int & iGreen, int & iBlue) 
{
   _RedComp   = iRed   ;
   _GreenComp = iGreen;
   _BlueComp  = iBlue; 
...

并发送一条通知:

...
    CATCallbackManager * pCBManager = ::GetDefaultCallbackManager(this) ;
    if ( NULL != pCBManager )
    {
         CAAAfrComboColorNotification * pNotification = new CAAAfrComboColorNotification();
         pCBManager->DispatchCallbacks(pNotification,this);
         pNotification->Release(); pNotification = NULL ;
    }
   return (S_OK) ;
}
...
SetCurrentColor 方法会发布通知,表明当前颜色已被修改。为此,全局函数 GetDefaultCallbackManager 获取与 CAAEAfrTemporaryObjectColor 实例默认关联的回调管理器,该管理器通过 DispatchCallbacks 方法,借助创建的 CAAAfrComboColorNotification 通知,告知所有订阅者或监听器当前颜色已发生变更。

有关回调机制的详细说明,以及 CAAAfrComboColorNotification 必须如何创建,请参考回调机制用例 [7]。您将了解到为何在调用 DispatchCallbacks 后立即释放 CAAAfrComboColorNotification 类实例。具体可参见 CAAAfrComboColorRep 类的构造函数。

创建表示命令头的组件

该组合框命令头是一个组件,在对象模型器(Object Modeler)与 C++ 架构下,必须继承自 CATAfrDialogCommandHeader,并且必须实现 CATIAfrCommandHeaderRep 接口(图 4)。本部分内容分为两小节:
  • 组件创建
  • CATIAfrCommandHeaderRep 接口实现

组件创建

以下是 CAAAfrComboColorHeader 头文件代码:

 

//ApplicationFrame 框架
#include "CATAfrDialogCommandHeader.h"

class ExportedByCAAAfrCustomizedCommandHeader CAAAfrComboColorHeader : public CATAfrDialogCommandHeader
{
  CATDeclareHeaderResources;
  CATDeclareClass ;

  public:
    CAAAfrComboColorHeader(const CATString & iHeaderName);

    virtual ~CAAAfrComboColorHeader();
    CATCommandHeader * Clone() ;
      
  private:
    CAAAfrComboColorHeader(CATCommandHeader *iHeaderToCopy);
    CAAAfrComboColorHeader(const CAAAfrComboColorHeader &iObjectToCopy);
    CAAAfrComboColorHeader & operator =(const CAAAfrComboColorHeader &iObjectToCopy);
};

CAAAfrComboColorHeader 继承自 CATAfrDialogCommandHeader,这对于拥有自定义图形表现形式的命令头而言是强制要求

CATDeclareClass 宏声明该类属于一个 CAA 组件。

CATDeclareHeaderResources 宏插入用于管理命令头资源的相关方法。

关于必需的公有方法:

  • const CATString 引用 作为参数的构造函数
  • 析构函数
  • CATCommandHeader 继承而来的 Clone 方法,用于复制命令头实例。有关 Clone 方法的完整细节,请参阅关于命令头的技术文章 [2] 中的 “自定义命令头类结构” 章节。

关于必需的私有方法:

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

以下是 CAAAfrComboColorHeader 的源文件代码:

#include "CAAAfrComboColorHeader.h"

CATImplementClass(CAAAfrComboColorHeader, 
                  Implementation,
                  CATAfrDialogCommandHeader, 
                  CATNull);

CATImplementHeaderResources(CAAAfrComboColorHeader,  
			 CATAfrDialogCommandHeader,          
			 CAAAfrComboColorHeader);            

CAAAfrComboColorHeader::CAAAfrComboColorHeader(const CATString & iHeaderName) : 
    CATAfrDialogCommandHeader(iHeaderName){}

CAAAfrComboColorHeader::~CAAAfrComboColorHeader(){}

CATCommandHeader * CAAAfrComboColorHeader::Clone ()                                  
{ 
    return new CAAAfrComboColorHeader(this); 
}   

CAAAfrComboColorHeader::CAAAfrComboColorHeader(CATCommandHeader * iHeaderToCopy):
                          CATAfrDialogCommandHeader(iHeaderToCopy)
{}
  • 自定义命令头是一个 CAA 组件。CATImplementClass 宏将 CAAAfrComboColorHeader 类声明为组件主类(Implementation 类型),使其在对象模型上继承自 CATAfrDialogCommandHeader [9]。
  • CATImplementHeaderResources 宏与头文件中的 CATDeclareHeaderResources 宏配合使用。它表明 CAAAfrComboColorHeader 类继承自 CATAfrDialogCommandHeader,并且其关联的资源文件名分别使用类名命名:CAAAfrComboColorHeader.CATNls 和 CAAAfrComboColorHeader.CATRsc。第二个参数设置的基类名有助于实现资源继承。第三个参数可以设为另一个关联了对应类名资源文件的类名,也可以设为已存在的一组资源文件的无后缀文件名。
  • Clone 方法返回当前对象的一个拷贝构造实例。

CATIAfrCommandHeaderRep 接口实现

ApplicationFrame 框架中的该接口,所有具备自定义图形表现形式的命令头都必须实现它
在图 4 中可以看到,CAAEAfrCommandHeaderRepForComboColor 类是该接口针对 CAAAfrComboColorHeader 组件的实现类。
以下是 CAAEAfrCommandHeaderRepForComboColor 头文件内容:
...
class CAAEAfrCommandHeaderRepForComboColor : public CATBaseUnknown
{
  CATDeclareClass;
public:
  
  CAAEAfrCommandHeaderRepForComboColor();
  virtual ~CAAEAfrCommandHeaderRepForComboColor();
  
  virtual HRESULT  CreateToolbarRep (const CATDialog * iParent,
                                            CATAfrCommandHeaderRep ** oHdrRep) ;
  virtual HRESULT  CreateMenuRep    (const CATDialog * iParent,
                                            CATAfrCommandHeaderRep ** oHdrRep) ;
  virtual HRESULT  CreateCtxMenuRep (const CATDialog * iParent,
                                            CATAfrCommandHeaderRep ** oHdrRep) ;
  
private:
  CAAEAfrCommandHeaderRepForComboColor(const CAAEAfrCommandHeaderRepForComboColor &iObjectToCopy);
  CAAEAfrCommandHeaderRepForComboColor & operator = (const CAAEAfrCommandHeaderRepForComboColor &iObjectToCopy);
};

CATDeclareClass 宏声明 CAAEAfrCommandHeaderRepForComboColor 属于一个组件。

CreateToolbarRep、CreateMenuRep、CreateCtxMenuRep 均为 CATIAfrCommandHeaderRep 接口的方法。

以下是 CAAEAfrCommandHeaderRepForComboColor 类的源文件:

...
#include <TIE_CATIAfrCommandHeaderRep.h>
TIE_CATIAfrCommandHeaderRep(CAAEAfrCommandHeaderRepForComboColor);

CATImplementClass(CAAEAfrCommandHeaderRepForComboColor, 
                  DataExtension,
                  CATBaseUnknown, 
                  CAAAfrComboColorHeader);
};

CAAEAfrCommandHeaderRepForComboColor::
           CAAEAfrCommandHeaderRepForComboColor():CATBaseUnknown(){}

CAAEAfrCommandHeaderRepForComboColor::~CAAEAfrCommandHeaderRepForComboColor(){}
...

CAAEAfrCommandHeaderRepForComboColor 类通过 TIE_CATIAfrCommandHeaderRep 宏声明其实现了 CATIAfrCommandHeaderRep 接口。

CATImplementClass 宏通过 DataExtension 关键字声明该类为数据扩展类,用于扩展 CAAAfrComboColorHeader 组件。对于任何类型的扩展类,第三个参数必须固定设置为 CATBaseUnknownCATNull

该类的构造函数与析构函数均为空实现。

...
HRESULT CAAEAfrCommandHeaderRepForComboColor::CreateToolbarRep
         (const CATDialog * iParent,CATAfrCommandHeaderRep ** oHdrRep)
{
   HRESULT rc = E_FAIL ;

   if ( oHdrRep != NULL )
   {
      CATString Name = "CAAAfrComboRepId" ;
      CAAAfrComboRep * pComboRep = new CAAAfrComboRep(iParent,Name);

      *oHdrRep = (CATAfrCommandHeaderRep *) pComboRep ;
      rc = S_OK ;
   }

   return rc ;
}
...

CreateToolbarRep 方法提供用于实例化组合框命令头图形界面的类。每当需要在工具栏中显示该命令头时,系统都会调用此方法。

CAAAfrComboRep 类是一个 CATCommand 类(图 5),负责实例化组合框命令头的图形界面(即一个 CATDlgCombo 实例)。下一节 “创建实例化图形界面的组件” 会对其进行详细说明。

iParent 是一个 CATDialog 组件,将作为 CATDlgCombo 实例的对话框父控件。

Name 是 CAAAfrComboRep 类的命令名称,所有 CAAAfrComboRep 实例均可使用同一个标识符。

您无需管理 CAAAfrComboRep 实例的生命周期:返回值 oHdrRep 由应用框架持有,该指针对象会被自动释放。

...
HRESULT CAAEAfrCommandHeaderRepForComboColor::
             CreateMenuRep(const CATDialog * iParent, CATAfrCommandHeaderRep ** oHdrRep)
{
  return E_FAIL;
}

HRESULT CAAEAfrCommandHeaderRepForComboColor::
          CreateCtxMenuRep(const CATDialog * iParent, CATAfrCommandHeaderRep ** oHdrRep)
{
  return E_FAIL;
}

该组合框命令头在菜单栏或右键菜单中不显示,因此 CreateMenuRepCreateCtxMenuRep 均返回 E_FAIL

创建实例化图形表示的类

该类为 CAAAfrComboRep,其主要作用如下:
  • 设置回调,以便在 CAASysGeomRootObj 组件上的当前颜色发生变化时接收通知(详见 “创建表示组合框中当前颜色的数据模型” 步骤)
  • 创建一个 CATDlgCombo 实例
  • CAASysGeomRootObj 组件发送通知时,更新 CATDlgCombo 实例的当前选中值

CAAAfrComboRep 头文件

...
class CAAAfrComboRep : public CATAfrCommandHeaderRep
{
public:
  // 构造函数
  CAAAfrComboRep(const CATDialog * iParent, CATString & iCommandName);
  // 析构函数
  virtual ~CAAAfrComboRep();

  // 构建方法
  HRESULT Build();

private:
  // 选择回调函数
  void SelectCB(CATCommand * iPublishingCommand, 
                CATNotification * iNotification, 
                CATCommandClientData iData);

  // 修改回调函数
  void ModifiedCB(CATCallback       iEvent, 
                  void            *       , 
                  CATNotification * iNotification, 
                  CATCallbackEvent  iData,
		          CATSubscriberData iCallBack);
  // 设置当前颜色
  HRESULT SetCurrentColor() ;

  // 拷贝构造函数(私有化,禁止使用)
  CAAAfrComboRep(const CAAAfrComboRep &iObjectToCopy);
  // 赋值运算符重载(私有化,禁止使用)
  CAAAfrComboRep & operator = (const CAAAfrComboRep &iObjectToCopy);

private:
     CATDlgCombo    * _pCombo;         // 组合框控件指针
     CATBaseUnknown * _pUIActiveObject;// UI 活动对象指针
     int              _ColorTable[30] ;// 颜色表数组
};
  • CAAAfrComboRep 类继承自 CATAfrCommandHeaderRep 类(图 5)。
  • Build 方法是 CATAfrCommandHeaderRep 类中的方法,您必须重写该方法。在 CATAfrCommandHeaderRep 类中,它是一个纯虚函数。该方法会在 CAAAfrComboRep 类实例化之后,也就是在 CreateToolbarRep 方法调用完成后,由应用框架立即调用。
  • 私有方法部分

    • SelectCB 方法:当最终用户在组合框中选择一种颜色时触发的回调方法。
    • ModifiedCB 方法:当 CAASysGeomRootObj 组件发送 CAAAfrComboColorNotification 通知时被调用的回调方法。
    • SetCurrentColor 方法:由 SelectCB 和 ModifiedCB 方法调用,用于修改数据成员 _pCombo 的当前选中值。
  • 数据成员部分

    • _pCombo:在 Build 方法中创建的 CATDlgCombo 类实例。
    • _pUIActiveObject:CAAGeometry 文档的 UI 活动对象,负责发送 CAAAfrComboColorNotification 通知并保存当前颜色。在您的建模设计中,该对象也可以是 UI 活动对象之外的其他组件。
    • _ColorTable:用于定义十种颜色的数组 —— 参见图 2。

CAAAfrComboRep 源文件内容如下:

类构造函数

首先初始化组合框的十个颜色值。为简化该用例,颜色值数量固定为十个,并且采用硬编码方式实现。
...
CAAAfrComboRep::CAAAfrComboRep(const CATDialog * iParent,CATString & iCommandName): 
                     CATAfrCommandHeaderRep(iParent,iCommandName)
                    ,_pUIActiveObject(NULL),_pCombo(NULL)
{
   float val ;
   for ( int i= 0 ; i < 10 ; i++)
   {
      // 红色分量
      val = (255 * i / 9 ); 
      _ColorTable[i*3]   = (int)val;

      // 绿色分量
      _ColorTable[i*3+1] = 10 ;

      // 蓝色分量
      val = (255 * (9-i) / 9); 
      _ColorTable[i*3+2] = (int)val;
   }
...

第二步是获取 CAASysGeomRootObj 组件,该组件同时也是 CAAGeometry 文档的 UI 活动对象。

...
   // 获取当前编辑器
   CATFrmEditor * pEditor   = CATFrmEditor::GetCurrentEditor();
   if ( NULL != pEditor )
   {
       // 获取UI活动对象路径
       CATPathElement path = pEditor->GetUIActiveObject();
       if ( 0 != path.GetSize() ) 
       {
          // 取路径最后一个对象作为UI活动对象
          _pUIActiveObject=path[path.GetSize()-1];

          // 增加引用计数
          _pUIActiveObject->AddRef();
       }
   }
...

最后一步是设置回调方法,用于在 CAASysGeomRootObj 组件发送 CAAAfrComboColorNotification 通知时接收提醒 —— 换句话说,就是当 CAASysGeomRootObj 组件所保存的当前颜色被修改时触发回调。

...
   // 为UI活动对象添加颜色变更通知回调
   if ( NULL != _pUIActiveObject )
   {
      ::AddCallback(this,                   // 回调订阅者
                   _pUIActiveObject,        // 通知发送者
	          "CAAAfrComboColorNotification", // 通知名称
	          (CATSubscriberMethod)&CAAAfrComboRep::ModifiedCB, // 回调处理函数
	          NULL);
   }
}
AddCallback 是一个静态全局函数,其参数说明如下:
  • this:回调订阅者
  • _pUIActiveObject:通知发布者
  • CAAAfrComboColorNotification:由发布者发送的通知类
  • ModifiedCB:收到 CAAAfrComboColorNotification 通知时将被调用的当前类成员方法
  • NULL:回调方法无附加参数

析构函数

...
CAAAfrComboRep::~CAAAfrComboRep()
{
    if ( NULL != _pUIActiveObject )
    {
       // 移除当前对象在发布者上注册的所有回调
       ::RemoveSubscriberCallbacks(this, _pUIActiveObject);

        // 释放UI活动对象的引用计数
        _pUIActiveObject->Release();
        _pUIActiveObject = NULL ;
    }
    if ( NULL != _pCombo )
    {
       // 延迟销毁组合框控件
       _pCombo->RequestDelayedDestruction();
       _pCombo = NULL ;
    }

}...

最后,在构造函数中注册的回调必须从回调管理器中移除 [7],同时 CATDlgCombo 控件实例也必须被释放。

Build 方法

必须重写此方法。该方法的作用是创建图形界面并完成初始化。
第一步是获取待创建图形界面的对话框父对象。该信息由 CATAfrCommandHeaderRep 类维护,并通过其 GetDialogParent 方法获取。随后,你可以使用对话框父对象 pParent 创建一个 CATDlgCombo 类实例。

CATDlgCombo 类的第二个参数是对话框对象的标识符,最后一个参数是组合框的类型(CATDlgCmbColor:颜色选择组合框)。创建完成后,你可以设置一个回调函数,用于在最终用户从十个颜色值中选择一种颜色时接收通知。

...
HRESULT  CAAAfrComboRep::Build()
{
   const CATDialog * pParent = NULL ;
   GetDialogParent(&pParent);

   _pCombo = new CATDlgCombo((CATDialog *)pParent, "CAAAfrEduCombo", CATDlgCmbColor);

   AddAnalyseNotificationCB(_pCombo,
			   _pCombo->GetComboSelectNotification(),
			   (CATCommandMethod)&CAAAfrComboRep::SelectCB,
			   (CATCommandClientData)NULL);
...

然后,你可以使用在构造函数中初始化的成员变量 _ColorTable,为组合框填充这十个颜色值。初始化完成后,调用 SetCurrentColor 方法设置当前选中值。

...
   for ( int i=0 ; i < 10 ; i++)
   {
     _pCombo->SetLine(CATUnicodeString(),
			(unsigned char)_ColorTable[i*3 ], 
			(unsigned char)_ColorTable[i*3+1], 
			(unsigned char)_ColorTable[i*3+2], 
			i);
   }
   SetCurrentColor();
...

最后,修改组合框的 CATCommand 父对象。默认情况下,命令父对象就是对话框父对象,也就是即将插入组合框的容器 pParent。如果你不修改命令父对象,当前的 CAAAfrComboRep 实例将无法接收 GetComboSelectNotification 通知。有关命令树的详细说明,请参阅参考文章 [8]。

...
   _pCombo->SetFather(this);

   return S_OK ;
}
...

SelectCB 方法

当最终用户在组合框中选择了一种颜色时,将调用 SelectCB 方法。该回调方法在 _pCombo 发送通知时被触发。
此方法的作用是:首先通过 GetSelect 获取当前选中的颜色,然后修改 CAASysGeomRootObj 组件上保存的当前颜色。_pUIActiveObject 即为 CAASysGeomRootObj 组件,它实现了 CAAIAfrTemporaryObjectColor 接口。
...
void CAAAfrComboRep::SelectCB(CATCommand * iPublishingCommand, 
			      CATNotification * iNotification, 
			      CATCommandClientData iData)
{
  CAAIAfrTemporaryObjectColor * pITemporaryObjectColor = NULL ;
  HRESULT rc = _pUIActiveObject->QueryInterface(IID_CAAIAfrTemporaryObjectColor,
                                                (void**) & pITemporaryObjectColor);
  ...
     int val = _pCombo->GetSelect();

     pITemporaryObjectColor->SetCurrentColor(_ColorTable[val*3 ],
                                                _ColorTable[val*3+1],
                                                _ColorTable[val*3+2]);
...

ModifiedCB 方法

ModifiedCB 方法会在 CAASysGeomRootObj 组件发送 CAAAfrComboColorNotification 通知时被调用。它用于告知 CAAAfrComboRep 类实例:CAASysGeomRootObj 组件上的当前颜色已被修改。
...
void CAAAfrComboRep::ModifiedCB(CATCallback, 
                              void *, 
                              CATNotification * iNotification,
			                  CATCallbackEvent, 
                              CATSubscriberData)
{
   SetCurrentColor();
}
...

SetCurrentColor 方法

该方法用于读取 CAASysGeomRootObj 组件上的当前颜色,并通过 SetSelect 方法更新 CAAAfrComboRep 类的 CATDlgCombo 成员变量 _pCombo 的当前选中值。
...
HRESULT CAAAfrComboRep::SetCurrentColor()
{
   CAAIAfrTemporaryObjectColor * pITemporaryObjectColor = NULL ;
   HRESULT rc = _pUIActiveObject->QueryInterface(IID_CAAIAfrTemporaryObjectColor,
                                                (void**) & pITemporaryObjectColor);
   ...
      int r,g,b ;
      pITemporaryObjectColor->GetCurrentColor(r,g,b);

      int position = 0 ;
      CATBoolean FOUND = FALSE ;
      while ( ( FALSE == FOUND) && ( position < 10 ))
      {
         if ( (r == _ColorTable[position*3 ]) &&
              (g == _ColorTable[position*3+1 ]) &&
              (b == _ColorTable[position*3+2 ]) )
         {
             FOUND = TRUE ;
         }else position ++ ;
      }

      if ( TRUE == FOUND) 
      {
         _pCombo->SetSelect(position,0);
      }
...

实例化组合框命令头类

该组合框命令头用于 CAAGeometry 文档。此命令头的实例已在文档工作台的一个插件(Add-in)中创建。以下是 CAAAfrGeoChartWindowAdn 类的代码片段,该类是 CAAIAfrGeometryWksAddin 接口的实现类。
...
void CAAAfrGeoChartWindowAdn::CreateCommands()
{
...
   new CAAAfrComboColorHeader("CAAAfrComboColorHdr");
}

组合框命令头通过其构造函数直接创建。

小结

本示例说明了如何创建一个具有自定义图形显示样式的命令头:
  • 该命令头是一个组件,在对象模型(OM)与 C++ 层面均继承自 CATAfrDialogCommandHeader,并实现 CATIAfrCommandHeaderRep 接口。
  • 自定义图形显示由一个类创建,该类必须继承自 CATAfrCommandHeaderRep
控制图形显示所使用数据的组件,与具体文档相关。
posted @ 2026-04-21 11:08  Breadss  阅读(8)  评论(0)    收藏  举报