本帖最后由 天工开发者团队 于 2024-10-17 15:32 编辑
一、整体框架
通过向导(天工CAD开发资源)得到一个天工CAD插件项目之后,可以得到上述几个核心类,分别有着以下作用。
TGCore:程序初始化入口
TGUIManager:Ribbon菜单UI管理类,负责创建Ribbon菜单
TGCmdManager:Cmd命令管理类,负责命令的注册和分发调度以及对话框的管理
TGEventManager:Event事件管理类,负责响应操作所产生事件的处理
TGHelper:Help类,可以调用一些辅助接口
二、业务流程
业务流程可以分成三部分:
(一)创建Ribbon菜单:用户根据UI设计菜单,并完成Ribbon命令菜单的创建。
(二)实现业务功能:实现菜单命令,具体包括命令创建、功能实现、命令调度、消息事件处理、命令注册。
(三)处理消息事件:处理命令响应、文档事件等情况。
2.1 创建Ribbon菜单
打开“当前项目//res//XXXRibbon.xml”文件,对Ribbon菜单进行编辑,具体格式如下:
- <ribbon>
- <!-- [TGTemple]在此处添加用户自定义的TabbedContainer -->
- <tab name="天工插件示例">
- <!-- [TGTemple]在此处添加用户自定义的group分组-->
- <group name="Welcome">
- <!-- [TGTemple]在此处添加用户自定义的命令按钮 -->
- <!-- [TGTemple]commandId: 自定义命令ID,必须唯一,用于标识命令 -->
- <!-- [TGTemple]label: 命令显示的名称 -->
- <!-- [TGTemple]imageId: 命令显示的图标ID -->
- <!-- [TGTemple]buttonStyle: 命令按钮的样式 -->
- <button commandId="0" label="弹出窗口" imageId="166" buttonStyle="5" />
- <button commandId="1" label="侧边栏" imageId="167" buttonStyle="5" />
- <button commandId="2" label="弹窗消息事件版" imageId="167" buttonStyle="5" />
- <button commandId="3" label="侧边栏消息事件版" imageId="167" buttonStyle="5" />
- </group>
- </tab>
- </ribbon>
复制代码
界面效果图如下所示
命令按钮关键词说明:
commandId:自定义命令ID(唯一)
label:命令显示的名称
imageId:按钮位图资源ID
buttonStyle:按钮风格
“1” seButtonAutomatic:按钮样式自动确定,即UI框架会根据上下文和平台偏好自动选择合适的样式
“2” seButtonCaption:只有按钮的文字标题,没有图标
“3” seButtonIcon:只有按钮图标,没有文字标题
“4” seButtonIconAndCaption:包括按钮图标和文字标题(通常并排显示)
“5” seButtonIconAndCaptionBelow:与“4”类似,但图标位于上方,标题位于下方
“6” seCheckButton:复选按钮,用户可以选中或取消选中
“7” seCheckButtonAndIcon:结合复选按钮和图标的样式,更直观
“8” seRadionButton:单选按钮,用户在一组中选择其中一个
根据UI设计的Menu,创建Ribbon菜单,将所有的命令按钮添加完毕,对应好命令ID,以及按钮要展示的命令名称和图标,并根据需求进行命令分组,菜单创建完成后就可以进行命令的实现了。
2.2 业务功能实现
业务的实现体现为命令按钮的功能实现,具体步骤:命令创建→功能实现→命令调度→事件处理→命令注册。代码逻辑流程如下图所示。
其中,创建的业务命令类型主要可分为以下三种:
弹框式命令(继承自TGCmdPopup) :基于TGCCmdBase的二次封装,支持弹窗对话框形式的业务命令
命令激活处理接口:Activate() 命令终止处理接口:
Terminate() 创建并展示对话框:CreateRibbon()
消息事件处理:MouseClick()、KeyDown()、MouseDrag()、MouseMove()、Filter()等
侧边栏命令(继承自TGCmdEdgebar) :基于TGCCmdBase的二次封装,支持侧边栏形式的业务命令
命令激活处理接口:Activate()
命令终止处理接口:Terminate()
创建并展示侧边栏对话框:CreateRibbon()
消息事件处理:MouseClick()、KeyDown()、MouseDrag()、MouseMove()等
直接操作命令(继承自TGCCmdBase)
命令激活处理接口:Activate()
命令终止处理接口:Terminate()
消息事件处理:raw_MouseDown()、raw_MouseUp()、raw_MouseMove()、raw_MouseClick(、raw_MouseDblClick()、raw_MouseDrag()、raw_Filter()、raw_WindowProc()等)
接下来,以弹框式界面命令实现为例子进行讲解
2.2.1 命令创建
(一)基于TGCmdPopup定义自己的命令类,如TGUserCmdPopup
(二)定义命令Com的别名:typedef ComObject TGCmdUserCmdPopupObj
(三)实现Activate和Terminate接口(若无多余操作,可不重写)
(四)添加需要处理的消息事件
- class TGUserCmdPopup : public TGCmdPopup
- {
- public:
- TGUserCmdPopup();
- virtual ~TGUserCmdPopup();
- STDMETHODIMP Activate();
- STDMETHODIMP Terminate();
- STDMETHODIMP MouseClick(short sButton, short sShift, double dX, double dY, double dZ, LPDISPATCH pWindowDispatch, long lKeyPointType, LPDISPATCH pGraphicDispatch);
- STDMETHODIMP MouseMove(short sButton, short sShift, double dX, double dY, double dZ, LPDISPATCH pWindowDispatch, long lKeyPointType, LPDISPATCH pGraphicDispatch);
- STDMETHOD(MouseDrag)(short sButton, short sShift, double dX, double dY, double dZ, LPDISPATCH pWindowDispatch, short DragState, long lKeyPointType, LPDISPATCH pGraphicDispatch);
- STDMETHODIMP Filter(LPDISPATCH pGraphicDispatch, VARIANT_BOOL* vbValid);
- STDMETHOD(KeyDown)(short* KeyCode,short Shift);
- };
- typedef CComObject<TGUserCmdPopup> TGCmdUserCmdPopupObj;
复制代码
2.2.2 对话框创建
(一)基于CDialogEx,新建MFC类,如TGPopupDialog
(二)通过工具对话框的UI设计完成界面的布局
(三)完成业务逻辑处理
- class TGPopupDialog : public CDialogEx
- {
- DECLARE_DYNAMIC(TGPopupDialog)
- public:
- TGPopupDialog(CWnd* pParent = nullptr); // 标准构造函数
- virtual ~TGPopupDialog();
- // 对话框数据
- #ifdef AFX_DESIGN_TIME
- enum { IDD = IDD_POPUPDIALOG };
- #endif
- protected:
- virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
- DECLARE_MESSAGE_MAP()
- public:
- // 业务逻辑处理
- afx_msg void OnTestButton1();
- afx_msg void OnTestButton2();
- virtual void OnOK();
- virtual void OnCancel();
- };
复制代码
2.2.3 命令与对话框绑定
(一)修改TGCmdDialogFactory::GetSpecificCmdDialog():添加new TGPopupDialog对象的操作
- //[TGTemple]此处为用户自定义命令界面类实例生成工厂,请根据自定义command对应的界面实例补充switch
- CDialog* TGCmdDialogFactory::GetSpecificCmdDialog()
- {
- switch (CommandId)
- {
- case 0:
- {
- TGPopupDialog* pPopupDialog = new TGPopupDialog();
- return dynamic_cast<CDialog*>(pPopupDialog);
- break;
- }
- default:
- return NULL;
- break;
- }
- }
复制代码 (二)修改TGCmdDialogFactory::GetSpecificCmdDialogTemplateId():添加相应对话框IDD
- //[TGTemple]此处为用户自定义界面类ID关联command处,请根据commandid关联所对应的界面
- UINT TGCmdDialogFactory::GetSpecificCmdDialogTemplateId()
- {
- switch (CommandId)
- {
- case 0:
- return IDD_POPUPDIALOG;
- break;
- default:
- return NULL;
- break;
- }
- }
复制代码 2.2.4 消息事件处理
命令激活时,会涉及到一些消息事件的处理,可以在用户自定义的类中完成对这一部分的处理,比如鼠标事件,此处也可能会涉及到一些SDK的使用,可以参照SDK的帮助文档
- HRESULT TGUserCmdPopup::MouseClick(short sButton, short sShift, double dX, double dY, double dZ, LPDISPATCH pWindowDispatch, long lKeyPointType, LPDISPATCH pGraphicDispatch)
- {
- HRESULT hr = NOERROR;
- AfxMessageBox(L"MouseClick");
- return hr;
- }
复制代码 在弹框界面中也一样,鼠标点击Button1,实现弹出"Click Button1"的功能
- void TGPopupDialog::OnTestButton1()
- {
- AfxMessageBox(L"Click Button1");
- }
复制代码
鼠标点击确认,实现销毁窗口并终止命令的功能
- void TGPopupDialog::OnOK()
- {
- TGAddinTemplate2App::GetApplication()->AbortCommand(false);
- }
复制代码
2.2.5 命令注册
在TGCmdMnager命令管理类中完成命令的注册
- //[TGTemple]此处为用户自定义命令实例化与实例化自定义命令和CommandID关联处
- //[TGTemple]1.请实例化自定义界面实例
- //[TGTemple]2.请将实例化自定义界面与关联的CommandID放入Map容器
- void TGCmdManager::InitCommandMap()
- {
- //声明并创建命令的Com对象,并完成引用计数
- TGCmdPopupObj* PopupCommand = NULL;
- TGCmdPopupObj::CreateInstance(&PopupCommand);
- PopupCommand->AddRef();
- //插入命令集合中
- InsertCommand(0, PopupCommand);//该命令ID(0)要求唯一,且需要和Ribbon菜单中的ID保持一致
- }
复制代码
如需要多个弹窗式命令按钮,重复上述操作即可。
2.3 事务管理
2.3.1 命令管理的消息事件
这类事件是在对应的派生类命令中进行处理的,可通过补充这些事件的处理方法来完成。
鼠标事件:
sButton:鼠标按键,表示那个哪个鼠标按钮被按下。通常,1表示左键,2表示右键,4表示中间键
sShift:按下鼠标时哪些Shift键(1)、Ctrl键(2)或Alt键(4)被按下。
dX, dY, dZ:分别表示鼠标在X、Y、Z轴上的位置
pWindowDispatch:指向触发事件的窗口对象的指针。这可以用来访问窗口对象的方法和属性。
lKeyPointType:表示关键点类型,可能用于识别特定的交互点类型
pGraphicDispatch:指向图形对象的指针,可以用来访问与绘图或图形相关的服务和操作
- // 鼠标点击事件
- STDMETHOD(MouseClick)(short sButton,short sShift,double dX,double dY,double dZ,LPDISPATCH pWindowDispatch,long lKeyPointType,LPDISPATCH pGraphicDispatch)
- { }
- // 鼠标双击事件
- STDMETHOD(MouseDblClick)(short sButton,short sShift,double dX,double dY,double dZ,LPDISPATCH pWindowDispatch,long lKeyPointType,LPDISPATCH pGraphicDispatch)
- { }
- // 鼠标拖拽事件
- STDMETHOD(MouseDrag)(short sButton,short sShift,double dX,double dY,double dZ,LPDISPATCH pWindowDispatch,long lKeyPointType,LPDISPATCH pGraphicDispatch)
- { }
- // 鼠标按下事件
- STDMETHOD(MouseDown)(short sButton,short sShift,double dX,double dY,double dZ,LPDISPATCH pWindowDispatch,long lKeyPointType,LPDISPATCH pGraphicDispatch)
- { }
- // 鼠标弹起事件
- STDMETHOD(MouseUp)(short sButton,short sShift,double dX,double dY,double dZ,LPDISPATCH pWindowDispatch,long lKeyPointType,LPDISPATCH pGraphicDispatch)
- { }
- // 鼠标移动事件
- STDMETHOD(MouseClick)(short sButton,short sShift,double dX,double dY,double dZ,LPDISPATCH pWindowDispatch,long lKeyPointType,LPDISPATCH pGraphicDispatch)
- { }
复制代码 键盘事件:
KeyAscii:当用户按下键盘上的一个键时,对应的ASCII**被传递给KeyAscii
KeyCode:表示用户释放的虚拟键码。虚拟键码是一个整数,代表了键盘上的一个键
Shift:表示在释放按键时哪些键(Shift=1、Ctrl=2、Alt=4)被按下
- // 键盘按键事件
- STDMETHOD(KeyPress) (short* KeyAscii){ }
- // 键盘按下事件
- STDMETHOD(KeyDown)(short* KeyCode,short Shift){ }
- // 键盘弹起事件
- STDMETHOD(KeyUp)(short* KeyCode,short Shift){ }
复制代码
2.3.2 EventManage管理的消息事件
这类事件是在TGEventManager管理类中对应的事件实现里去补充。
命令事件:
基于不同版本会有不同的事件类负责处理,如XAddInEvents、XAddInEventsEx、XAddInEventsEx2。
nCmdID:绑定的命令标识符,即命令ID。
hFrameWnd:应用程序主框架窗口的句柄。
uHelpCommand:请求帮助的类型或命令。
- // 相应UI界面中的命令事件,比如菜单按钮的点击
- STDMETHOD(raw_OnCommand)(long nCmdID){}
- // 相应UI界面中的帮助命令事件
- STDMETHOD(raw_OnCommandHelp)(long hFrameWnd,long uHelpCommand,long nCmdID){}
复制代码
侧边栏事件:
theDocument:指向文档对象的指针。
EnvironmentCatID:表示一个环境类别ID,用于分类或描述页面展示环境的一个字符串标识符。
vbIsPageDisplayable:传出参数,表示页面是否在给定的环境类别下可以显示。
- // 添加侧边栏
- STDMETHOD(raw_AddPage)(LPDISPATCH theDocument){}
- // 删除侧边栏
- STDMETHOD(raw_RemovePage)(LPDISPATCH theDocument){}
- // 用于判断一个页面是否可以在特定环境下显示
- STDMETHOD(raw_IsPageDisplayable)(IDispatch* theDocument,BSTR EnvironmentCatID,VARIANT_BOOL* vbIsPageDisplayable);
- { }
复制代码 文档事件:
- // 激活文档切换事件
- STDMETHOD(raw_AfterActiveDocumentChange) (LPDISPATCH theDocument){}
- // 命令运行之后的事件,命令执行完之后,无论成功失败都会触发该事件
- STDMETHOD(raw_AfterCommandRun) (long theCommandID){}
- // 文档打开之后的事件
- STDMETHOD(raw_AfterDocumentOpen) (LPDISPATCH theDocument){}
- // 文档保存完成后的事件处理
- STDMETHOD(raw_AfterDocumentSave) (LPDISPATCH theDocument){}
- // 新建文档并打开后的事件处理
- STDMETHOD(raw_AfterNewDocumentOpen) (LPDISPATCH theDocument){}
- // 命令激活之前的事件
- STDMETHOD(raw_BeforeCommandRun) (long theCommandID){}
- // 文档关闭之前的事件
- STDMETHOD(raw_BeforeDocumentClose) (LPDISPATCH theDocument){}
- // 文档保存之前的操作
- STDMETHOD(raw_BeforeDocumentSave) (LPDISPATCH theDocument){}
复制代码
|