Creating an Interruptible Task-使用 CATIProgressTask、CATIProgressTaskUI 与 CATTaskController

摘要

本文介绍如何创建可中断任务并搭配进度指示器。

本示例教程学习要点

CAAAfrProgressTask 示例程序

  • 程序功能说明
  • 程序运行方式
  • 源码文件位置

操作步骤

内容小结

参考资料

本用例学习内容
部分任务执行耗时较长,此时搭配进度展示界面会十分实用。同时,赋予终端用户终止任务的权限也很有必要。本文将介绍如何通过达索组件实现进度展示与任务控制功能。你需要完成以下操作:

  •     实现 CATIProgressTask 接口以执行业务任务,并借助 CATIProgressTaskUI 接口管控交互界面;
  •     调用 CATTaskController 类来启动任务。

CAAAfrProgressTask 示例
CAAAfrProgressTask 是 CAAApplicationFrame.edu 框架下的示例,用于演示应用框架的各项功能。

CAAAfrProgressTask 功能说明
本示例模拟一个耗时较长的执行流程。该任务共分为 50 个步骤,每个步骤都会执行以下代码:

for ( int j= 0 ; j<= 5000000 ; j++)
{
   double k = 24.25 * (double) j ;
}

流程进度由达索系统组件进行展示,该组件会弹出如下对话框:

图 1:用户界面

图片

 

该对话框包含四处可由开发者自定义的区域(图中红色框选部分):
  1. 对话框标题
  2. 左上角代表当前任务的图标
  3. 任务所处理对象的名称
  4. 进度条上方的说明文字
其余组成部分如下:
  •     三种进度展示形式
    •         进度条  
    •         任务已完成百分比
    •         剩余预估时间
  •     用于终止流程的取消按钮(该按钮为可选配置)

该任务通过交互式命令启动,此命令已添加至 CAAGeometry 文档的 CAA V5 几何分析工作台中。该命令命名为进度任务,分别设置在分析菜单栏与数学分析工具栏内。

图 2:数学分析工具栏

图片

 

该命令基于CATDlgDialog实现,对应的用户界面如下:
图 3:进度任务命令界面

图片

  •  勾选可中断任务单选按钮后,进度条对话框中将显示取消按钮(见图 1)。
  • 终端用户点击计算按钮,即可启动任务。

运行 CAAAfrProgressTask 示例
如需了解本示例的详细启动步骤,请查阅 CAAGeometry 示例 文档中「如何运行 CAAGeometry 示例」章节。具体操作流程如下:
启动 CATIA 软件,待程序加载完成后:

  1. 点击开始菜单,依次选择基础架构,再点击 CAA V5:几何分析。
  2. 启动进度任务命令,调出可中断任务对话框:
    • 方式一:在数学分析工具栏中点击对应按钮 
    • 方式二:打开分析菜单,选择进度任务
  1. 点击计算
    弹出计算对话框,此时无取消按钮,等待任务执行完毕。
  2. 在可中断任务对话框中勾选可中断任务选项。
  3. 点击计算
    弹出带有取消按钮的计算对话框,在任务结束前点击取消。
  4. 再次点击计算
    弹出带取消按钮的计算对话框,等待任务执行完毕。
  5. 点击可中断任务对话框中的关闭按钮。

查找 CAAAfrProgressTask 相关代码

CAAAfrProgressTask 示例程序仅包含一个文件,该文件位于CAAApplicationFrame.edu框架下的CAAAfrProgressTask.m模块中:
  • Windows 系统路径:安装根目录 \CAAApplicationFrame.edu\CAAAfrProgressTask.m\
  • Unix 系统路径:安装根目录 / CAAApplicationFrame.edu/CAAAfrProgressTask.m/
其中,安装根目录指 CAA 光盘文件的安装目录。

分步说明

CAAAfrProgressTask 包含两大逻辑步骤:
  1. 创建交互命令
  2. 实现 CATIProgressTask 接口

创建交互命令

该命令命名为 CAAAfrProgressTaskSampleCmd。本章节介绍以下内容:
  • 头文件
  • 源文件
  • 本地化资源文件

头文件

// 对话框框架
#include "CATDlgDialog.h"     // 用于继承 CATDlgDialog 类

// 对话框框架
class CATDlgCheckButton;
// 应用框架
class CATFrmEditor;

