找回密码
 注册
Simdroid-非首页
查看: 1198|回复: 29

[其他] ANSYS Mechanical脚本编程

[复制链接]
发表于 2011-2-1 05:18:57 | 显示全部楼层 |阅读模式 来自 加拿大
本帖最后由 whatinrain 于 2011-2-1 21:19 编辑

1部分


by Matt Sutton


原文:
http://www.padtinc.com/blog/post/2010/11/10/ANSYS-Mechanical-Scripting-HOWTO-Part-1.aspx


背景
在过去的10多年,ANSYS把越来越多的功能逐步迁移到现在的ANSYS Mechaincal产品线上(以前的名字从DesignSpace到Workbench再到Workbench Simulation)。
如果在过去5年中使用过ANSYS你可能会知道Workbench这个平台,并有可能把它划定为相对于经典ANSYS,或MechanicalAPDL完全不同的平台。以下所列两个平台的特性是我和你们可能想到的:

Mechanical APDL 是:

1, 陈旧和笨重的外观。

2, 古怪但是功能强大。

3,  “
真正的分析师唯一使用的工具。
4, 强大的脚本功能。


ANSYS Mechanical 是:

1, 炫酷流行的用户界面。
2,
开箱即用的支持是分析超级容易使
3,
强大的网格和支持。
4,
不能编制脚本。

幸运的是每个版本的Mechanical APDLANSYS Mechanical之间功能差别越来越小,越来越多的真正的分析师正在转到ANSYS Mechanical来完成他们的仿真需求。
当然,两个产品之间的一个明显差别是脚本。Mechanical APDL核心就是脚本,实际上这也是我唯一用来和这个程序交互的,相信大多数人也是这么做的。ANSYS Mechanical 好像是看不透的黑箱,它就是做它该做的。幸运的是,这只是部分正确。事实上ANSYS Mechanical的背后非常巧妙地隐藏着脚本功能,说是隐藏是因为没有对应的文档,而且在我看来ANSYS公司准备继续保持这种方式。在过去几个月的时间里我非常地刻苦地探索ANSYS Mechanical的内部,所以我在这里向你展示一些有趣的发现。

解剖DesignSpace
为什么我要提起ANSYS Mechanical原来的名称 DesignSpace呢?你可以想象的到,开发人员不如市场那么灵活,所以ANSYS Mechanical中许多代码还是沿用原来代号DesignSpace,或DS。 如果每次有个好主意就改变一个产品的名字,并要求所有的开发者必须重写他们的代码以反映新的名称,你可以想像这将会发生兵变的。当然这不会发生。

那么,DS里面到底是什么样呢?我只能告诉它的架构是这样的:

外面这一层(又称坚不可摧的黑箱)是图形用户界面。显然,这是典型的用户用于和程序进行交互的。但是,图形用户界面本身不是一个静态编译的可执行代码。它更像一个解释器,每次ANSYS Mechanical启动的时候创建自己。
(您可能会问,自己,这就是为什么需要这么这么这么长的时间来启动吗?”,自己回答:也许...顺便说一句,我需要更多的咖啡。)因此,下一个合乎逻辑的问题是它怎么知道创建什么?”我很高兴你这么问,因为这是打开黑箱的其中一个钥匙。ANSYS Mechanical的图形用户界面的结构建立在一堆XML文件中。这样做很重要,原因是:
1, XML
只是文本,所以你不必查看看不懂的二进制。
2, XML
有结构,大脑喜欢结构。

我们现在知道图形用户界面的结构是由
XML文件来描述的。意思是说XML中的文本是与所有的菜单按钮相关联的。不管是工具栏,工具栏按钮或是菜单项,都在XML文件中以文本描述的。当然,如果图形用户接口不能和用户交互那就仅仅是一个图像,那么用户接口是怎样工作的呢?

我很高兴你这么问。ANSYS Mechanical用户界面交互部分主要是通过使用JavaScript来实现的。JavaScript是一种解释型脚本语言,流行于网络开发。它是基于文本的,也就是说,它不用编译。其工作方式是,几乎所有的ANSYS Mechanical的核心功能是由C + +代码库实现的,这些代码库用于实现如划分网格,虚拟拓扑,图像或几何选择,并提供一堆公共函数供JavaScript解释器调用,而ANSYS Mechanical中有内建的JavaScript解释器,这样代码库就和JavaScript紧密地结合在一起了。所以用户接口就是一堆JavaScript调用C+ +代码库。这个有点象Mechanical APDL,如命令ASBW隐藏了复杂的面和面的相交函数以及BREP(边界表示)的修补,而用户只需知道这个命令用于实现“用工作平面分割面”即可。同样,JavaScript可以调用函数来实现新的边界条件,改变网格控制或重新划分网格。

最后,这里是拼图的最后一块,在后续部分我们将以例子来说明。你应该还记得图形用户界面每次创建都是基于XML文件的。在XML文件中定义了JavaScript函数,当用户点击按钮或选择菜单项的时候调用,使得图像用户界面结构和动态用户交互之间建立了关联。这里是打开黑箱的方法:在XML文件中找到我们需要的图形用户界面对象,找到用户和这个对象交互时调用的JavaScript函数名,用这个函数名在安装目录中找到这个函数的实现代码。我们可以研究这个代码并找出它的作用。

请继续关注后续部分。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

1

查看全部评分

发表于 2011-2-1 10:49:47 | 显示全部楼层 来自 加拿大
Simdroid开发平台
1# whatinrain

作者的编程造诣不错
回复 不支持

使用道具 举报

 楼主| 发表于 2011-2-1 21:43:12 | 显示全部楼层 来自 加拿大
第2部分
by Matt Sutton     
http://www.padtinc.com/blog/post/2010/12/15/Workbench_Scripting_2.aspx
     
继续上次的...

在第一部分,我大致描述了ANSYS Mechanical的产品结构。如果你还没有看过建议你最好熟悉一下。有一件事情是,定制ANSYS Mechanical不适合胆怯的,但在同时,它也并非是不可能完成的任务,主要是有2个困难:
1.    ANSYS Mechanical不是设计成用于客户定制的,至少不是为最终用户。
2.    没有内部API(应用程序接口)文档,所以我们只能自己破译内部运行机制。

尽管如此,ANSYS Mechanical的体系结构是C + +编译的并和JavaScript通过COM(组件对象模型)接口捆绑在一起的功能块集合。这也就意味着,ANSYS Mechanical的大部分功能可以通过接口在脚本中调用。因此,即使ANSYS Mechanical可能不是显性地设计成脚本编程的,也没有内部文档,但我们发现脚本编程还是可能的,因为ANSYS软件开发人员遵循的是一个始终如一的模式,其内部结构是可以被第三方所理解的。

探索ANSYS Mechanical功能的方法

