做过Abaqus二次开发的人,可能大多使用过RSG做出对话框,自动生成的脚本文件中,往往有3个py脚本,除了内核脚本,另外两个是对话框脚本(xxxDB.py)和注册脚本(xxx_plugin.py)。
对话框中所有的控件,都是在对话框脚本中创建出来的,它们很好辨认,比如:
文本框控件:AFXTextField()
复选按钮控件:FXCheckButton()
单选按钮控件:FXRadioButton()
可能有人对这些控件产生过好奇,在Abaqus帮助文档中查询过这些控件是如何创建的,以及它们的参数。
比如,文本框控件:
AFXTextField(p, ncols, labelText, tgt=None, sel=0, opts=AFXTEXTFIELD_STRING, x=0, y=0, w=0, h=0, pl=DEFAULT_PAD, pr=DEFAULT_PAD, pt=DEFAULT_PAD, pb=DEFAULT_PAD)
可能一看就蒙了,创建一个控件要这么多的参数?
实际上,我们使用AFXTextField(p, ncols, labelText, tgt=None, sel=0, opts=AFXTEXTFIELD_STRING)就可以了,后面的一大堆一般用不上,使用默认值就行。在这些参数中,p是父控件,ncols是文本框宽度,labelText是文本框前面的字符串,opt为选项参数,这些都好理解,但tgt和sel却并不容易理解。
tgt的意思是message target,消息目标。sel意思是selector,可以通俗的认为是message id,消息id。这两个参数一般都是成对出现。
在Abaqus插件对话框脚本中(有时也存在于注册脚本中),tgt和sel这两个参数的作用极为重要,它们相当于纽带,把控件、方法和注册脚本有效的联系在一起。没有它们,各个控件都是散沙,无法使用。
在这里,和大家梳理一下参数tgt和sel的设置方法。
一般来说,它们设置方式有三种。
第一种,tgt = 关键字, sel = 0或非0
采用这种设置方法的控件都有一个特征:以收集数据为目的。比如:
文本框:AFXTextField(p, ncols, labelText, tgt, sel, opts)
按钮:FXButton(p, text, ic, tgt, sel, opts)
列表:AFXList(p, nvis, tgt, sel, opts)
下拉列表:AFXComboBox(p, ncols, nvis, text, tgt, sel, opts)
单选框:FXRadioButton(p, text, tgt, sel, opts)
复选框:FXCheckButton(p, text, tgt, sel, opts)
……
以最为常用的文本框为例,在对话框脚本中,可以这样设置:
tgt = form.widthKw,sel = 0 。这是什么意思?
form.widthKw是关键字,但关键字是定义在注册脚本中的。比如:
这里是在对话框脚本中,通过form.来调用注册脚本中定义的关键字。
关键字有8种类型,每种类型的关键字,对应的构造方法也不一样,比如这里的关键字是浮点类型的。这里不对关键字展开讨论,以后另开帖子,专门说说这8种关键字。
tgt为浮点类型的关键字,那么sel则必然是0。
我们可以从帮助文档Abaqus GUI Toolkit User's Guide中的6.5.10中找到下面这张表,可以看出,关键字如果为AFXFloatKeyword,ID则为0。
第二种:tgt = 类的实例对象, sel = AFXMode.ID_ACTIVATE
如果消息目标tgt为某类的实例对象,那么消息id一般都是AFXMode.ID_ACTIVATE
这种设置方式,是将这个控件与某个实例对象做关联。
以RSG对话框生成器做出的文件选择控件为例:
在脚本中,这个控件实际上是由文本框控件和后面的按钮控件组合而成的。所以在脚本中,会自动生成以下的代码
大概解释一下:
25行,将某个类实例化,赋值给变量fileHandler
26-27行,创建水平框架布局控件,它将作为父控件,成为文本框和按钮的参数。
28-29行,创建文本框控件,此处有tgt=关键字,sel=0
30行,创建图标
31-32行,创建按钮,将tgt=fileHandler(即25行中的实例对象),sel=AFXMode.ID_ACTIVATE
在这里,按钮中的tgt和sel就是以第二种方式设置的。至于25行中的类是什么,RSG会在脚本下方自动创建,如下:
这里就不对这个类展开讨论了,在我的《Abaqus 插件程序GUI的二次开发 初中级篇》课程中有详细阐述。
这两个参数如此设置,是什么意思呢?
以这里的按钮控件为例,表示当我们单击这个按钮时,按钮控件会向这个类的实例对象发送一条消息AFXMode.ID_ACTIVATE,从而会使这个类在外部运行,并启动相应的对话框。
第三种:tgt = self, sel = 自定义ID
如果消息目标tgt设为self,那么消息id则设为某个自定义的ID,同时还需要配合FXMAPFUNC()方法,将消息id和某个方法,以某种消息类型结合在一起。
简单来说,这种设置方式,是将这个控件与某方法做关联。
以某个自定义的按钮控件为例:
点击按钮后,会在消息区域打印出一行字符串:
脚本中是这样的:
第35行,创建一个按钮控件,tgt消息目标是self,也就是对话框实例本身,消息id是在第14行自定义的ID号。
除了这两个参数外,在使用时,还需要配合使用FXMAPFUNC()方法,将消息类型、ID号和某个方法做关联。
比如这里,用FXMAPFUNC()方法,将自定义ID和一个方法onMessage做关联。那通过怎样的方式能够触发这个方法呢?这里使用的是消息类型SEL_COMMAND,它的意思是单击,也就是说,当我们点击这个按钮时,会通过自定义的ID这个纽带,找到对应的方法。这里例举的方法比较简单,仅仅在abaqus窗口下方的消息区域输出一行字符串。
以上就是参数tgt和sel的三种设置方式了。
很明显,后两种的设置方法,它的用途并不是创建某个控件,而是调用其他的功能,比如调用某个类的实例对象,或者为了调用某个方法。
这两种方式都可实现与外部功能做关联,那使用哪个更合适呢?
这个问题不好一概而论,不同的场合用不同的方式。如果某个功能是通过定义一个类来设定的,那么自然用第二种比较合适,比如这里的文件选择对话框控件,它自身有一个类,通过将此类实例化,可以运行类中定义的功能。
如果某个功能是通过某个实例方法实现的,那么用第三种合适。这样的设置方法比较直观,实例方法中就直接可以编写出我们想要的功能,比如这里的按钮控件,点击后,会执行方法中的语句,就是在消息区域打印出一行字符串。
当然,tgt和sel的设置,只是Abaqus GUI二次开发宝矿中的一角,还有更多的知识等待挖掘。
在系列视频课程《基于Python语言Abaqus插件程序GUI二次开发技术训练营31讲(初中高篇)》中,tgt和sel的设置方式是基础知识,课程还对Abaqus插件对话框的GUI二次开发做更深一步的探讨。课程不仅具有29个控件的创建和使用,还包含7个用RSG无法实现的高级实例,欢迎试看了解。