济南友泉软件有限公司

SALOME是一套开源跨平台的CAE集成开发平台,包含全参数化建模、后处理可视化、求解器集成、分析优化等模块。而SUIT(SALOME User Interface Toolkit)则提供了整个GUI开发的基础。

Ref. from SALOME GUI Architecture

SALOME GUI module or SUIT (SALOME User Interface Toolkit) represents a user interface framework for SALOME platform. It reflects the last trends of the GUI developments and best practices of the software development. SUIT is developed as a set of packages implementing reusable software components, allowing building multi-scale CAD applications. With SUIT it is possible both to implement new CAD applications (completely independent from SALOME itself) and develop and integrate fully SALOME-compliant modules - “light-weight” (without any CORBA connection, also called “light”) and “full-scale” (distributed, CORBA-based), using C++ or Python programming languages.

Among other important features SUIT proposes flexible, powerful and safe mechanisms of interaction with other SALOME modules (both distributed and “light”), resources management, viewers and selection handling, exception/signals processing, bringing to the top the multi desktop dockable-windowed user interface which improves usability of SALOME GUI.

本模块涉及的主要技术要点包括:

  • Layered Architecture
  • MVVM Architecture
  • GoF' Command Pattern
  • Data Object Model
  • Plug-in System

关于上述技术要点,可参见笔者博文:大型CAx(CAD/CAE/CAM)工业软件开发中的关键组件

鉴于SALOME GUI模块是整个SALOME的一个基础模块,宜作为研究的切入点。同时考虑到SALOME GUI模块功能特点与独立性,本文拟主窗口、视图、菜单、工具栏等CAx软件界面组件方面探讨SALOME GUI模块实现的原理。

注1:限于笔者研究水平,难免有表述不当,欢迎批评指正。

注2:博文会不定期更新,敬请关注。

一、整体流程

suitexe是SALOM提供的加载不同应用的一个启动器,默认会加载LightApp。对应代码为gui/src/SUITApp/SUITApp.cxx。

// gui/src/SUITApp/SUITApp.cxx//............int main( int argc, char* argv[] )
{//............if ( args.empty() )args << "LightApp"; // fallback application library//............// Create sessionSession session( iniFormat );// Initialize and start application supplied by the library specified via the parameterSUIT_Application* sessionApp = session.startApplication( appName );if ( sessionApp ){
#ifdef USE_SALOME_STYLEStyle_Salome::initialize( session->resourceMgr() );if ( session->resourceMgr()->booleanValue( "Style", "use_salome_style", true ) )Style_Salome::apply();
#endif // USE_SALOME_STYLEif ( !debugExceptions )app.setHandler( session.handler() );if ( splash )splash->finish( sessionApp->desktop() );return app.exec();}return 1;
}

SUIT_Session用于根据用户输入参数appName创建不同的应用对象,实际上就是加载不同的动态链接库,并通过调用动态链接库内的createApplication()来生成应用程序对象。

从上图可以看出,SUIT_Application是所用应用对象的基类,应用对象定义文档类型(SUIT_Application::myStudy)、主窗口(SUIT_Application::myDesktop)、公用菜单与公用工具栏(SUIT_Application::myActionMap)、视图(STD_Application::myViewMgrs)等组件。

注:主窗口菜单、工具栏主要来自两部分,一部分是由SUIT_Application::myActionMap所定义菜单与工具栏;另一部分是来自CAM_Module::myActionMap

Ref. from gui/src/SUIT/SUIT_Application.h

An Application is a class which defines application configuration and behaviour. For example Application object defines what Viewers are used in this application, what auxilliary windows are present, how user can dial with them. Also Application object defines an sertain type of data structure by holding of pointer on an instance of SUIT_Study class (which represents Document data structure). In other words Application defines type of sata structure, type of used Viewers, type of main GUI widget (Desktop), and other auxilliary tools.

二、主要组件

2.1 SUIT_Session

SUIT_Session实际上可以看作整个程序的启动器,根据指定的动态链接库名称,调用动态链接库内的createApplication()来创建不同的SUIT_Application对象,进而通过虚函数SUIT_Application::start()来完成主窗口创建、模块加载等启动工作。

Ref. from SUIT_Session.h

The class Sesssion manages launching of Applications. Application must be returned by static function "createApplication" in external library. The Library must be loaded with loadLibrary method and after that application can be started.

2.2 CAM_Application

SUIT_Application用于窗口SUIT_Application::myDesktop与文档对象SUIT_Application::myStudy等的管理。