正如我在这篇文章中提到的,ANSYS开发人员有一套非常完善的软件开发方法来创建ANSYS Mechanical产品。这方法是:找到一个特定的模式来解决在最一般的情况下的问题。因此,让我们描述了ANSYS开发人员面临的问题,然后我们将描述我所认为的他们的解决方法。这个问题可以概括为:如何创建一个图形用户接口,在以后的版本中很容易扩展并能够包括现在还不知道的功能?That is the problem from 50,000 ft.这里是关于这个问题的更多细节:
•    可扩展意味着我(ANSYS的开发者),当随着时间的推移增加更多功能的时候,可能需要增加或减少菜单项、工具栏按钮、菜单组以及按钮组。我不希望每次添加一个按钮的时候都要重写很多底层代码。
•    我已经知道我们(ANSYS)在世界各地拥有讲不同语言的客户。我不希望维护10种不同的版本并给每一种语言以技术支持。如果我可以把语言独立于其它的代码那就好了。
•    当我根据需要添加按钮、菜单项时,我能够描述当用户按下按钮、选择菜单时会发生什么,我不想限制自己,所以这需要尽可能一般化。
所以,这就是问题所在,或许你已经想到了解决方案。下面是ANSYS开发人员所使用的构建灵活的图形用户界面的标准模式。
1.    在最后一分钟创建实际的图形用户界面。也就是说,不硬编码一个图形用户界面,而是硬编码一个图形用户界面的生成器。生成器在运行的时候读入描述图形用户界面的可读配置文本,并在每一次程序启动的时候动态创建图形用户界面。现在你所拥有的是一个可以根据需要动态改变界面的静态可执行文件。
2.    这是对第一条的推理。既然我们要在最后一分钟创建图形用户界面,我们必须能够用最一般化项来描述在运行时当用户按下一个按钮或选择一个菜单项时会发生什么。因此,我们需要一个动态脚本语言在运行时进行解释。请注意,这种语言的真正的唯一的目的是协调应用层的变化。底层细节,比如划分网格,已经在可编译语言中创建并包含在代码库中而且可以在脚本语言中调用。所以,因为第一条我们需要一个用于Mechanical的可编程接口。
3.    我们要把语言的差异,即英语,法语,德语等隔离到一个尽可能小的文件子集中。这个问题的最好的编程技术是“额外间接层“。也就是说,在代码中使用只是一个数字常量的标识符ID_File来表示菜单项”File", 而不是直接使用文字串“File”来描述。然后,我们构造一个字符串表来映射数字识别。所以,如果ID_File的数值是438,那么在字符串表会有一条记录438对应“File”。同样,在实际的图形用户界面的任何地方,如果我们需要字符串“File”,那么在代码中就用ID_File替代。现在,比如说,我们希望有一个法语版的ANSYS Mechanical,我们怎么办呢?我们只需简单地把字符串表翻译成法语并创建一个新的字符串表文件。在运行时,我们读入法语字符串表,这样我们就有法语版的ANSYS Mechanical了。

所以,这就是ANSYS开发人员用于创建易扩展图形用户界面的方法。对我们来说可以利用的是,通过脚本语言的引导,我们可以用回溯的方法来搞清楚ANSYS Mechanical的后台究竟是怎么回事。以下是在ANSYS Mechanical中如何找到功能实现的方法。

主要工具

1.    良好的文本搜索工具(我用的是SlickEdit。附加的好处是,它可以递归搜索整个目录)
2.    耐心

步骤

1.    在界面中找到所需的功能。
2.    在dsstringtable.xml文件中搜索菜单名或工具栏按钮的描述字符串。
3.    在字符串表中注意相应的ID_ ***字符串标识符。
4.    在dscontextmenu.xml或类似的界面结构文件中搜索字符串标识符ID_ ***。
5.    当找到标识符ID_ ***,请注意所列的与界面元素相关的回调函数名do***。
6.    在目录aisol或DesignSpace找到do***函数。
就这么简单?

例子

选中树中的某一项插入一个命令对象,最终用编程来实现。
第1步:在界面中找到功能所在
下图所示是在选中树中的某项插入命令时所显示的菜单。所以我们要查找的字符串是“Commands”

第2步:在dsstringtable.xml中搜索字符串“Commands”
要注意的是,字符串表文件位于language目录下。当前我们使用的字符串表位于Language\en-us\xml。当我们执行搜索,结果如下图所示:

第3步:注意字符串表中的对应ID_ ***
从上图可见与ID对应的命令是ID_CommandEditorDefaultName。看上去很有道理。

第4步:在dscontextmenu.xml 中搜索ID_CommandEditorDefaultName
要注意的是,前面已经提到,ANSYS Mechanical图形用户界面的结构是在一系列的XML文件中进行描述的。文件dscontextmenu.xml就是其中之一,令人震惊地描述了程序中不同的上下文菜单的布局方案。因此,查找字符串ID_CommandEditorDefaultName,看看下图所示找到的结果:

注意这个文件的结构,有不同的入口表示给定上下文菜单的各个菜单项。每个入口都有一系列的带有methodName属性的回调。通过推测我们可以假设,用户点击这个菜单项时,所列的JavaScript函数就会被调用来执行对应动作。你会注意到还有一项visibilityCallback,ANSYS的古怪的开发者考虑到了所有事情...
现在,有一个回调是“doPrototypeInsertCommandEditor”,如果这看上去不像一个函数用于插入一个命令编辑器的话,我都不知道还会像什么。让我们看看是否我们能够找到它。
第五步:在aisol或Designspace目录中搜索doPrototypeInsertCommandEditor
现在我们在javascript(.js)文件中搜索函数doPrototypeInsertCommandEditor(),在文件DSMenuScript.js中我们找到了这个函数的定义:

所以你知道吗,无论什么时候你在树中插入一个命令对象,就是这个21行的函数被调用。在下个贴子出来之前请花一些时间在这个代码上,你会发现一些ANSYS Mechanical架构的最基础部分。现在,你可能会想这很好呀,但是如果不仅仅是插入一个命令对象呢?如果要在这个命令对象中添加一些APDL呢?此外,所有这些变量到底是什么意思?怎样才能调用这该死的函数呢?

请继续关注...更多惊喜等着你。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2011-2-1 22:01:36 | 显示全部楼层 来自 浙江温州
这个东西在他们官方网站有看到,当时觉得真是太厉害 了,上面还有些例子,可惜看不太懂
如今希望借楼主翻译的能好好研究下!谢谢!
回复 不支持

使用道具 举报

发表于 2011-2-5 21:43:45 | 显示全部楼层 来自 广东深圳
确实是比较高深的东西!
回复 不支持

使用道具 举报

发表于 2011-2-10 03:33:44 | 显示全部楼层 来自 德国
学习了,haodongxi
回复 不支持

使用道具 举报

发表于 2011-2-10 17:09:23 | 显示全部楼层 来自 江苏无锡
第三篇出来了啊
回复 不支持

使用道具 举报

 楼主| 发表于 2011-2-22 04:52:21 | 显示全部楼层 来自 加拿大
