Creating Editors in Toolbars-如何创建一个命令头类,使其在工具栏中的呈现形式为一个编辑器?
摘要
-
通过本用例你将学到
-
CAAAfrEltCountHeader 用例介绍
- CAAAfrEltCountHeader 功能说明
- CAAAfrEltCountHeader 启动方法
- CAAAfrEltCountHeader 代码存放路径
-
操作步骤
-
内容小结
-
参考资料
本用例学习目标
- 创建命令头对应组件
该组件必须继承自CATAfrDialogCommandHeader类。 - 创建用于实例化图形界面的组件
该组件必须继承自CATAfrCommandHeaderRep类,并实例化两个CATDlgEditor编辑控件对象。 - 创建图形界面的数据控制组件
界面所展示的数据为当前文档中的直线数量与点数量,该数据与 V5 文档实例强相关。
拓展阅读
- CAAAfrComboColorHeader 用例 [1]:介绍另一款自定义命令头,其工具栏展示形式为下拉组合框,实现方式与本文相似。
- CAAAfrMRUHeader 用例 [2]:介绍另一款自定义命令头,在菜单栏下拉菜单中展示动态按钮列表。与本文用例不同,其数据源为字符串列表,独立于文档内容。
若想完整理解本文内容,建议先阅读技术文档《命令头》[3],重点查阅「创建自定义命令头」章节。
CAAAfrEltCountHeader 用例
CAAAfrEltCountHeader 功能说明

存在一个命令头,用于显示 CAAGeometry 文档中所创建点元素与直线元素的数量 [5]。
CAASysGeomCont 组件是用于管控界面展示数据的核心组件。该组件通过 CAAISysCollection 接口,对 CAAGeometry 文档内的元素列表进行管理。
图 2 界面展示数据控制组件 - UML 类图