在SALOME中,主窗口菜单、工具栏等界面组件主要来自两部分:一部分是共用菜单与工具栏,这部分实际上是存储在SUIT_Application::myActionMap;另一部分是与当前模块相关的菜单、工具栏,这部分存储在CAM_Module::myActionMap。

STD_Application(派生于SUIT_Application)定义了文件打开、文件保存等共用菜单栏、工具栏,同时提供了视图管理功能。

CAM_Application(派生于STD_Application)主要提供了功能模块CAM_Module加载与管理的功能。

2.3 数据对象模型

SUIT_Study实际上就是文档对象,用于组织树状结构的数据对象SUIT_DataObject。另外,SUIT_Study提供了基于事务的文档修改的接口。

CAM_Study(派生于SUIT_Study)提供了对CAM_DataObject(派生于SUIT_DataObject)的支持。

2.4 主窗口

SUIT_Desktop定义了菜单管理器SUIT_Desktop::myMenuMgr与工具栏管理器SUIT_Desktop::myToolMgr。根据QAction的编排顺序,菜单管理器myMenuMgr与myToolMgr用于将QAction添加到菜单与工具栏。

/*!\class SUIT_DesktopProvides standard desktop: main window withmain menu manager, toolbars manager and logo.
*/
class SUIT_EXPORT SUIT_Desktop : public QtxMainWindow
{Q_OBJECTclass ReparentEvent;enum { Reparent = QEvent::User };public:SUIT_Desktop();virtual ~SUIT_Desktop();QtxActionMenuMgr*        menuMgr() const;QtxActionToolMgr*        toolMgr() const;QtxLogoMgr*              logoMgr() const;virtual SUIT_ViewWindow* activeWindow() const = 0;virtual void setActiveWindow(SUIT_ViewWindow*);virtual QList<SUIT_ViewWindow*> windows() const = 0;int                      logoCount() const;void                     logoClear();void                     logoRemove( const QString& );void                     logoInsert( const QString&, QMovie*, const int = -1 );void                     logoInsert( const QString&, const QPixmap&, const int = -1 );void                     emitActivated();void                     emitMessage( const QString& );signals:void                     activated();void                     deactivated();
//  void                     moved();void                     windowActivated( SUIT_ViewWindow* );void                     closing( SUIT_Desktop*, QCloseEvent* );void                     message( const QString& );protected:virtual bool             event( QEvent* );virtual void             customEvent( QEvent* );virtual void             closeEvent( QCloseEvent* );virtual void             childEvent( QChildEvent* );virtual void             addWindow( QWidget* ) = 0;private:QtxActionMenuMgr*        myMenuMgr;QtxActionToolMgr*        myToolMgr;QtxLogoMgr*              myLogoMgr;
};

另外,在STD模块中,派生了STD_SDIDesktop、STD_MDIDesktop、STD_TabDesktop等三种主窗口,STD_Application与CAM_Application默认使用STD_MDIDesktop类型主窗口(参见STD_Application构造函数)。

2.5 视图

2.6 CAM_Module

CAM_Module不仅定义了一组菜单、工具栏等界面元素,而且维护了模块相关的对象数据结构。