ANSYS Mechanical脚本编程第3部分

by Matt Sutton
http://www.padtinc.com/blog/post/2011/01/06/ANSYS-Mechanical-Scripting-HOWTO-Part-3.aspx
继续上次的...
在本系列的第二部分,我们讨论了如何通过界面入口在ANSYS的源代码中找到功能实现。这个方法是我们工具箱中的第一个工具。在这篇文章中,我将介绍一些ANSYS Mechanical中与几何形状相关的内部数据结构,只是简单介绍,并不涉及到与这些数据结构相关的功能函数。在以后的文章中,我将一步步来介绍最给力的工具:Visual Studio Script Debugger。
ANSYS Mechanical中几何选择管理器和B - REP的几何数据结构
在计算机中几何模型是以边界表示(B-Rep)的数据结构来呈现的,计算机科学家喜欢把这类数据结构称为叫图形。一般来说,一个图形是由节点以及连接各个节点的弧组成的结构。地图就是一种图形,其中城市表示节点和道路表示连接的弧。像非死不可和LinkedIn这样的网站就是巨大的图形,里面的人是节点,朋友或熟人关系可以代表为弧。正如你所看到的,图形是相当普遍的,你可以用来描述很多结构化的关系。
在几何模型中,图形中的节点可以由不同的拓扑实体组成,如点,线,面,壳和体。这些实体之间的关系就是弧。举例来说,线有一个开始点和结束点。关系可以表示为特定线与开始点或结束点之间的连接。同样地,一个特定线的开始点可能是另一根线的结束点。因此,这种关系可以表示为一个给定点与所有相连线之间的连接。线和面之间也有类似的关系。一系列的线会形成一个给定面的边界,一系列的面可能共享同一根线。壳代表了由一堆相连接的面所定义的体积(即面共享线)。一个体由一个或更多的壳组成。为什么体和壳不一样吗?
事实证明,有内孔的体可以更方便地表示为两个或更多的壳的组成。一个壳代表外部形状,其他壳代表内部空隙。 那么怎么知道壳是内部还是外部呢?组成壳的面都有一个关联的外法线向量,方向指向体的外部。法线向量方向由给定面的边界顺序而定。通常当你遍历给定面的所有边界时实际上是反时针绕了面一圈(右手法则?)。使用这个假设,可以决定一个向外法线。
让我们讨论一下ANSYS Mechanical B-Rep的一些特性。首先,在Mechanical中每个B-Rep结构都是相关联的。其次,每个B-Rep中的实体(点、线、面和体)的都有一个独一无二的标识符(这个标识符也成为TopoID,或拓扑标识符),这个标识符是一个无符号整数, with one small twist。如果你有15零件你就有15个不同的B-Rep结构。标识符的前2位编码为实体的拓扑类型,也就是说,如果提取前2位,你会得到以下四个组合之一:

Top Two Bits 前两位     Decimal Value 十进制值     Topological Type 拓扑型
  1. 00     0     Vertex点
  2. 01     1    Edge线
  3. 10     2     Face面
  4. 11     3     Body体
复制代码

后面30位就编码成给定点、线、面或体的唯一标识符。也就是说ANSYS Mechanical中模型最多有约十亿的点、线等等...,如果模型多于这个数值,则需要简化。
要用B-Rep对象访问某个拓扑实体,可以用下面类似的函数调用。(注意,我还没有提到brep_object是怎么来的,耐心等待,我们很快就提到了。)
  1. var topo_object = brep_object.Cell(topo_id);
复制代码

Cell函数接受有效的topoID并返回关联的对象。返回的对象是一个富对象,取决于拓扑类型会有大量的明显不同的属性。比如说,线会有StartVertex和EndVertex两个属性用于关联特定的开始点和结束点。当然,所有拓扑对象都有一个共同的属性,那就是标识符属性ID。下面的代码就是获得和给定线关联的开始点的topolD:

  1. var brep_object = /*从某个地方或的B-Rep对象*/
  2. var edge_id = /* 从某个地方或的线的标识符 */
  3. var edge = brep_object.Cell(edge_id);
  4. var start_vertex_id = edge.StartVertex.Id;
复制代码


由此可以得到对应的开始点对象:
  1. var start_vertex = brep_object.Cell(start_vertex_id);
复制代码

现在,每个点对象都包含一个连接到这个点的所有线的列表。所以如果我们需要获得所有和起始线连接在一起的线,我们可以使用这个方法。
浏览B - REP数据结构也许很有趣的事,但对我们来说没有什么用处。我们需要的是能够选择几何的一部分或是一些几何。ANSYS Mechanical的选择管理器可以做到。这个对象和B - REP数据结构是密切相关的。在我们讨论这个对象的一些细节之前,可以用以下代码作为开始:
// 这个脚本对象是对嵌在Mechanical中的JavaScript引擎的调用。这个对象包含了定义在ANSYS
// Mechanical javascript文件中的所有函数。

  1. var SC = DS.Script;
复制代码


//  选中管理器对象是对ANSYS mechanical中几何选中工具的调用。这是一个复杂的对象,包含了对当
//  前几何实体选择集的调用,更重要的是包含了Mechanical BREP结构中实体标识符的指针。

  1. var SM = SC.sm;
复制代码

这段代码引入了两个全局变量。第一个对象是对内嵌在Mechanical中实际JavaScript引擎的引用。这个对象来自Mechanical 程序中最基本的DS对象,你可以把它想象为所有对象之母。ScriptCode或SC对象可以引用Mechanical产品中所有的JavaScript代码。所以如果你要使用在第2部分描述的技术找到一个特定的函数调用,实际上是通过这个对象来调用的。
例如,在第2部分我们找到函数doPrototypeInsertCommandEditor,在我们自己的脚本中是这样调用的:
  1. SC.doPrototypeInsertCommandEditor();
复制代码

第二个全局变量是选择管理器,或SM。你可以看到,这个对象是脚本代码对象的子对象。这个对象有众多的函数和属性,在以后的文章我希望尽我所能来描述。下面代码中的两个函数以及一些属性有助于理解SM这个对象,也可以了解在脚本中是如何调用的:
// Clear()  
// 这个函数用于复位选择管理器,当前没有几何被选中

  1. SM.Clear();
复制代码


// AddToSelection(partID, topoID, bShouldDraw)
// 这个函数用于添加特定的实体(点、线、面和体)到当前的选择集中。第一个参数指定
// 了与选中实体相关的零件,也可以认为是对BRep结构的引用,第二个参数指定了拓扑
// 标识符,最后一个参数是个布尔值,决定选择管理器是否要把选中几何以绿色高亮。

  1. SM.AddToSelection(partID, topoID, bShouldDraw);
复制代码


// Vertices
// 选中的点的数目
  1. var num_selected_vertices = SM.Vertices;
复制代码


// Edges
// 选中的线的数目
  1. var num_selected_edges = SM.Edges;