CAAAfrEltCountHeader 是一个组件,必须实现 CATIAfrCommandHeaderRep 接口,以此提供自定义的图形界面展示。该接口包含三个方法:
- CreateCtxMenuRep:无返回值
- CreateMenuRep:无返回值
- CreateToolbarRep:用于实例化 CAAAfrEltCountRep 类对象。该类的结构由下方 UML 类图进行说明:
- 图 4 图形呈现实例化类 — UML 类图
![图片]()
如何运行 CAAAfrEltCountHeader
CAAAfrEltCountHeader 代码存放位置
- Windows 系统:
安装根目录\CAAApplicationFrame.edu\ - Unix 系统:
安装根目录/CAAApplicationFrame.edu/
其中,安装根目录为 CAA 安装包的安装路径。
- CAAAfrCustomizedCommandHeader.m 模块包含用于定义元素计数命令头及其自定义界面呈现的相关类:
CAAAfrEltCountRep.h(本地接口目录)、CAAAfrEltCountRep.cpp(源码目录)CAAEAfrCommandHeaderRepForEltCount.h(本地接口目录)、CAAEAfrCommandHeaderRepForEltCount.cpp(源码目录)CAAAfrEltCountHeader.cpp(源码目录)、CAAAfrEltCountHeader.h(私有接口目录)
- CAAAfrGeoModel.m 模块包含:
CAAEAfrCollection.h(本地接口目录)、CAAEAfrCollection.cpp(源码目录)
该文件是 CAAISysCollection 接口的数据扩展,在 CAASysGeomCont 组件上实现。该组件与对应接口均定义于 CAASystem.edu 框架内 [5]。
分步实现
- 创建数据提供组件
- 创建命令头展示组件
- 创建图形呈现实例化类
创建数据提供组件
CAAISysCollection 接口位于 CAASystem.edu 框架的公共接口目录下。如需了解该接口的创建细节,可参考《创建接口》相关用例 [8]。
// 由 CAASysGeoModelInf 模块导出
class ExportedByCAASysGeoModelInf CAAISysCollection : public CATBaseUnknown
{
// 声明CAA接口
CATDeclareInterface;
public:
/**
* 获取对象总数
* @param oCount [输出] 对象数量
*/
virtual HRESULT GetNumberOfObjects(int * oCount) = 0;
/**
* 根据索引获取对象
* @param iRank [输入] 索引序号
* @param oObject [输出] 获取到的对象指针
*/
virtual HRESULT GetObject(int iRank, CATBaseUnknown ** oObject) = 0;
/**
* 添加对象到集合
* @param iObject [输入] 待添加的对象
*/
virtual HRESULT AddObject(CATBaseUnknown * iObject) = 0;
/**
* 从集合中移除对象
* @param iObject [输入] 待移除的对象
*/
virtual HRESULT RemoveObject(CATBaseUnknown * iObject) = 0;
/**
* 清空集合中所有对象
*/
virtual HRESULT Empty() = 0;
};
该接口由 CAASysGeomCont 组件通过 CAAEAfrCollection 类扩展实现。
...
#include "TIE_CAAISysCollection.h"
TIE_CAAISysCollection(CAAEAfrCollection);
CATBeginImplementClass(CAAEAfrCollection,DataExtension,CATBaseUnknown,CAASysGeomCont);
CATAddClassExtension(CAASysSampCont) ;
CATEndImplementClass(CAAEAfrCollection);
...
CAAEAfrCollection 类通过 TIE_CAAISysCollection 宏声明自身实现了 CAAISysCollection 接口。该扩展类专属于目标组件,CATBeginImplementClass 宏借助 DataExtension 关键字声明 CAAEAfrCollection 为数据扩展类,并指明其扩展的主类为 CAASysGeomCont 的组件。第三个参数必须固定设置为 CATBaseUnknown,该参数对扩展类无实际意义,也不会被使用。
创建命令头展示组件
CATAfrDialogCommandHeader,同时必须实现 CATIAfrCommandHeaderRep 接口(见图 3)。- 组件创建
- CATIAfrCommandHeaderRep 接口实现
组件创建
// 应用框架模块
#include "CATAfrDialogCommandHeader.h"
// 由 CAAAfrCustomizedCommandHeader 模块导出
class ExportedByCAAAfrCustomizedCommandHeader CAAAfrEltCountHeader
: public CATAfrDialogCommandHeader
{
// 声明命令头资源管理相关内容
CATDeclareHeaderResources;
// 声明CAA组件类
CATDeclareClass;
public:
// 构造函数:传入命令头名称
CAAAfrEltCountHeader(const CATString & iHeaderName);
// 析构函数
virtual ~CAAAfrEltCountHeader();
// 命令头克隆方法
CATCommandHeader * Clone();
private:
// 拷贝构造(禁止使用)
CAAAfrEltCountHeader(CATCommandHeader *iHeaderToCopy);
// 复制构造(禁止使用)
CAAAfrEltCountHeader(const CAAAfrEltCountHeader &iObjectToCopy);
// 赋值运算符重载(禁止使用)
CAAAfrEltCountHeader & operator = (const CAAAfrEltCountHeader &iObjectToCopy);
};
CAAAfrEltCountHeader 类继承自 CATAfrDialogCommandHeader 类。如需自定义命令头的界面展示样式,必须继承此类。CATDeclareClass 宏用于声明当前类属于 CAA 标准组件。CATDeclareHeaderResources 宏会自动植入相关方法,用于统一管理命令头的各类资源。
必选公有方法说明:
- 构造函数:入参为常量 CATString 引用;
- 析构函数;
- Clone 方法:继承自 CATCommandHeader,用于复制命令头实例。
可参考命令头相关技术文档中「自定义命令头类结构」章节 [2],里面包含 Clone 方法的完整详细说明。
必选私有方法说明:
- 接收 CATCommandHeader 指针的构造函数,专门为 Clone 方法提供调用支持;
- 另外两个构造函数在私有域中进行声明,且不在源文件中实现。
该写法可避免编译器暗中自动生成公有拷贝构造与赋值函数,防止非预期调用。
以下是 CAAAfrEltCountHeader 的源文件代码:
#include "CAAAfrEltCountHeader.h"
CATImplementClass(CAAAfrEltCountHeader,
Implementation,
CATAfrDialogCommandHeader,
CATNull);
CATImplementHeaderResources(CAAAfrEltCountHeader,
CATAfrDialogCommandHeader,
CAAAfrEltCountHeader);
CAAAfrEltCountHeader::CAAAfrEltCountHeader(const CATString & iHeaderName) :
CATAfrDialogCommandHeader(iHeaderName){}
CAAAfrEltCountHeader::~CAAAfrEltCountHeader(){}
CATCommandHeader * CAAAfrEltCountHeader::Clone ()
{
return new CAAAfrEltCountHeader(this);
}
CAAAfrEltCountHeader::CAAAfrEltCountHeader(CATCommandHeader * iHeaderToCopy):
CATAfrDialogCommandHeader(iHeaderToCopy)
{}
自定义命令头属于 CAA 组件。
CATImplementClass 宏将 CAAAfrEltCountHeader 定义为组件主实现类(Implementation),并通过对象建模器继承 [10] 自 CATAfrDialogCommandHeader。CATImplementHeaderResources 宏需与头文件中的 CATDeclareHeaderResources 宏配合使用。该宏声明:CAAAfrEltCountHeader 类继承自 CATAfrDialogCommandHeader,且其关联资源文件以当前类名命名,分别为:CAAAfrEltCountHeader.CATNls(文本资源)与 CAAAfrEltCountHeader.CATRsc(界面资源)。
Clone 方法会通过拷贝构造函数,生成并返回当前命令头的全新实例副本。
CATIAfrCommandHeaderRep 接口实现
如图 3 所示,CAAEAfrCommandHeaderRepForEltCount 类是为 CAAAfrEltCountHeader 组件专门实现此接口的实现类。
以下为 CAAEAfrCommandHeaderRepForEltCount 头文件代码:
...
class CAAEAfrCommandHeaderRepForEltCount: public CATBaseUnknown
{
CATDeclareClass;
public:
CAAEAfrCommandHeaderRepForEltCount();
virtual ~CAAEAfrCommandHeaderRepForEltCount();
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:
// 禁用拷贝构造
CAAEAfrCommandHeaderRepForEltCount(const CAAEAfrCommandHeaderRepForEltCount& iObjectToCopy);
// 禁用赋值运算符
CAAEAfrCommandHeaderRepForEltCount& operator = (const CAAEAfrCommandHeaderRepForEltCount& iObjectToCopy);
};
CATDeclareClass 宏用于声明 CAAEAfrCommandHeaderRepForEltCount 为 CAA 组件类。CreateToolbarRep、CreateMenuRep、CreateCtxMenuRep 均为 CATIAfrCommandHeaderRep 接口的纯虚方法。
以下是 CAAEAfrCommandHeaderRepForEltCount 源文件代码:
...
#include <TIE_CATIAfrCommandHeaderRep.h>
TIE_CATIAfrCommandHeaderRep(CAAEAfrCommandHeaderRepForEltCount);
CATImplementClass(CAAEAfrCommandHeaderRepForEltCount,
DataExtension,
CATBaseUnknown,
CAAAfrEltCountHeader);
CAAEAfrCommandHeaderRepForEltCount::
CAAEAfrCommandHeaderRepForEltCount() : CATBaseUnknown(){}
CAAEAfrCommandHeaderRepForEltCount::~CAAEAfrCommandHeaderRepForEltCount(){}
...
CAAEAfrCommandHeaderRepForEltCount 类通过 TIE_CATIAfrCommandHeaderRep 宏,声明自身实现了 CATIAfrCommandHeaderRep 接口。
CATImplementClass 宏借助 DataExtension(数据扩展)关键字,将该类定义为数据扩展类,用于扩展 CAAAfrEltCountHeader 组件。
对于所有扩展类而言,第三个参数必须固定填写为 CATBaseUnknown 或 CATNull。此类的构造函数与析构函数均为空实现。
...
HRESULT CAAEAfrCommandHeaderRepForEltCount::CreateToolbarRep
(const CATDialog * iParent,CATAfrCommandHeaderRep ** oHdrRep)
{
HRESULT rc = E_FAIL ;
if ( oHdrRep != NULL )
{
CATString Name = "CAAAfrEltCountRepId" ;
CAAAfrEltCountRep * pEltCountRep = new CAAAfrEltCountRep(iParent,Name);
*oHdrRep = (CATAfrCommandHeaderRep *) pEltCountRep ;
rc = S_OK ;
}
return rc ;
}
...
CreateToolbarRep 方法用于创建元素计数(EltCount)命令头的图形界面对象实例。每当该命令头需要在工具栏中显示时,都会调用此方法。CATCommand 类(见图 4),负责为 EltCount 命令头创建图形界面,包含两个 CATDlgEditor 编辑器控件实例。该类的详细说明见下文创建图形呈现实例化组件章节。iParent 为对话框组件,将作为后续 CATDlgEditor 控件的父级窗口。名称为 CAAAfrEltCountRep 类的命令标识,该类的所有实例可共用同一个标识。开发者无需手动管理 CAAAfrEltCountRep 实例的生命周期。输出参数 oHdrRep 返回的对象由框架应用统一托管,指针内存会自动释放。
HRESULT CAAEAfrCommandHeaderRepForEltCount::
CreateMenuRep (const CATDialog * iParent,CATAfrCommandHeaderRep ** oHdrRep)
{
return E_FAIL ;
}
HRESULT CAAEAfrCommandHeaderRepForEltCount::
CreateCtxMenuRep (const CATDialog * iParent,CATAfrCommandHeaderRep ** oHdrRep)
{
return E_FAIL;
}
EltCount 命令头不在菜单栏与右键上下文菜单中展示,因此 CreateMenuRep 与 CreateCtxMenuRep 两个方法直接返回失败码 E_FAIL。
创建图形呈现实例化类
- 注册回调函数,当 CAASysGeomCont 组件所管控的元素列表发生变更时,接收通知;
- 创建两个 CATDlgEditor 控件实例;
- 当 CAASysGeomCont 组件发出通知时,更新 CATDlgEditor 控件的显示内容。
以下是 CAAAfrEltCountRep 类的头文件代码:
...
class CAAAfrEltCountRep : public CATAfrCommandHeaderRep
{
public:
// 构造函数
CAAAfrEltCountRep(const CATDialog * iParent, CATString & iCommandName);
// 析构函数
virtual ~CAAAfrEltCountRep();
// 构建界面
HRESULT Build();
private:
// 元素修改回调函数
void ModifiedCB(CATCallback iEvent,
void * ,
CATNotification * iNotification,
CATCallbackEvent iData,
CATSubscriberData iCallBack);
// 赋值编辑器显示内容
HRESULT ValuateEditors() ;
// 私有化拷贝构造函数(禁止使用)
CAAAfrEltCountRep(const CAAAfrEltCountRep &iObjectToCopy);
// 私有化赋值运算符(禁止使用)
CAAAfrEltCountRep & operator = (const CAAAfrEltCountRep &iObjectToCopy);
private:
// 点数量编辑器控件
CATDlgEditor * _pEdtPoint;
// 线数量编辑器控件
CATDlgEditor * _pEdtLine;
// 几何元素集合接口指针
CAAISysCollection * _piSysCollection ;
};
- CAAAfrEltCountRep 类继承自 CATAfrCommandHeaderRep 类(见图 4)。
- Build 方法是 CATAfrCommandHeaderRep 类的成员方法,必须由子类重写;该方法在基类中为纯虚函数。框架应用会在 CAAAfrEltCountRep 类实例化完成后立即调用本方法,也就是在
CreateToolbarRep方法执行完毕之后触发。 - 私有方法说明
- ModifiedCB:回调方法。当 CAASysGeomCont 组件发出 CAASysCollectionModifNotif 变更通知时,该方法会被触发调用。
- ValuateEditors:由
Build方法和ModifiedCB方法共同调用,用于更新数据成员_pEdtPoint与_pEdtLine的当前显示内容。
- 数据成员说明
_pEdtPoint、_pEdtLine:两个 CATDlgEditor 控件实例,在Build方法中完成创建。_piSysCollection:接口指针,指向当前 CAA 几何文档中 CAASysGeomCont 组件的 CAAISysCollection 接口。
以下是 CAAAfrEltCountRep 的源文件代码:
类构造函数
...
CAAAfrEltCountRep::CAAAfrEltCountRep(const CATDialog * iParent,CATString & iCommandName):
CATAfrCommandHeaderRep(iParent,iCommandName),
_piSysCollection(NULL),_pEdtPoint(NULL),_pEdtLine(NULL)
{
...
rc = pContainer->QueryInterface(IID_CAAISysCollection, (void**)&_piSysCollection);
...
第二步(也是最后一步):设置回调方法,用于在CAASysGeomCont组件发送CAASysCollectionModifNotif通知时接收消息。
...
if ( NULL != _piSysCollection )
{
::AddCallback(this,
_piSysCollection,
"CAASysCollectionModifNotif",
(CATSubscriberMethod)&CAAAfrEltCountRep::ModifiedCB,
NULL);
}
}
AddCallback 是一个静态全局函数,其参数说明如下:- this:订阅者
- _piSysCollection:发布者
- CAASysCollectionModifNotif:由发布者发出的通知类
- ModifiedCB:订阅者自身的回调方法,当
CAASysCollectionModifNotif通知触发时被调用 - NULL:回调方法无自定义入参
类析构函数
CAAAfrEltCountRep::~CAAAfrEltCountRep()
{
if ( NULL != _piSysCollection )
{
::RemoveSubscriberCallbacks(this, _piSysCollection);
_piSysCollection->Release();
_piSysCollection = NULL ;
}
if ( NULL != _pEdtPoint )
{
_pEdtPoint->RequestDelayedDestruction();
_pEdtPoint = NULL ;
}
if ( NULL != _pEdtLine )
{
_pEdtLine->RequestDelayedDestruction();
}
}
析构阶段,需要从回调管理器中注销构造函数里注册的回调[9],同时释放所有 CATDlgEditor 控件实例资源。
Build 方法
HRESULT CAAAfrEltCountRep::Build()
{
// 创建界面对象
const CATDialog * pParent = NULL ;
GetDialogParent(&pParent);
_pEdtPoint = new CATDlgEditor((CATDialog *)pParent, "CAAAfrEdtPoint",
CATDlgEdtReadOnly);
_pEdtLine = new CATDlgEditor((CATDialog *)pParent, "CAAAfrEdtLine",
CATDlgEdtReadOnly);
// 为编辑框赋值
ValuateEditors();
return S_OK ;
}
第一步:获取待创建界面的父级对话框。该父窗口句柄由基类 CATAfrCommandHeaderRep 统一维护,通过 GetDialogParent 方法获取。随后以获取到的父对话框 pParent 为载体,创建 CATDlgEditor 编辑框控件实例。CATDlgEditor 构造函数第二个参数为对话框控件的唯一标识名,最后一个参数指定编辑框类型(CATDlgEdtReadOnly 只读模式)。最后调用 ValuateEditors 方法,完成编辑框初始内容的赋值与展示初始化。
ModifiedCB 方法
该方法用于通知 CAAAfrEltCountRep 类实例:CAASysGeomCont 组件上的点 / 线数量已被修改。这一功能是通过调用 ValuateEditors 方法实现的。
...
void CAAAfrEltCountRep::ModifiedCB(CATCallback,
void *,
CATNotification * iNotification,
CATCallbackEvent,
CATSubscriberData)
{
ValuateEditors();
}
...
ValuateEditors 方法
CAAAfrEltCountRep 类的两个数据成员:_pEdtPoint 与 _pEdtLine 的当前显示内容。HRESULT CAAAfrEltCountRep::ValuateEditors()
{
...
// 获取集合内元素总数
int nbeltcont = 0 ;
_piSysCollection->GetNumberOfObjects(&nbeltcont);
int NbPoint = 0 ; // 点数量
int NbLine = 0 ; // 直线数量
// 遍历所有几何元素
for (int i=1 ; i <= nbeltcont ; i++)
{
CATBaseUnknown * pObject = NULL ;
rc = _piSysCollection->GetObject(i,&pObject);
if (SUCCEEDED(rc))
{
// 查询点接口
CAAISysPoint * piSysPoint = NULL;
rc = pObject->QueryInterface(IID_CAAISysPoint, (void**)&piSysPoint);
if (SUCCEEDED(rc))
{
// 当前元素为点
NbPoint ++ ;
piSysPoint->Release(); // 释放接口
piSysPoint = NULL ;
}
// 查询直线接口
CAAISysLine * piSysLine = NULL;
rc = pObject->QueryInterface(IID_CAAISysLine, (void**)&piSysLine);
if (SUCCEEDED(rc))
{
// 当前元素为直线
NbLine ++ ;
}
...
// 将数字转为CATIAUnicode字符串
CATUnicodeString stNbPoint ;
stNbPoint.BuildFromNum(NbPoint) ;
CATUnicodeString stNbLine ;
stNbLine.BuildFromNum(NbLine) ;
// 给编辑框赋值、刷新显示
_pEdtPoint->SetText(stNbPoint);
_pEdtLine ->SetText(stNbLine);
...
简要总结
- 命令头作为 CAA 组件,需在对象建模器与 C++ 层面继承自
CATAfrDialogCommandHeader,并实现CATIAfrCommandHeaderRep接口; - 自定义图形界面由专门的类负责创建,该类必须继承自
CATAfrCommandHeaderRep。
为图形界面提供数据的控制组件,与当前文档相互关联、依赖文档上下文。


浙公网安备 33010602011771号