/*!\class CAM_Module\brief Base implementation of the module in the CAM application architecture.Provides support of menu/toolbars management.
*/
class CAM_EXPORT CAM_Module : public QObject
{Q_OBJECTpublic:CAM_Module();CAM_Module( const QString& );virtual ~CAM_Module();virtual void           initialize( CAM_Application* );QString                name() const;QString                moduleName() const;virtual QPixmap        moduleIcon() const;virtual QString        iconName() const;CAM_DataModel*         dataModel() const;CAM_Application*       application() const;virtual void           contextMenuPopup( const QString&, QMenu*, QString& ) {};virtual void           updateCommandsStatus() {};virtual void           putInfo( const QString&, const int = -1 );int                    showNotification(const QString& message, const QString& title, int timeout = -1);void                   hideNotification(const QString& message);void                   hideNotification(int id);bool                   isActiveModule() const;virtual void           setMenuShown( const bool );void                   setMenuShown( QAction*, const bool );void                   setMenuShown( const int, const bool );virtual void           setToolShown( const bool );void                   setToolShown( QAction*, const bool );void                   setToolShown( const int, const bool );virtual void           updateModuleVisibilityState();virtual bool           activateOperation( int actionId );virtual bool           activateOperation( const QString& actionId );virtual bool           activateOperation( const QString& actionId, const QString& pluginName );// actions/menu/toolbars managementQtxActionMenuMgr*      menuMgr() const;QtxActionToolMgr*      toolMgr() const;virtual QAction*       action( const int ) const;virtual int            actionId( const QAction* ) const;virtual QAction*       createAction( const int, const QString&, const QIcon&, const QString&,const QString&, const int, QObject* = 0,const bool = false, QObject* = 0, const char* = 0, const QString& = QString() );virtual QAction*       createAction( const int, const QString&, const QIcon&, const QString&,const QString&, const QKeySequence&, QObject* = 0,const bool = false, QObject* = 0, const char* = 0, const QString& = QString() );QtxActionGroup*        createActionGroup( const int, const bool = true );int                    createTool( const QString&, const QString& = QString() );int                    createTool( const int, const int, const int = -1 );int                    createTool( const int, const QString&, const int = -1 );int                    createTool( QAction*, const int, const int = -1, const int = -1 );int                    createTool( QAction*, const QString&, const int = -1, const int = -1 );void                   clearTool( const QString& title );int                    createMenu( const QString&, const int, const int = -1, const int = -1, const int = -1,QMenu * = 0);int                    createMenu( const QString&, const QString&, const int = -1, const int = -1, const int = -1 );int                    createMenu( const int, const int, const int = -1, const int = -1 );int                    createMenu( const int, const QString&, const int = -1, const int = -1 );int                    createMenu( QAction*, const int, const int = -1, const int = -1, const int = -1 );int                    createMenu( QAction*, const QString&, const int = -1, const int = -1, const int = -1 );static QAction*        separator();public slots:virtual bool           activateModule( SUIT_Study* );virtual bool           deactivateModule( SUIT_Study* );virtual void           connectToStudy( CAM_Study* );virtual void           studyClosed( SUIT_Study* );virtual void           studyChanged( SUIT_Study*, SUIT_Study* );virtual void           onApplicationClosed( SUIT_Application* );private slots:void                   onInfoChanged( QString );protected: virtual bool           isSelectionCompatible();virtual CAM_DataModel* createDataModel();void                   setName( const QString& );virtual void           setModuleName( const QString& );int                    registerAction( const int, QAction* );bool                   unregisterAction( const int );bool                   unregisterAction( QAction* );// IMN 05/03/2015: we copied myActionMap for reset/unset actions accelerator keys// after activate/deactivate modulesQMap<QAction*, QKeySequence> myActionShortcutMap; //!< copy actions shortcut mapvirtual bool           abortAllOperations();private:CAM_Application*       myApp;             //!< parent application objectQString                myName;            //!< module title (user name)QPixmap                myIcon;            //!< module iconQString                myInfo;            //!< latest info messageCAM_DataModel*         myDataModel;       //!< data modelQMap<int, QAction*>    myActionMap;       //!< menu actionsbool                   myMenuShown;       //!< menu shown flagbool                   myToolShown;       //!< tool shown flagfriend class CAM_Application;
};

通过重写CAM_Module::initialize()函数可以将创建的QAction对象添加到CAM_Module::myActionMap,同时将其注册到主窗口SUIT_Desktop的菜单管理器SUIT_Desktop::myMenuMgr与工具栏管理器SUIT_Desktop::myToolMgr,进而将这些QAction对象添加到主窗口。

CAM_DataModel实现了树状层次结构的数据对象模型,每个CAM_Module将创建的CAM_DataObject添加到CAM_DataModel::myDataModel。

三、总结与讨论

按照研究问题的顺序,笔者抛出以下问题供大家分析与讨论。

Q1. 试分析SALOME启动器的工作原理与优缺点。

Q2. 总结CAM_Application及其子类的创建过程?

Q3. Module是何时加载的?

A3. 在CAM_Application创建时读取module列表,SUIT_Session::startApplication()会调用CAM_Application::start(),进而调用CAM_Application::loadModules()加载各个模块。

Q4. 在GUI模块中,toolbar、menu等何时创建与更新?

整个界面的toolbar、menu等界面元素来自两部分:

Q5. toolbar与menu是如何出发命令响应的?

Q6. 命令Redo/Undo是如何实现的?

Q7. 每个module都有一个数据对象模型,其与study对象关系是怎样的?

Q8. ViewManager是何时创建的,怎样添加不同的Viewer?

参考文献

Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides. Design Patterns:elements of reusable object-oriented software. Addison Wesley, 1994.