复制代码


// Faces
// 选中的面的数目
  1. var num_selected_faces = SM.Faces
复制代码


// Parts
// 选中的体的数目,
  1. var num_selected_bodies = SM.Parts
复制代码


// SelectedCount
// 所选实体的总数
  1. var num_selected = SM.SelectedCount;
复制代码


// SelectedEntityTopoID(i)
// 第i个选中实体的拓扑标识符。你可以用这个标识符的前2位来确定选中对象的类型,
// i的范围是从1到SelectedCount。
  1. var selected_topoid = SM.SelectedEntityTopoID(i);
复制代码


// SelectedPartID(i)
// 选中实体的零件标识符。一个模型有很多零件,这个函数告诉你选中的实体是属于哪个
// 零件的,可以用这个标识符来引用Brep结构。i的范围也是从1到SelectedCount。
  1. var selected_partid = SM.SelectedPartID(i);
复制代码


// 零件管理器对象是选择管理器的子对象,它有很多方法和属性,一个最有用的属性是
// PartById,用来返回和给定标识符对应的零件对象。
  1. var part = SM.PartMgr.PartById(partID);
复制代码


// 通过属性PartMgr.PartById来返回的零件对象与给定的Brep数据结构有关联,引用
// 这个Brep结构可以从选择管理器选中的实体标识符得到指定拓扑。例如,假设用户组
// 选中了模型上的一个面,使用下面代码来获得面对象。
  1. var topo_id = SM.SelectedEntityTopoID(1);
  2. var part_id = SM.SelectedPartID(1);
  3. var part = SM.PartMgr.PartById(part_id);
  4. var brep = part.BRep;
  5. var face = brep.Cell(topo_id);
复制代码


上面的代码表示了一小部分ANSYS Mechanical选择管理器的接口以及几何BRep结构。正如你可以看到,这两个结构通过两个标识符耦合在一起,一个是零件标识符,代表了指定Brep结构,另一个是实体标识符,代表了Brep结构中的某个实体。一旦给定的拓扑实体被识别并从BRep结构中返回,用户可以在Brep中浏览邻近拓扑实体的连接信息。通过选择管理器中函数Clear()和AddToSelection(),用户可以编程控制当前哪个拓扑实体被选中。

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2011-2-23 10:48:40 | 显示全部楼层 来自 四川成都
这个对深层次的运用AWE很有帮助,谢谢楼主。
回复 不支持

使用道具 举报

 楼主| 发表于 2011-8-7 05:19:22 | 显示全部楼层 来自 加拿大
本帖最后由 whatinrain 于 2011-8-7 05:22 编辑

ANSYS Mechanical脚本:HOWTO的第4部分
by Matt Sutton
http://www.padtinc.com/blog/post ... cripting_Part4.aspx

继续上一次的......
在本系列的第三部分中,介绍了ANSYS选择管理和几何BRep。
我们还创建了一个示例脚本,在一个选定的体上遍历所有的面并创建一个命名选择,其所用到的技术就是在第二部分中描述的。

介绍Microsoft Visual Studio脚本调试
在这篇文章中,将介绍微软Visual Studio脚本调试器。

在调试器下运行ANSYS Mechanical无疑是创建自定义脚本的最有力的工具。如果你能有效地使用这个工具,你就可以在精确控制的环境中查看Mechanical与你的脚本互动的内部运作。此外,强大的调试器显示可以让你在暂停的情况下查看绝大多数Mechanical对象,也可以让你实时查看这些对象的属性和方法。 最后,在Mechanical的调试状态,在调试器的即时窗口中可以执行输入的随机代码。 这将允许你在同一个调试会话中测试各种程序代码。
简而言之,你必须非常熟练使用调试器才有希望成功地在ANSYS Mechanical编制脚本。

一些准备
通过下面这些步骤来正确设置调试器环境:

   1. 显然,你需要安装Visual Studio。我使用Visual Studio专业版2010,但我想任何包括2005及以上的版本都可以的。我不确定Express版是否可以,所以如果有人有这方面的经验和一些启发,请发表评论。
   2. 在Internet Explorer的“Internet选项”对话框(菜单工具 - > Internet选项),你需要确保“Disable Script Debugging (Other)”没有被勾上。见下图。
   3. 最 后,需要调整注册表设置HKEY_CURRENT_USER\Software\Microsoft\Windows Script\Settings\JITDebug = 1。


调试代码
在调试器中暂停Mechanical运行的最简单的方法就是在你需要的地方插入javascript命令“debugger”。举例来说,我们有下面的脚本:
  1. function my_func() {
  2.   debugger;
  3.   var my_array = new Array();
  4.   for(var i = 0; i < 10; i++) {
  5.       my_array[i] = 2*i;
  6.   }
  7. }
  8. my_func();
复制代码
正如你可以看到的,这个简单的脚本有一个my_func函数用来填充数组。在这个函数中的第一条语句就是命令debugger。如果一切按计划进行,当我们执行这个脚本,我们将最终停留在微软调试器中。
为了让这一切顺利进行,你需要遵循以下10个步骤:

   1. 启动MS Visual Studio,
   2. 启动ANSYS Mechanical,
   3. 上面的脚本复制到一个文件名为debug_test.js的文件并保存在硬盘上,
   4. 在MS Visual Studio中,点击菜单Debug->Attach to Process…

   5. 在弹出的对话框中,在列表中找到AnsysWBU.exe,

   6. 选择AnsysWBU.exe,然后按“Attach”按 钮,
   7. 切换到ANSYS Mechanical,
   8. 从工具菜单,选择Tools->Run Macro…
   9. 找到保存的debug_test.js,并单击“open”,
  10. 开始调试...


这时候你可以在脚本中设置断点,单步跳入跳出函数,查询变量的值等...这个调试器是一个非常了不起用的工具,因为我们已经渐渐接触到了实质。

MS调试器的旋风之旅
下图是我们的脚本显示在Visual Studio调试器中,我们的小脚本的屏幕截图。

正如你可以看到,当前执行的就是 debugger语句。按F10往下运行一行。 此外,你会发现有在代码窗口下有一个窗口的标签是“Locals”,此选项卡显示的是这个函数中定义的局部地变量。在执行的当前点,这些变量还没有被定 义。不过,当我们一步步执行下去,这些变量将开始发挥作用。 当你执行过这些代码,你可以看到这些变量值的变化。另外你会注意到第二个名为“Immediate Window”的窗口。这个窗口在默认调试布局可能不可见。如果你看不到它,可以使用菜单 Debug->Windows->Immediate Window 来打开。

当应用程序停留在调试器中,在即时窗口中输入的代码会立即执行。举例来说,如果你在代码中看到一个问题,你可能停止调试去修改代码并重新运行。不过,如果你不确定你的修改是否正确,或是你想尝试一些其他的想法,你可以直接输入到即时窗口看看会发生什么。它的工作原理是在当前断点执行在即时窗口输入的新代码,而这些新代码还没有出现在已有的脚本中。你可以执行你的几行脚本,然后在即时窗口中输入的一些代码,然后继续就执行。这是一个非常强大的技术。
让我们执行几行代码,大概按F10 四到五次,然后得到了以下的画面。