class CAAAfrProgressTaskSampleCmd : public CATDlgDialog
{
  ...
  DeclareResource(CAAAfrProgressTaskSampleCmd, CATDlgDialog);
 
public:
    // 构造函数
    CAAAfrProgressTaskSampleCmd();
    // 析构函数
    virtual ~CAAAfrProgressTaskSampleCmd();  

  ...

private:
    // 计算按钮点击响应函数
    void ClickCompute(CATCommand            *iPublishingCommand,
                    CATNotification         *iNotification,
                    CATCommandClientData     iUsefulData);
 
    // 关闭按钮点击响应函数
    void ClickClose(CATCommand              *iPublishingCommand,
                    CATNotification         *iNotification,
                    CATCommandClientData     iUsefulData);
                    
    // 编辑器关闭回调函数
    void EditorClose  (CATCallbackEvent  iEvent,
                           void             *iFrom,
                           CATNotification  *iNotification,
                           CATSubscriberData iData,
                           CATCallback       iCallBack );
                           
    // 拷贝构造函数(禁用)
    CAAAfrProgressTaskSampleCmd(const CAAAfrProgressTaskSampleCmd &iObjectToCopy);
    // 赋值运算符重载(禁用)
    CAAAfrProgressTaskSampleCmd & operator = (const CAAAfrProgressTaskSampleCmd &iObjectToCopy);

private:
    CATDlgCheckButton * _pInterruptTask;  // 任务中断复选框
    CATFrmEditor      * _pEditor;         // 编辑器指针
};

该头文件包含以下声明内容:

  1.     此类继承自 CATDlgDialog。
  2.     DeclareResource 宏用于指定:命令类 CAAAfrProgressTaskSampleCmd 的资源存放于 CAAAfrProgressTaskSampleCmd.CATNls 文件中。若 CATDlgDialog 类也配置了资源,两类资源会进行合并加载。
  3.     按照常规写法,该类定义了构造函数与析构函数。
  4.     拷贝构造函数和赋值运算符(=)被声明为私有成员,避免编译器将其默认为公有成员。
  5.     两个回调函数,分别用于响应用户点击计算和关闭按钮的操作。
  6.     回调函数 EditorClose 用于监听编辑器关闭事件。若指针 _pEditor 所指向的编辑器正是启动当前命令的编辑器,则终止该命令。
  7.     一个复选框控件。

源文件

    • 引入所需头文件
      // 版权所有 达索系统 2002
      // 本地框架
      #include "CAAAfrProgressTaskSampleCmd.h"

      // 对话框框架
      #include "CATDlgCheckButton.h"
      #include "CATDlgPushButton.h"
      #include "CATDlgGridConstraints.h"
      // 省略其他头文件

      // 应用框架
      #include "CATApplicationFrame.h"
      #include "CATFrmEditor.h"
      #include "CATTaskController.h"
      // 省略其他头文件

      // C++ 标准库
      #include "iostream.h"
      // 省略其他头文件

    • 命令注册
      该命令通过外部命令进行启动,相关代码如下:
      // 省略部分代码
      #include "CATCreateExternalObject.h"
      CATCreateClass(CAAAfrProgressTaskSampleCmd);
      // 省略部分代码
      CATCreateClass 宏的作用是支持通过类名对该命令类进行实例化。
    • 构造函数实现
      // 。。。
      CAAAfrProgressTaskSampleCmd::CAAAfrProgressTaskSampleCmd()
        : CATDlgDialog((CATApplicationFrame::GetFrame())->GetMainWindow(),
                       "CAAAfrProgressTaskSampleId",
                       CATDlgGridLayout | CATDlgWndBtnClose )
      {
        // 创建任务中断复选框,并设置网格布局约束
        _pInterruptTask = new CATDlgCheckButton(this, "InterruptId" );
        _pInterruptTask->SetGridConstraints(0,0,1,1,CATGRID_CENTER);      
       
        // 创建计算按钮,并设置网格布局约束
        CATDlgPushButton * pComputeButton   = NULL ;
        pComputeButton = new CATDlgPushButton(this, "ComputeButtonId" );
        pComputeButton->SetGridConstraints(1,0,1,1,CATGRID_CENTER);      
            
        // 为计算按钮绑定点击回调函数
        AddAnalyseNotificationCB(pComputeButton, pComputeButton->GetPushBActivateNotification(),
                      (CATCommandMethod)&CAAAfrProgressTaskSampleCmd::ClickCompute,
                                  NULL);
       
        // 绑定窗口关闭、对话框关闭事件的回调函数
        AddAnalyseNotificationCB(this, this->GetWindCloseNotification(),
                      (CATCommandMethod)&CAAAfrProgressTaskSampleCmd::ClickClose,
                                  NULL);
        AddAnalyseNotificationCB(this, this->GetDiaCLOSENotification(),
                      (CATCommandMethod)&CAAAfrProgressTaskSampleCmd::ClickClose,
                                  NULL);

        // 获取当前编辑器实例
        _pEditor = CATFrmEditor::GetCurrentEditor();
        if ( (NULL != _pEditor) && (NULL != CATFrmLayout::GetCurrentLayout()) )
        {
           // 注册编辑器关闭事件的回调
           ::AddCallback(this,
                      CATFrmLayout::GetCurrentLayout(),
                      CATFrmEditor::EDITOR_CLOSE_ENDED(),
                      (CATSubscriberMethod)&CAAAfrProgressTaskSampleCmd::EditorClose,
                      NULL);
        }
       
        // 显示当前对话框
        SetVisibility(CATDlgShow);
      }
      // 。。。
