Editing Objects-使自定义对象支持编辑 / 将对象设为可编辑状态

摘要

本文演示如何将对象设置为可编辑状态,以及如何创建配套编辑对话框。
  • 本用例学习目标

  • CAAAfrGeoEdition 用例

    •  CAAAfrGeoEdition 用例功能说明  
 CAAAfrGeoEdition 启动方法
  •  CAAAfrGeoEdition 代码存放位置
  • 分步实现

  • 内容小结

  • 参考文献

 

本用例学习要点

本用例旨在演示如何实现对象可编辑,以及编辑该对象需要提供哪些关联对象。

CAAAfrGeoEdition 用例

CAAAfrGeoEdition 是 CAAApplicationFrame.edu 框架下的示例用例,用于演示应用框架(ApplicationFrame)的各项功能特性。

CAAAfrGeoEdition 用例功能

CAAAfrGeoEdition 用例将点对象设置为可编辑对象,并为其提供编辑命令与编辑对话框。

图片

 

CAAAfrGeoEdition 启动方法

如需了解该用例的详细启动步骤,请参阅《CAAGeometry 示例》用例中标题为「CAAGeometry 用例启动方法」的章节。
针对本用例的专属操作流程如下:
请勿在命令行中输入模块名称,改为输入 CNEXT 启动程序。应用程序加载完成后,按以下步骤操作:
  1. 选择【文件】→【新建】;
  2. 在新建窗口中选择 CAAGeometry,点击【确定】;
  3. 使用【基本图元】工具栏,至少创建一个点;
  4. 右键单击该点,选择【定义】命令。

CAAAfrGeoEdition 代码位置

CAAAfrGeoEdition 用例包含三个类文件,统一存放于 CAAApplicationFrame.edu 框架的 CAAAfrGeoEdition.m 模块中:

Windows 系统路径

安装根目录\CAAApplicationFrame.edu\CAAAfrGeoEdition.m\

Unix 系统路径

安装根目录/CAAApplicationFrame.edu/CAAAfrGeoEdition.m/

其中,安装根目录 指 CAA 安装包的安装目录。

涉及的三个类说明如下:
  • CAAEAfrEditPoint:CAASysPoint 组件的扩展类
  • CAAAfrPointEditCmd:编辑命令类
  • CAAAfrPointEditDlg:编辑命令对应的对话框类

分步实现

要使对象具备可编辑能力,需完成以下三个步骤:
序号操作步骤对应实现类
1 令点对象实现 CATIEdit 接口 CAAEAfrEditPoint 类
2 创建编辑命令 CAAAfrPointEditCmd 类
3 创建编辑对话框 CAAAfrPointEditDlg 类
 

使点对象实现 CATIEdit 接口

CATIEdit 接口主要提供 Activate 方法,该方法需返回一个 CATCommand 类实例,正是该实例实现对象的编辑功能。当最终用户通过双击对象,或通过对象的右键上下文菜单触发编辑操作时,系统会自动调用 Activate 方法。
为了让 CAASysPoint 组件实现 CATIEdit 接口,我们创建一个继承自 CATExtIEdit 适配器类的新类,将其作为 CAASysPoint 类的数据扩展,并实现 Activate 方法的具体逻辑。CATIEdit 接口的其他方法直接从 CATExtIEdit 类继承。

创建 CAAEAfrEditPoint 类的头文件

#include "CATExtIEdit.h"   // 继承 CATExtIEdit 必需的头文件

class CAAEAfrEditPoint : public CATExtIEdit
{
  CATDeclareClass;
  public :
    CAAEAfrEditPoint();
    virtual ~CAAEAfrEditPoint();
    virtual CATCommand  * Activate(CATPathElement * iPath);
  private :
    // 禁用拷贝构造函数
    CAAEAfrEditPoint(const CAAEAfrEditPoint &iObjectToCopy);
};

说明CATDeclareClass 宏声明 CAAEAfrEditPoint 属于一个组件。该类仅重写 CATIEdit 接口的 Activate 方法。

在类的源文件中添加对象建模器代码

...
CATImplementClass(CAAEAfrEditPoint,
                  DataExtension,
                  CATBaseUnknown,
                  CAASysPoint);

#include "TIE_CATIEdit.h"
TIE_CATIEdit(CAAEAfrEditPoint);
...
说明
  • CATImplementClass 宏的含义:CAAEAfrEditPoint 是 CAASysPoint 的数据扩展类
  • 对于所有类型的扩展,第三个参数必须固定为 CATBaseUnknownCATNull
  • TIE 宏为 CATIEdit 接口创建对应的 TIE 类。

实现 Activate 方法