Martin Fowler. Patterns of Enterprise Application Architecture.  Addison Wesley, 2002.

网络资料

SALOMEhttps://www.salome-platform.org/

SALOME GUI Architecturehttps://docs.salome-platform.org/latest/extra/SALOME_GUI_Architecture.pdf

GUI Architectures https://martinfowler.com/eaaDev/uiArchs.html

大型CAx(CAD/CAE/CAM)工业软件开发中的关键组件 https://blog.csdn.net/qq_26221775/article/details/123193318?spm=1001.2014.3001.5501

SALOME源码分析:GUI模块相关推荐

  1. koa源码分析-co模块以及thunk

    Thunk以及CO模块 co4.0之前都是返回的thunk函数 之后的都是返回promise thunk thunk:在 JavaScript 语言中,Thunk 函数替换的是将多参数函数,替换成单参 ...

  2. Python3.5源码分析-sys模块及site模块导入

    Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的sys模块初始化 根据分析完成builtins ...

  3. nginx源码分析之模块初始化

    在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...

  4. Fabric源码分析-共识模块

    正好这些天要有一个需求要帮客户魔改Fabric-v0.6,把一些hyperchain的高级特性移植过去,借此机会把之前看过的源码在梳理一下. 下面就是对Fabric共识模块的源码分析和梳理,代码都是以 ...

  5. [Abp vNext 源码分析] - 2. 模块系统的变化

    一.简要说明 本篇文章主要分析 Abp vNext 当中的模块系统,从类型构造层面上来看,Abp vNext 当中不再只是单纯的通过 AbpModuleManager 来管理其他的模块,它现在则是 I ...

  6. Canal源码分析deployer模块

    canal有两种使用方式:1.独立部署 2.内嵌到应用中. deployer模块主要用于独立部署canal server.关于这两种方式的区别,请参见server模块源码分析.deployer模块源码 ...

  7. 5章 性能平台GodEye源码分析-第三方模块

    5. 第三方模块 5.1 Crash(XCrash) Crash监控崩溃后的堆栈上传,作者采用接入爱奇艺的XCrash框架 源码分析 1.启动Crash的监控 Crash的监控通过反射启动XCrash ...

  8. WebRTC源码分析——Call模块

    目录 1. 引言 2. Call对象的创建 2.1 创建CallFactory对象 2.2 创建Call对象 2.2.1 PeerConnection.CreateCall_w 2.2.2 CallF ...

  9. Zepto源码分析-event模块

    源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT l ...

最新文章

  1. java 1%10_Java 操作符与运算符详解
  2. webuploader 怎么在react中_另辟蹊径搭建阅读React源码调试环境支持所有React版本细分文件断点调试...
  3. python关键字匹配_python通过BF算法实现关键词匹配的方法
  4. 网站301重定向 解决方法
  5. 马化腾:5G技术可以影响甚至重构整个互联网服务形态
  6. Android 音频开发(一) 基础入门篇
  7. ural 1297 O(nlogn) 后缀数组求最长回文字串
  8. 计算机专业挂职锻炼,计算机学院挂职体验谈
  9. 视频分析服务器作用,如何选择合适的视频分析解决方案?
  10. easyUI_rowdata
  11. 主题:小菜一碟可以怎样说
  12. html5库存管理,库存管理的基本方法
  13. 深度学习检测视频马赛克
  14. python复杂网络分析库networkx
  15. 针对PVS方式的VDI部署趋势杀毒优化方法
  16. Linux下Oracle11G64位安装流程
  17. ps-ef命令linux,【Linux】- ps -ef |grep 命令
  18. 移动端适配时对meta name=“viewport“ content=“width=device-width,initial-scale=1.0“的理解
  19. 联想7400pro打印有横黑道
  20. Flightmare: A Flexible Quadrotor Simulator 无人机仿真器

热门文章

  1. 使用EF配合Linq语句进行查询
  2. 作者年份 soft computing参考文献格式要求,LaTeX实现
  3. python 笔记6:格式化时间缩写
  4. 解析 Java 类和对象的初始化过程
  5. Eclipse/MyEclipse转IntelliJ IDEA完全攻略
  6. NO.65——人工智能学习:python实现广度优先搜索
  7. node+express 搭建商城项目(2-建立 Mysql链接 完成注册账号接口)
  8. 网站统计IP PV UV实现原理
  9. 判断南红价值,“红“的等级是关键
  10. 最新咸鱼数据采集工具