你可以看到数组my_array边上出现了+号而且i等于1。如果点击my_array旁边的加号,在Locals窗口中可以得到如下图所示:

可以看到,在数组中第0项已经赋值为0。继续多按几次F10键...注意,你也可以将鼠标悬停在代码窗口中的数组上,可以看到有更多数组项被赋值了。
使用键盘上的print screen键可能没有办法很好捕捉到显示内容,但可以看到数组的值已经改变。

现在,比方说为了下 面的代码正常工作,数组的第五个值必须小于10。(其实下面没有任何代码,这很做作但请使用你的想象力多多包涵)所以,我只要在即时窗口中键入:
my_array [5] = 8;

当我按回车键时将执行这行代码。你可以看 到,my_array [5]现在值是8而不是10。

你也可以在代码中设置断点,在代码行点击右键在弹出菜单中选择 Breakpoint->Insert Breakpoint。

断点的工作有点像debugger命令,只是没有列在你的代码中。 通常,我在脚本的顶部插入debugger命令,然后在需要的地方设置断点。断点也可以是有条件的。也就是说,它们不会起断点作用除非某些条件为真。这个非常有用,尤其是在执行一个循环并需要最后一个或是最后第二个循环停止的时候。当插入一个断点后,只需右键选择菜单 Breakpoint->Condition…

您可以插入一个条件,如下图所示:

从这里,按F5运行命令,代码将执行内循环,直到i== 8。

小结
调试器是你的朋友,简单明了。明智地利用它,并经常用它。事实上,如果你想编写Mechanical脚本,你必须十分熟悉调试器。在以后的文章中,我将展示更强大的调试技巧如果调试器没有办法满足你的需求。敬请期待...

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

1

查看全部评分

回复 不支持

使用道具 举报

 楼主| 发表于 2011-8-14 13:08:17 | 显示全部楼层 来自 加拿大
本帖最后由 whatinrain 于 2011-8-14 13:12 编辑

使用JScript实现最大应力的精确定位