...
CATCommand * CAAEAfrEditPoint::Activate(CATPathElement * pPath)
{
  CAAAfrPointEditCmd *  pEdtCmd = NULL;
  CAAISysPoint * pISysPointOnPoint = NULL;                
  HRESULT rc = QueryInterface(IID_CAAISysPoint, (void**)&pISysPointOnPoint);
  if (SUCCEEDED(rc))
  {
    CAAAfrPointEditCmd *  pEdtCmd = new CAAAfrPointEditCmd(pISysPointOnPoint);
    pISysPointOnPoint->Release();
  }
  return (CATCommand*) pEdtCmd;
}

Activate 方法执行流程:

  1. 获取对象接口指针
    首先获取待编辑对象所实现的接口指针,用于传递给编辑对话框。此处选择获取 CAASysPoint 的类型接口指针,因为该接口提供了管理对象参数的方法 —— 我们需要在对话框中显示并修改这些参数,即点的坐标
  2. 构建编辑命令对象
    创建编辑命令类 CAAAfrPointEditCmd 的实例,并将上述待编辑对象的指针传入该命令。
  3. 返回编辑命令指针
    最终以 CATCommand 基类指针的形式返回创建的编辑命令。

 

创建编辑命令

点编辑命令类命名为 CAAAfrPointEditCmd,直接继承自 CATCommand

该命令除了重写从 CATCommand 继承的三个方法(用于管控命令可用性与生命周期:ActivateDesactivateCancel)以外,还包含 CloseBox 方法。当用户关闭编辑对话框时,会触发该方法,请求销毁对话框。

命令的成员变量包含:对话框指针、以及 CAAISysPoint 接口指针。
以下为 CAAAfrPointEditCmd.cpp 源码内容。下面以事件驱动的逻辑逐段解析。

构造函数

当用户双击对象、或在点对象右键菜单中选择【定义】选项时,命令选择器会调用该构造函数。
CAAAfrPointEditCmd::CAAAfrPointEditCmd(CAAISysPoint * ipEdit)					 
             : CATCommand ("PointEditCommandId",CATCommandModeExclusive),
               _pEdit(ipEdit),_DialogPoint(NULL)
{
  if (_pEdit) _pEdit -> AddRef();
}

构造函数在调用父类 CATCommand 构造时,传入第二个参数 CATCommandModeExclusive,将当前命令设为独占模式,会终止所有正在运行的其他命令。所有会修改文档内容的命令,都必须设置为独占模式。同时,构造函数获取待编辑对象的 CAAISysPoint 接口指针,并手动增加引用计数。

Activate 方法

命令实例创建完成后,命令选择器会立即调用 Activate 方法。
CATStatusChangeRC CAAAfrPointEditCmd::Activate(CATCommand      *iCmd,
                                               CATNotification *iNotif)
{
  if ( ! _DialogPoint)
  {
    CATDlgStyle style = CATDlgWndOK|CATDlgWndAPPLY|CATDlgWndCANCEL|
                        CATDlgWndHELP|         // Unix 平台帮助按钮(长帮助)
                        CATDlgWndTitleBarHelp| // 标题栏帮助(仅 Windows 平台)
                        CATDlgGridLayout ;
    CATString id ("CAAAfrPointEditDlgId");
    CATDialog * pParent = (CATApplicationFrame::GetFrame())->GetMainWindow() ;

    _DialogPoint = new CAAAfrPointEditDlg(pParent,id,style,_pEdit);

    AddAnalyseNotificationCB(_DialogPoint, _DialogPoint->GetWindCloseNotification(),
                             (CATCommandMethod)&CAAAfrPointEditCmd::CloseBox,
                             NULL);

    _DialogPoint->Build();
  }

  _DialogPoint->SetVisibility(CATDlgShow);
  return (CATStatusChangeRCCompleted);
}
逻辑说明:
  1. 若对话框未创建,则定义对话框样式:包含确定、应用、取消、帮助按钮,并启用网格布局;
  2. 获取应用主窗口作为对话框父级窗口;
  3. 实例化点编辑对话框,并传入点对象接口指针;
  4. 注册窗口关闭消息回调,绑定至 CloseBox 方法;
  5. 执行对话框初始化构建;
  6. 显示对话框,返回命令执行完成状态。

命令选择器将焦点赋予当前命令时,就会触发 Activate 方法执行。触发场景包括:用户手动选中该命令,或是当前命令被共享命令置为非激活状态后重新获得焦点。

若编辑对话框尚未创建,Activate 会新建对话框、将其显示,并返回方法正常执行完成。
创建对话框时,会向对话框构造函数传入以下参数:
  1. 第一个参数:传入命令树结构中的父级对象。对话框的父级通常应为其他对话框,因此这里统一设置为框架主窗口。
  2. 第二个参数:传入对话框名称。
  3. 样式组合参数:组合样式标识,使对话框自带确定(OK)应用(Apply)、** 取消(Cancel)** 三个按钮。
    • 在 UNIX 系统下,会额外显示 ** 帮助(Help)** 按钮;
    • 在 Windows 系统下,则在标题栏显示问号帮助图标;
    • 同时指定对话框采用网格布局进行页面排版。
  4. 第四个参数:传入 CAAISysPoint 接口指针,用于操作目标点对象。