应用程序主窗口是该对话框的父窗口。对话框样式设置为 CATDlgGridLayout(网格布局),便于精准排布内部控件;同时启用 CATDlgWndBtnClose 样式,仅在对话框底部显示一个关闭按钮。
该对话框包含两个控件:
  • 复选框,由指针 _pInterruptTask 管理,供用户设置任务是否允许被中断。
  • 普通按钮,由指针 pComputeButton 管理,用于启动任务。

当用户执行以下操作时,会触发 ClickClose 回调方法:

  • 点击对话框关闭按钮:触发 GetDiaCLOSENotification 通知。
  • 点击窗口关闭(Windows 系统为窗口右上角叉号,Unix 系统为在标题栏点击鼠标右键):触发 GetWindCloseNotification 通知。

最后,我们注册回调函数以监听编辑器关闭事件。该通知由当前布局对象(会话期间为单例对象)发出。

  • 析构函数相关说明

在析构函数代码中,无需释放通过本命令创建的对话框对象,对话框管理进程会自动完成该对象的销毁,但强烈建议将成员数据指针置空(NULL)
CAAAfrProgressTaskSampleCmd::~CAAAfrProgressTaskSampleCmd()
{
   _pInterruptTask   = NULL ;
   
   if ( (NULL != _pEditor) && ( NULL != CATFrmLayout::GetCurrentLayout()) )
   {
      ::RemoveSubscriberCallbacks(this,CATFrmLayout::GetCurrentLayout());
   }

   _pEditor = NULL ;
}
构造函数里注册的回调函数必须执行注销操作;但若析构是由编辑器关闭接口(EditorClose)触发时除外,该场景下注销逻辑已提前执行完毕。
  • ClickCompute 方法:
void CAAAfrProgressTaskSampleCmd::ClickCompute (   CATCommand          * iPublishingCommand,
                                              CATNotification     * iNotification,
                                              CATCommandClientData  iUsefulData)
{
  CATTaskController  Task ;

  CATIProgressTask * pIProgressTask = NULL ;
  HRESULT rc = QueryInterface(IID_CATIProgressTask,(void**)& pIProgressTask);

  if ( SUCCEEDED(rc) && (NULL != _pInterruptTask ) )
  {
      if ( CATDlgCheck == _pInterruptTask->GetState() )
      {
         Task.Schedule(pIProgressTask,TRUE,NULL);
      }else
      {
         Task.Schedule(pIProgressTask,FALSE,NULL);
      }

      pIProgressTask->Release();
      pIProgressTask = NULL ;
  }
}
最终用户点击了计算(Compute)按钮,此时必须启动对应任务。该功能可通过CATTaskController(应用程序框架)实现。
Schedule 方法会启动一个命令,该命令会弹出带进度条的对话框(见图 1)。
此方法的参数依次为:
  1. CATIProgressTask 接口指针,由 pIProgressTask 引用。在当前场景中,命令类自身实现了该接口,因此对自身执行接口查询(QueryInterface)操作。
  2. 布尔值,用于标识是否显示取消(Cancel)按钮。本场景中,_pInterruptTask 复选框的状态存储了用户的选择。
  3. 作为 PerformTask 方法输入数据的参数(此处为 NULL)。
  • ClickClose 方法:

void CAAAfrProgressTaskSampleCmd::ClickClose(CATCommand           * iPublishingCommand,
                                          CATNotification      * iNotification,
                                          CATCommandClientData   iUsefulData)
{
  SetVisibility(CATDlgHide);
                         
  RequestDelayedDestruction();
}

RequestDelayedDestruction 用于销毁当前命令对象。

  • EditorClose 方法:

void CAAAfrProgressTaskSampleCmd::EditorClose(CATCallbackEvent  iEvent,
                                              void            * iFrom,
                                              CATNotification * iNotification,
                                              CATSubscriberData iClientData,
                                              CATCallback       iCallBack )
{
  if ( _pEditor == iFrom )
   {
   
      // 取消本类所有订阅消息回调
      ::RemoveSubscriberCallbacks(this,CATFrmLayout::GetCurrentLayout());

      // 自销毁命令对象
      RequestDelayedDestruction();

      _pEditor = NULL ;
   }
}

当编辑器关闭(即对应文档被关闭)时,布局管理器会发送通知消息,消息发布源为该编辑器;入参iFrom指向即将关闭的编辑器。倘若该编辑器与启动当前命令的编辑器是同一个实例,则需要销毁本命令对象。

  1. NLS 资源文件:

CAAAfrProgressTaskSampleCmd.CATNls 文件存放路径为:CAAApplicationFrame.edu/Cnext/resources/msgcatalog,文件内容说明如下:
  • 对话框标题与内嵌控件标题配置:
Title                ="Interruptible Task" 
ComputeButtonId.Title="Compute" ;
InterruptId.Title    ="Interruptible Task" ;
...
  • 鼠标悬停在对话框上时,状态栏显示的帮助提示信息:
...
Help = "Dialog box which creates an interruptible task ";
...
  • 点击问号图标选中对话框控件时,气泡弹窗展示的详细帮助信息:
...
InterruptId.LongHelp     ="Check if the task is interruptible or not" ;
ComputeButtonId.LongHelp ="Launch the task. It is interruptible if the previous
button is checked" ;
...
  • 鼠标悬浮在对话框控件上时,气泡弹窗显示的简短帮助信息:
...
InterruptId.ShortHelp     ="Check if the task is interruptible or not" ;
ComputeButtonId.ShortHelp ="Launch the task" ;
...
  • 鼠标悬停在对话框控件上时,状态栏所显示的帮助提示:
...
InterruptId.Help     ="Check if the task is interruptible or not" ;
ComputeButtonId.Help ="Launch the task" ;
...

实现 CATIProgressTask 接口

CAAAfrProgressTaskSampleCmd 类实现了 CATIProgressTask 接口,本节介绍具体实现步骤:
  1. 在头文件中声明 CATIProgressTask 接口的各个方法
  2. 在源文件中添加所需头文件包含
  3. 编写 PerformTask(任务执行)方法代码
  4. 编写 GetCatalogName(获取资源目录名)方法代码
  5. 编写 GetIcon(获取图标)方法代码
  6. 修改 CAAAfrProgressTaskSampleCmd.CATNls 多语言资源文件
  7. 将该命令声明为组件
  • 在头文件中声明 CATIProgressTask 接口的方法

class CATIProgressTaskUI ;

class CAAAfrProgressTaskSampleCmd : public CATDlgDialog
{
    ...      
 public :
 
    ...
    virtual HRESULT PerformTask    (CATIProgressTaskUI  * iUI, void * iUserData);
    
    virtual HRESULT GetCatalogName (CATString           * oCatalogName);

    virtual HRESULT GetIcon        (CATString           * oIcon) ;
    ...
}

以上便是 CATIProgressTask 接口 的三个接口函数。

  • 添加所需头文件:

// 对话框框架头文件
#include "CATMsgCatalog.h"

// 应用框架头文件
#include "CATIProgressTaskUI.h"

  • 编写 PerformTask 方法