看来我不继续翻译,Matt Sutton的howto系列也没有继续更新, 。其实howto的第5部分早已经出来了,那是对前面4个部分综合应用的一个实例。翻译完howto第 4部分的时候也想找个例子实际检验一下,正好J版的帖子Mechanical中获取最大结果值节点坐标和编号的方法(http://forum.simwe.com/viewthread.php?tid=996929)出现了。要使用脚本编程来自动实现一些功能,要么是简单重复的功能,要么是复杂的需要多次鼠标点击键盘输入的才能实现,而J版要描述的方法正好符合第二种情况。

思路。
在J版的方法中,1,输入一个probe,2,在最大值的附近点取一个坐标(coordinate),3,snap to mesh nodes,4,选取要显示的结果类型,5,evaluate。

要用脚本JScript来代替用户输入,插入一个probe好办,选取一个坐标可能没有那么简单。仔细查看了在Mechanical中的操作过程,当点取工具栏上的坐标(Coordinate)然后选取的geometry,并不是vertex,不是很明白是什么类型,但是选取后在probe的 geometry中可以应用。Probe的location method中还有一个选项是coordinate system,而对于如何创建一个坐标系已经有代码了(http://forum.simwe.com/viewthread.php?tid=940832),那就准备用这个了。问题是原点坐标从哪里来?



第一个想法就是导出所有stress的数据,导出前确定一并导出节点号和节点坐标,然后在导出的文件中找出最大值。但是如果导出的文件中包含了很多节点数据,那光是查找出最大值就要花很多时间。


第二个想法是用*get等APDL的命令通过 restart来获得,这样也不用重新求解。问题是缺省情况下,restart control中retain files after full solve是为No的。也就是说如果求解完了,插入了APDL命令,然后想用restart的时候发现没有支持文件存在。直接的APDL不行,想到了 JPDL,用JScript封装的APDL命令,但怎么试都不行,连初始的对象都没有办法创建。于是寻求了一下技术支持,答曰早不支持JPDL了。不支持了为什么还封装在安装包里呀,浪费我硬盘呀,有木有!直接问技术支持如何用JScript来获得最大应力的节点号及坐标,此帖发布之时还没有回应。

于是非常纠结地回到了第一个想法。虽然有可能会在搜查最大应力数据的时候花很长时间,但终究也是一个解决方法。就准备用第一个想法了。

于是更新后的完整思路如下,
1,选定应力数据项,求解过的;
2,导出数据,不是excel file而是text file,方便计算机上没有安装excel的使用;
3,找到第一个最大应力值,返回节点号和节点坐标;
4,根据节点坐标创建坐标系,节点号可以成为新建坐标系的名称;
5,插入一个probe,并使用创建的坐标系;
6,evaluate。

编程。
这段程序断断续续写了一个星期,如果没有microsoft visual studio 2010(mvs)这个调试工具,完成的日期可能是遥遥无期。在AWB 11.0的时候有写过一些代码,但是这些代码在AWB 13.0中并不能顺利运行,通过mvs才知道很多对象、属性和方法都改变了。最不能令人忍受的是还没有文档,一切都是在摸黑中进行,mvs也只不过是一个手电筒而已。Matt Sutton的脚本编程howto系列前面4个部分,可以算是另外一个手电筒。有了两个手电筒,也勉强可以行走了。

1,在dsstringtable.xml中搜索Mechanical中工具栏或菜单项上字符串,并找到对应的ID。有时候会出现搜索的字符串出现在多个地方并有多个ID对应,如果不能准备判断就只能一个个查看了;
2,在dscontextmenu.xml中搜索ID,并找到对应的函数;
3,搜索函数出现的js文件并找到函数的定义,大多数函数出现在 DSMenuScript.js中;
4,函数的定义中会出现一些常量,大多数常量可以在DSConstants.js中找到;
5,最难搞定的是对象的获得和引用,这个需要mvs出马。在debugger状态下,可以在mvs中查看对象以及所属的属性和方法;
6,Detail of Probe中有个Location Method,正好Probe对象有个属性是LocationMethod,界面上有Result Selection,于是猜有个属性应该是ResultSelection,但是找不到,试着运行也不行,用mvs一看,对应的属性应该是 DisplayFilter,跟界面上的根本不一样;
7,代码已附,注释已加。

结果。
在类似于J版的模型上测试代码运行,运行速度很快(这么小的模型能不快吗,:lol ),结果也不错。
1,全自动后台处理,过程中无需用户输入;
2,最大值的出现的位置无论是表面还是内部都是无差别处理。



对于只是提供一个解决方法来说,到这里就可以收工了。而如果对于应用来说,可能还会有以下问题,
1,对于大模型最大值的搜索速度能满足吗?如果不行,修改算法或通过其他的方法获得最大值对应的节点信息?
2,和J版的snap to mesh nodes方法比,这个方法可能会有插值的问题,虽然是对应的坐标是一样的。曾惊鸿一瞥地看到通过代码得到的probe结果和通过的snap to mesh nodes得到的结果相差了0.001,而坐标是完全一样的。虽然后面测试再也没有看到这样的结果,但还是有这样的怀疑。



后记。
碰到同事有点小得意地说编了这么个程序可以自动得到结果,同事盯着我看了3秒说,这有什么用呢?当时就石化加凌乱了,一个星期呀,这让我情何以堪呀。
谨以我的第1000贴纪念我在simwe上的日日夜夜。
  1. // JScript source code

  2. //常量声明
  3. var id_kProbeStress                 = 1;
  4. var id_AnswerSet                    = 107;
  5. var id_COORDINATE_SYSTEM_SELECTION  = 1;
  6. var id_ShowMaxPrincipal             = 11;
  7. var id_ShowEquivalent               = 13;
  8. var id_EquivalentStress             = 1;
  9. var id_MaximumPrincipalStress       = 2;
  10. var ForReading                      = 1;
  11. var ForWriting                      = 2;
  12. var ForAppending                    = 8;
  13. var MBBID_IDNO                      = 7;
  14. var MBBID_IDCANCEL                  = 2;
  15. var id_Result                      = 520;

  16. InsertProbeStressWithCS();


  17. function InsertProbeStressWithCS()
  18. {
  19.     //debugger在正式运行的时候屏蔽,调试的时候打开
  20.     //debugger;
  21.     var probeResult = null;
  22.         var answerSetObj = null;
  23.         var stressObj=null;
  24.         var selObj=null;


  25.         //选择一个项,判断是不是结果,是Equivalent Stress还是Maximum Principal Stress
  26.         selObj=DS.Tree.FirstActiveObject;
  27.        
  28.         if (selObj.Class==id_Result)
  29.         {
  30.             if (!(selObj.ResultType==id_EquivalentStress||selObj.ResultType==id_MaximumPrincipalStress))
  31.             {
  32.                 WBScript.Out( "Please select one stress item.", true );
  33.                 return;
  34.             }
  35.         }
  36.         else
  37.         {
  38.             WBScript.Out( "Please select one stress item.", true );
  39.             return;
  40.         }
  41.        
  42.        
  43.         //弹出对话框提示选择输出节点位置
  44.         var Text="Please make sure the option of Export in Mechanical is YES\nfor include node number/node location.";
  45.     var Caption="Message";
  46.     var buttonType = 1; // Yes|No|Cancel;
  47.     buttonType += 32; // Icon Questionmark
  48.     var retVal = WBScript.Out(Text, true, Caption, buttonType, WB.hWnd);
  49.     if (retVal==MBBID_IDCANCEL)
  50.         return;
  51.        
  52.     //确定AnswerSet对象
  53.     answerSetObj = selObj.Parent;
  54.     //确定branch对象
  55.     var branchObj = DS.Tree.FirstActiveBranch;
  56.     //确定是否求解过
  57.     if (!selObj.IsSolved)
  58.         {
  59.             WBScript.Out("Please solve/evaluate the stress item first",true);
  60.         return;
  61.         }
  62.        
  63.         //查找最大应力值并返回对应节点信息
  64.         var maxStress=new Array(5);
  65.         maxStress = GetMaxResult(selObj);
  66.        
  67.     //没有找到最大应力值
  68.         if (maxStress[0]==0)
  69.         {
  70.             WBScript.Out("Cannot find node info of Max. Stress",true);
  71.             return;
  72.         }
  73.        
  74.         //使用返回的节点信息创建坐标系
  75.         var stressCS = CreateCoordinateSystem(branchObj, "Node" + maxStress[0], parseFloat(maxStress[1]), parseFloat(maxStress[2]), parseFloat(maxStress[3]));
  76.        
  77.         //插入一个stress probe
  78.         probeResult = answerSetObj.AddResultProbe(SM, id_kProbeStress);
  79.         if( !probeResult )
  80.         {
  81.                 WBScript.Out( "Can not Find Object", true );
  82.                 return;
  83.         }
  84.    
  85.     //清空选择管理器
  86.     SM.Clear();

  87.     //把probe的定位方法选择为坐标系
  88.         probeResult.LocationMethod=id_COORDINATE_SYSTEM_SELECTION;
  89.         //要使用坐标系的内部ID,而不是ansys的坐标系号码
  90.         probeResult.LocationCoordinateSystem = stressCS.ID;
  91.         //根据第一个所选的应力类型自动改变probe的结果类型,并修改对应名称
  92.         if (selObj.ResultType == id_EquivalentStress)
  93.     {
  94.             probeResult.DisplayFilter = id_ShowEquivalent;
  95.             probeResult.Name = "Equivalent Stress Probe @Node " + maxStress[0];
  96.         }
  97.         if (selObj.ResultType == id_MaximumPrincipalStress)
  98.     {
  99.         probeResult.DisplayFilter = id_ShowMaxPrincipal;
  100.         probeResult.Name = "Max. PrincipalStress Probe @Node " + maxStress[0];
  101.         }
  102.    
  103.     //evaluate
  104.         answerSetObj.FindAnswers();
  105.         //更新树
  106.         DS.Script.fillTree();
  107. }


  108. //在输出文件中查找最大应力值并返回对应节点信息
  109. function GetMaxResult(resObj)
  110. {
  111.     //给定一个文件名作为输出文件名
  112.     var fileName = "c:\\temp\\resulttoexcel.txt";
  113.     //导出所选结果项的数据   
  114.     var fileText = resObj.CreateTabbedFile(fileName);
  115.     //创建一个文件对象
  116.     var fso = new ActiveXObject("Scripting.FileSystemObject");
  117.     //创建一个文件
  118.     f = fso.CreateTextFile(fileName, true);
  119.     //写入文件
  120.     f.Write(fileText);
  121.     //关闭文件
  122.     f.Close();
  123.     //打开这个文件
  124.     f = fso.OpenTextFile(fileName, ForReading);
  125.     var tmpData = new Array(5);
  126.     var maxData = new Array(0,0,0,0,0);
  127.     var i=0;
  128.     var r;
  129.     //把第一行的抬头跳过去
  130.     f.SkipLine();
  131.     while (!f.AtEndOfStream)
  132.     {
  133.         r = f.ReadLine();
  134.         //通过制表符提取数据,\t是制表符,/\t/是正则表达式
  135.         tmpData = r.split(/\t/);
  136.         //把碰到的最大的数据记录下
  137.         if (parseFloat(tmpData[4]) > parseFloat(maxData[4]))
  138.         {
  139.             maxData = tmpData;
  140.         }
  141.     }
  142.     f.Close();
  143.     return maxData;   
  144. }

  145. //创建坐标
  146. function CreateCoordinateSystem(branchObj,csName,csX,csY,csZ)
  147. {

  148.     //获得CoordinateSystemGroup对象
  149.    var CurrentModels = branchObj.Model;
  150.    if (CurrentModels.CoordinateSystemGroup)
  151.       curCoorGroup = CurrentModels.CoordinateSystemGroup;
  152.    else
  153.       curCoorGroup = CurrentModels.AddCoordinateSystemGroup();

  154.    // 插入一个新坐标系
  155.    var currCoor = curCoorGroup.AddCoordinateSystem(SM);
  156.    //用节点号作为坐标系名
  157.    currCoor.Name = csName;
  158.    //原点
  159.    currCoor.OriginAlignment=0;
  160.    currCoor.OriginXLocation=csX;
  161.    currCoor.OriginYLocation=csY;
  162.    currCoor.OriginZLocation=csZ;
  163.    //cartesian system
  164.    currCoor.CoordinateSystemType = 0;
  165.    currCoor.AxisPriority = 0;
  166.    currCoor.PrimaryAxis = 1;
  167.    currCoor.SecondaryAxis = 2;
  168.    currCoor.PrimaryAxisAlignment = 2;
  169.    currCoor.SecondaryAxisAlignment = 3;

  170.    return currCoor;
  171. }   


复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

2

查看全部评分

回复 不支持

使用道具 举报

 楼主| 发表于 2012-3-2 02:40:32 | 显示全部楼层 来自 加拿大
本帖最后由 whatinrain 于 2012-3-2 02:58 编辑

在Mechanical中定制自己的按钮

在使用Ansys或自己编写的脚本的时候,每次都需要从菜单tools->run macro...进去,然后找到脚本所在的目录,如果藏的很深的话,要点很多下鼠标。所以提出一个问题,是否可以在Mechanical中添加自己的按钮,把所实现某个功能的脚本和这个按钮关联在一起,然后每次使用的时候只要点击这个按钮就可以了,从而实现懒人少点击几次鼠标按钮的想法,

在Ansys Workbench中一直可以添加自己的按钮(所谓客户定制),我所了解的至少从v11.0开始都是可以的。不过从v12.0开始Ansys Workbench的framework有了大的修改,所以添加自己的按钮的方法和v11.0不一样。v11.0中比较复杂,需要在注册表中注册顶定义按钮信息,需要使用代理(delegate)来却的工具栏对象,需要使用钩函数来注册功能函数。总之比较复杂,在这篇文章中略过不谈。

从v12.0开始,Ansys Workbench使用全新的framework,有很多对象是动态加载的,比如工具栏,这也是为什么启动Mechanical会变慢的原因之一。不过这也方便了我们来定制自己的按钮。最少只要3个文件就可以实现按钮定制,基本步骤是,
1,找到目录C:\Program Files\ANSYS Inc\v140\commonfiles\registry\winx64\append,
2,拷贝文件AbaqusSolverAddin.XML,并粘帖到同一个目录下,
3,修改这个模板文件,
4,创建一个按钮对象处理脚本,
5,创建一个按钮图像文件,
6,在Mechanical中加载测试。

这里是各个步骤的详细信息,
1, 这个应该没有问题,这里所显示的是缺省的安装目录,如果修改了安装目录的,请找到对应的目录。另外我现在所有的计算机都是64位的,所以32位的没有办法测试。或许可以用AbaqusSolverAddin.XML这个文件来找到对应的目录。

2,粘帖完后修改文件名,这个可以自由定义,系统不加控制的,Ansys Workbench在启动的时候会扫描这个目录下的所有xml文件来加载。

3,修改的时候最好能够使用支持xml格式的编辑器来打开,这样可以高亮语法而且也不会弄乱格式。如下面代码所示要修改的地方是高亮的一些字符串。
第8行,     v140 -- 这个后面再说,
第14行,   AbaqusSolverAddin -- 工具栏的名称,这个名称会出现在Mechanical中菜单tools->addins的窗口中,
第16行,   %AWP_ROOT140%\AISOL\WBAddins\AbaqusAddin -- 修改成存放按钮对象处理脚本的目录,因为我们用的类型是JScript,所以是双斜杠,
第19行,   AbaqusSolverAddIn.AbaqusAddin.140 -- 修改成脚本的文件名叫绝对路径,也是双斜杠,
第20行,   progid -- 修改成jscript,保留原来的双引号,
第21行,   <VALUE ObjectName="ResultFileType" Value="odb" ValueType="2"/> -- 这一行彻底删除。
  1. <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
  2. <KEYS>

  3.   <KEY ObjectName="SOFTWARE" RegObjectType="0">
  4.     <KEYS>
  5.       <KEY ObjectName="ANSYS, Inc." RegObjectType="0">
  6.         <KEYS>
  7.           <KEY ObjectName="v140" RegObjectType="0">
  8.             <KEYS>
  9.               <KEY ObjectName="APFramework" RegObjectType="0">
  10.                 <KEYS>
  11.                   <KEY ObjectName="AddIns" RegObjectType="0">
  12.                     <KEYS>
  13.                       <KEY ObjectName="AbaqusSolverAddin" RegObjectType="0">
  14.                         <VALUES>
  15.                           <VALUE ObjectName="InstallDir" Value="%AWP_ROOT140%\AISOL\WBAddins\AbaqusAddin" ValueType="2"/>
  16.                           <VALUE ObjectName="IsAddin" Value="true" ValueType="2"/>
  17.                           <VALUE ObjectName="LoadOnStartUp" Value="true" ValueType="2"/>
  18.                           <VALUE ObjectName="Location" Value="AbaqusSolverAddIn.AbaqusAddin.140" ValueType="2"/>
  19.                           <VALUE ObjectName="Type" Value="progid" ValueType="2"/>
  20.                           <VALUE ObjectName="ResultFileType" Value="odb" ValueType="2"/>
  21.                         </VALUES>
  22.                       </KEY>
  23.                     </KEYS>
  24.                   </KEY>
  25.                 </KEYS>
  26.               </KEY>
  27.             </KEYS>
  28.           </KEY>
  29.         </KEYS>
  30.       </KEY>
  31.     </KEYS>
  32.   </KEY>

  33. </KEYS>
复制代码
这是修改完后我的xml文件,
  1. <?xml version="1.0" encoding="UTF-8" standalone="no" ?>
  2. <KEYS>

  3.   <KEY ObjectName="SOFTWARE" RegObjectType="0">
  4.     <KEYS>
  5.       <KEY ObjectName="ANSYS, Inc." RegObjectType="0">
  6.         <KEYS>
  7.           <KEY ObjectName="v140" RegObjectType="0">
  8.             <KEYS>
  9.               <KEY ObjectName="APFramework" RegObjectType="0">
  10.                 <KEYS>
  11.                   <KEY ObjectName="AddIns" RegObjectType="0">
  12.                     <KEYS>
  13.                       <KEY ObjectName="myTestTool" RegObjectType="0">
  14.                         <VALUES>
  15.                           <VALUE ObjectName="InstallDir" Value="D:\\SIMWE\\WB\\myTool" ValueType="2"/>
  16.                           <VALUE ObjectName="IsAddin" Value="true" ValueType="2"/>
  17.                           <VALUE ObjectName="LoadOnStartUp" Value="true" ValueType="2"/>
  18.                           <VALUE ObjectName="Location" Value="D:\\SIMWE\\WB\\myTool\\myTool.js" ValueType="2"/>
  19.                           <VALUE ObjectName="Type" Value="jscript" ValueType="2"/>
  20.                         </VALUES>
  21.                       </KEY>
  22.                     </KEYS>
  23.                   </KEY>
  24.                 </KEYS>
  25.               </KEY>
  26.             </KEYS>
  27.           </KEY>
  28.         </KEYS>
  29.       </KEY>
  30.     </KEYS>
  31.   </KEY>

  32. </KEYS>
复制代码

4, 接下来就是创建按钮对象处理脚本,也是我的xml中提到的myTool.js,
  1. var g_oAddinMgr = null;
  2. var g_bDSAppletInitialized = false;
  3. var g_oContext = null;
  4. var g_oApplet = null;
  5. var g_menuBars = null;
  6. var g_toolBars = null;
  7. var g_oImageList = AnsObjectFactory.CreateDispatchObject("WBControls.WBImageList.140");
  8. var ds = null;
  9. var wb = null;

  10. var installDir = "D:\\SIMWE\\WB\\myTool"; //Addin installation directory

  11. function OnLoad(oAddinMgr)
  12. {
  13.     g_oAddinMgr = oAddinMgr;
  14.     g_oAddinMgr.OnContextChange.AddCOM(this, "OnContextChange");
  15. }

  16. function UnLoad()
  17. {
  18.     g_oAddinMgr.OnContextChange.RemoveCOM(this, "OnContextChange");
  19. }

  20. function OnContextChange(sender, args)
  21. {
  22.     g_oContext = args.Context;
  23.     if (g_oContext.Name == "WB.DSApplet")
  24.     {
  25.         if (!g_bDSAppletInitialized)
  26.         {

  27.             g_oApplet = g_oContext.Item("WB.Applet");
  28.             g_toolBars = g_oContext.Item("WB.Applet.ToolBars");
  29.             
  30.             // to avoid script error when duplicate or import
  31.             if (g_toolBars!=null)
  32.             {
  33.                 var imageDir = installDir + "\\images";  //to use images from this folder
  34.                 var macrotoolbar = g_toolBars.Add("MacroToolbar","");
  35.                 g_oImageList.Create();
  36.                 g_oImageList.Add(imageDir);
  37.                 macrotoolbar.ImageList = g_oImageList;
  38.                
  39.                 var buttons = macrotoolbar.Buttons;
  40.                 var button1 = buttons.AddButton(101,"Test Tool Button1",30001,"InsertAnswer",false,"Test Tool Button2","Test Tool Button3");
  41.                 // 4th argument to the function is the image name (without the extension)

  42. button1.OnClick.AddCOM( this, "button_OnClick"); //function call associated with the button
  43.                
  44.                 g_bDSAppletInitialized = true;
  45.             }
  46.         }
  47.     }
  48. }

  49. function button_OnClick()
  50. {
  51.     WBScript.Out("no no no", true, "Message");
  52. }
复制代码
代码中高亮的地方是可以修改的地方,
第7行,  140 -- 这个也是后面再说,
第11行,D:\\SIMWE\\WB\\myTool -- 这个目录必须和xml中的一样,
第38行,\\images -- 按钮图像文件所存的目录,
第45行,Test Tool Button1 -- 按钮名称,text on toolbar选中时显示按钮名称,不过这个代码没有显示好像是还要设置某个属性,不过这个不影响我们的使用。
第45行,InsertAnswer -- 这是按钮图像的文件名称,不带扩展名。如我的图像文件名是InsertAnswer.bmp,所以这里是InsertAnswer。图像一般用16x16的bmp文件。
第45行,Test Tool Button2 -- 按钮提示,这个代码中这个没有显示
第45行,Test Tool Button3 -- 按钮提示,这个代码中显示了这个字符串
第48行,button_OnClick -- 按钮处理函数名,整行代码的意思是把button_OnClick这个函数和按钮的点击事件关联起来,
第58行,WBScript.Out("no no no", true, "Message"); -- 按钮处理的具体代码,这里的例子点击这个的时候显示一个提示消息。

都保存好后就可以测试了,为了进入到Mechanical中需要创建一个简单的模型,然后打开Mechanical就可以看到定制的按钮已经加载,

打开tool->addins窗口,可以看到定制的工具栏名称已经在列表中,


前面一直没有说的v140的修改,如果是使用其他版本,修改这个字符串就可以在其他版本上加载定制的按钮,版本v12.0,修改成v120
版本v12.1,修改成v121
版本v13.0,修改成v130
注意要在xml和脚本两个文件中同时修改,而且要把xml拷贝到对应的版本的安装目录下。

以上代码及对应修改代码在v12.0,v12.1,v13.0和v14.0中测试通过。




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
回复 不支持

使用道具 举报

发表于 2012-3-2 04:56:39 | 显示全部楼层 来自 挪威
问一下最大值的那个怎么用?运行一下还是?
回复 不支持

使用道具 举报

发表于 2012-5-9 16:30:13 | 显示全部楼层 来自 湖北武汉
相当佩服,楼主真厉害
回复 不支持

使用道具 举报

发表于 2012-5-9 17:46:43 | 显示全部楼层 来自 浙江宁波
神人,楼主很强大,膜拜
回复 不支持

使用道具 举报

发表于 2012-5-10 09:50:08 | 显示全部楼层 来自 上海
高深了,楼主无私强大,加人品
回复 不支持

使用道具 举报

发表于 2013-7-10 19:54:32 | 显示全部楼层 来自 北京
神帖,对楼主的景仰如滔滔江水连绵不绝,如黄河泛滥一发而不可收拾
回复 不支持

使用道具 举报

发表于 2013-7-12 23:21:50 | 显示全部楼层 来自 江苏常州
真是强大啊! 永远的标杆!
回复 不支持

使用道具 举报

发表于 2013-7-13 08:32:43 | 显示全部楼层 来自 湖北武汉
写得好  学习了
回复 不支持

使用道具 举报

发表于 2013-7-13 14:11:34 | 显示全部楼层 来自 江苏苏州
真是强大啊! 永远的标杆!
回复 不支持

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|小黑屋|联系我们|仿真互动网 ( 京ICP备15048925号-7 )

GMT+8, 2024-6-24 21:21 , Processed in 0.118695 second(s), 15 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表