程序为对话框绑定了关闭消息回调,用于监听用户关闭对话框的操作;同时调用对话框的 Build 方法,完成界面控件的初始化与布局填充。
对话框构造函数仅负责申请内存、创建对象,不加载资源文件中的文本、字段内容

原因是:构造阶段资源文件可能尚未完成加载。界面赋值、文本填充等初始化逻辑统一交由 Build 方法实现,完成后即可正常显示对话框。更多细节可参考「创建编辑对话框」章节。

其余方法实现与说明如下:

CATStatusChangeRC CAAAfrPointEditCmd::Desactivate(CATCommand      * iCmd,
                                                  CATNotification * iNotif)
{
  _DialogPoint->SetVisibility(CATDlgHide);
  return (CATStatusChangeRCCompleted);
}

CATStatusChangeRC CAAAfrPointEditCmd::Cancel(CATCommand      * iCmd,
                                             CATNotification * iNotif)
{
  _DialogPoint->SetVisibility(CATDlgHide);
  RequestDelayedDestruction();  
  return (CATStatusChangeRCCompleted);
}

void CAAAfrPointEditCmd::CloseBox(CATCommand           * iSendingCommand,
                                  CATNotification      * iSentNotification,
                                  CATCommandClientData   iUsefulData)
{
  _DialogPoint->SetVisibility(CATDlgHide);
  RequestDelayedDestruction();
}

方法功能说明

  1. Desactivate(停用)
    当命令选择器收回当前命令焦点时调用,常见于被共享命令抢占焦点的场景。该命令会保留在命令栈中,待共享命令执行完毕后可重新恢复焦点。方法仅隐藏对话框,不销毁任何资源,避免命令停用期间用户误操作;保留资源以便后续重新获取焦点时快速恢复对话框。
  2. Cancel(取消)
    当命令永久失去焦点、需要销毁时触发,一般在用户切换至其他独占式命令时调用。该方法隐藏对话框,并申请延迟销毁当前编辑命令。
  3. CloseBox(关闭窗口)
    用户点击确定、取消按钮,或直接关闭对话框窗口时触发。功能逻辑与 Cancel 一致,但它是对话框消息回调触发,而非由命令选择器主动调用。RequestDelayedDestruction 用于通知命令选择器释放当前命令焦点,系统会自动切换并激活默认命令(通常为选择命令)。

析构函数由 RequestDelayedDestruction 触发执行,会先移除对话框绑定的消息回调,再申请销毁对话框对象:

CAAAfrPointEditCmd::~CAAAfrPointEditCmd()
{
  if (_DialogPoint)
  {
    RemoveAnalyseNotificationCB(_DialogPoint,
                                _DialogPoint->GetWindCloseNotification(),
                                NULL);
    _DialogPoint->RequestDelayedDestruction();
  }
}

创建编辑对话框

编辑命令所对应的对话框,是通过 CATIEdit 接口实现类的 Activate 方法创建生成的。

该对话框高度依赖待编辑对象本身,其设计与编码方式和普通对话框完全一致:采用空构造函数,并依靠 Build 方法完成界面构建。以下为 CAASysPoint 类对应的编辑对话框实现说明:

 

图片

 

该编辑对话框包含三个数值微调控件,用于显示并修改点的 X、Y、Z 坐标。
  • 确定(OK) 按钮:应用新参数并关闭对话框;
  • 应用(Apply) 按钮:仅保存修改参数,对话框保持打开;
  • 取消(Cancel) 按钮:关闭窗口,还原坐标初始值。
CAAAfrPointEditDlg 类继承自 CATDlgDialog 类,该类是所有对话框的基类。其构造函数接收一个 CAAISysPoint 接口指针。该接口是点对象所实现的核心接口,借助此指针,程序可以读取对象参数以初始化对话框,也能在用户点击确定应用按钮时修改对象数据。
Build 方法负责创建界面控件、完成对话框布局,同时从资源文件读取文本标签、或通过 CAAISysPoint 接口读取数值并完成界面赋值。
该方法还会为确定、应用、取消按钮以及窗口关闭事件分别注册回调函数,依次对应:ClickOKClickApplyClickCancelCloseBox
下文将依次讲解各类按钮回调、窗口关闭方法,以及 ModifyModelAndVisu 方法 —— 该方法用于修改文档数据并刷新视图显示。

确定按钮回调 — ClickOK