HRESULT CAAAfrProgressTaskSampleCmd::PerformTask (CATIProgressTaskUI  * iUI, void * iUserData)
{
    if ( NULL == iUI ) return E_FAIL ;

    int min = 1 ;
    int max = 50 ;
    iUI->SetRange(min,max);
    
    for ( int i= min ; i <= max ; i++)
    {
        iUI->SetProgress(i);

        CATUnicodeString usMessage ;
        CATUnicodeString usParam[1] ;
        
        usParam[0].BuildFromNum(i);

        usMessage = CATMsgCatalog::BuildMessage("CAAAfrProgressTaskSampleCmd",
                                        "ProgressTaskUI.CommentRuntime",usParam,1,
                                        "Step ...");

        iUI->SetComment(usMessage);

        // 步骤耗时模拟开始
        for ( int j= 0 ; j<= 5000000 ; j++)
        {
            double k = 24.25 * (double) j ;
        }
        // 步骤耗时模拟结束

        CATBoolean interrupt ;
        if ( S_OK != iUI->IsInterrupted(&interrupt) || (TRUE == interrupt) )
        {
            return E_FAIL ;
        }
    }

    return S_OK ;
}

该方法用于执行任务,并向由CATIProgressTaskUI 接口管控的进度对话框输出信息(见图 1)。
任务正式启动前,需要通过SetRange方法设定进度区间范围。
任务每运行一步,都会更新对话框内容:
  • 进度条、预估剩余时间与完成百分比:由SetProgress方法实现刷新。
  • 进度条上方的说明文字:先用BuildMessage拼接多语言(NLS)文本,再通过SetComment更新显示内容。
本示例中提示文案为:第i步...,其中 i 代表当前步骤序号。
用户点击取消按钮即可终止任务:若用户点击取消键、或是界面未配置取消按钮,IsInterrupted方法返回TRUE;一旦任务被中断,本方法返回E_FAIL,进度对话框随之关闭。
  • 编写 GetCatalogName 方法
HRESULT CAAAfrProgressTaskSampleCmd::GetCatalogName (CATString * oCatalogName)
{
    if ( NULL == oCatalogName ) return E_FAIL ;

    *oCatalogName = CATString("CAAAfrProgressTaskSampleCmd");
    return S_OK ;
}
该方法用于返回NLS 资源文件名,该资源文件中存放界面标题、控件默认名称以及默认提示说明文字,详见后续小节《修改 NLS 资源文件》。
  • 编写 GetIcon 方法
HRESULT CAAAfrProgressTaskSampleCmd::GetIcon(CATString  * oIcon)
{
    if ( NULL == oIcon ) return E_FAIL ;

    *oIcon = CATString("I_CAAProgressClock");
    return S_OK ;
}
图标文件I_CAAProgressClock.bmp存放于 CAAApplicationFrame.edu 工程路径下:CNext/resources/graphic/icons/normal目录中。
  • 修改 CAAAfrProgressTaskSampleCmd.CATNls 资源文件

对话框内所有文本标识均以关键字 ProgressTaskUI: 作为前缀:
ProgressTaskUI.Title = "Computing...";
ProgressTaskUI.ObjectName = "Model";
ProgressTaskUI.Comment = "Step ..."; // 本示例未使用
本示例中仅 Title(标题)ObjectName(对象名称)生效。注释文案会在任务每一步动态变更,因此默认文本Step ...不会被调用。每一步的提示内容依靠CommentRuntime关键字拼接生成,占位参数用于填入当前步骤序号。
ProgressTaskUI.CommentRuntime = "第/p1步 ...";
  • 将命令声明为组件

实现接口的类对象必须定义为组件。

class CAAAfrProgressTaskSampleCmd : public CATDlgDialog
{
    CATDeclareClass;
    ...      
 public :      
...

 

CATDeclareClass宏用于声明:CAAAfrProgressTaskSampleCmd类隶属于组件。

CATImplementClass(CAAAfrProgressTaskSampleCmd, Implementation, CATCommand, CATNull);

 

CATImplementClass宏配合Implementation关键字,声明CAAAfrProgressTaskSampleCmd是组件主类,并基于 OM 机制继承自CATCommand

#include <TIE_CATIProgressTask.h>
TIE_CATIProgressTask(CAAAfrProgressTaskSampleCmd);

 

借助TIE_CATIProgressTask宏,标明CAAAfrProgressTaskSampleCmd类实现了CATIProgressTask接口。

 

接口字典文件CAAApplicationFrame.edu.dico存放在框架目录:CAAApplicationFrame.edu/CNext/code/dictionary,文件内添加如下配置行:
...
CAAAfrProgressTaskSampleCmd CATIProgressTask  libCAAAfrProgressTask
...

简要总结

本文介绍如何创建可中断且带进度指示的任务。承载任务的类需要实现CATIProgressTask接口,任务通过CATTaskController类实例启动运行。

 

posted @ 2026-05-29 17:10  Breadss  阅读(6)  评论(0)    收藏  举报