void CAAAfrPointEditDlg::ClickOK(CATCommand * iSendingCommmand,
                                 CATNotification * iSentNotification,
                                 CATCommandClientData UsefulData)
{
  ModifyModelAndVisu(_XSpinner->GetCurrentValue(),
                     _YSpinner->GetCurrentValue(),
                     _ZSpinner->GetCurrentValue());
  CloseBox();
}

用户点击确定按钮时触发该方法。首先调用 ModifyModelAndVisu,读取三个坐标微调框的当前值,完成点坐标修改与视图刷新;随后调用 CloseBox 方法,执行对话框关闭逻辑。

应用按钮回调 — ClickApply

void CAAAfrPointEditDlg::ClickApply(CATCommand * iSendingCommmand,
                                    CATNotification * iSentNotification,
                                    CATCommandClientData UsefulData)
{
  ModifyModelAndVisu(_XSpinner->GetCurrentValue(),
                     _YSpinner->GetCurrentValue(),
                     _ZSpinner->GetCurrentValue());
}

用户点击应用按钮时触发。功能与确定按钮一致:更新点坐标并刷新显示,但不会关闭对话框,界面保持打开状态。

取消按钮回调 — ClickCancel

void CAAAfrPointEditDlg::ClickCancel(CATCommand * iSendingCommmand,
                                     CATNotification * iSentNotification,
                                     CATCommandClientData UsefulData)
{
  ModifyModelAndVisu(_Xfirst,_Yfirst,_Zfirst);
  CloseBox();
}

用户点击取消按钮时触发。读取保存的初始 X/Y/Z 坐标,还原点原始数据并刷新视图,最后关闭对话框。

窗口关闭回调 — ClickClose

void CAAAfrPointEditDlg::ClickClose(CATCommand * iSendingCommmand,
                                    CATNotification * iSentNotification,
                                    CATCommandClientData UsefulData)
{
  CloseBox();
}

用户点击窗口关闭按钮时执行,直接调用 CloseBox 完成关闭流程。

窗口关闭核心方法 — CloseBox

 

void CAAAfrPointEditDlg::CloseBox()
{
  SetVisibility(CATDlgHide);

  RemoveAnalyseNotificationCB(this, this->GetDiaOKNotification(),NULL);
  RemoveAnalyseNotificationCB(this, this->GetDiaAPPLYNotification(),NULL);
  RemoveAnalyseNotificationCB(this, this->GetDiaCANCELNotification(),NULL);
  RemoveAnalyseNotificationCB(this, this->GetWindCloseNotification(),NULL);

  SendNotification(GetFather(),CATDlgDialog::GetWindCloseNotification());
}

该方法首先隐藏对话框,再逐一移除确定、应用、取消、窗口关闭的消息回调,避免内存泄漏与消息残留。随后向父级窗口发送窗口关闭通知。该父窗口在对话框构造时被指定为程序框架主窗口。关闭通知会沿着命令树向上传递,直至匹配到注册了对应回调的命令。由于上层通常无匹配命令,通知最终会送达命令选择器,并转发至当前激活的编辑命令,触发其绑定的关闭回调方法。

模型与视图更新方法 — ModifyModelAndVisu

void CAAAfrPointEditDlg::ModifyModelAndVisu(const float iX, const float iY, const float iZ)
{
  _pPointEdit->SetCoord(iX, iY, iZ);

  CATIModelEvents * pModelEvents = NULL;
  HRESULT rc = _pPointEdit -> QueryInterface(IID_CATIModelEvents, (void**)&pModelEvents);
  if (SUCCEEDED(rc))
  {
    CATModify * pNotif = new CATModify(pModelEvents);
    pModelEvents->Dispatch(*pNotif);
    delete pNotif;
    pModelEvents->Release();
  } 
}
该方法用于修改文档中的点对象,并发送模型变更通知,驱动界面实时刷新。
  1. 调用 SetCoord 写入新的 X、Y、Z 坐标;
  2. 查询模型事件接口 CATIModelEvents
  3. 构造模型修改事件并分发通知,通知框架数据已变更;
  4. 释放临时资源与接口指针,保证内存安全。

简要总结

只要对象实现了 CATIEdit 接口的 Activate 方法,当选择命令处于激活状态时,用户双击该对象图形,或通过对象右键菜单,即可弹出编辑对话框对对象进行编辑。
随后,对象编辑命令会被激活。该命令必须以独占模式创建,确保命令选择器能够正确管控命令的可用状态与生命周期。

专属编辑对话框的开发方式与普通对话框完全一致:通过各类控件绑定的回调函数,调用对象自身接口修改业务数据;同时向可视化管理器分发更新通知,刷新对象的图形显示。

posted @ 2026-04-29 10:33  Breadss  阅读(12)  评论(0)    收藏  举报