1. GUI開發簡介
Abaqus GUI程序開發時,可以采用兩種方式創建GUI圖形界面。
(1)使用RSG對話框構造器創建
(2)使用Abaqus GUI工具包創建
RSG對話框構造器是(RSG dialog Builder)是Abaqus/CAE內嵌的GUI插件開發輔助工具,位於Abaqus/CAE主視圖“Plug-ins”菜單下的“Abaqus”子菜單中的 "RSG dialog Builder" ,點擊后進入下圖所示的界面。在該界面中,用戶可以創建新的對話框,選擇並編輯控件,查看對話框的效果,關聯插件執行的內核文件等。該工具使用快捷方便,是插件開發很高效的輔助工具,但是RSG對話框構造器自身的控件種類很少,一共只用22種,對於簡單的GUI開發程序基本都能滿足。
對於復雜的GUI程序,需要用到更多的控件,此時RSG對話框無法滿足需求,需要采用第二種GUI圖形界面的創建方式,即直接在源程序文件中編輯GUI命令。
插件程序一般包括4個文件
(1)注冊文件~_plugin.py
(2)圖形界面文件~DB.py
(3)內核執行文件~Modul.py
(4)圖標文件~.png
2. 目標和消息
2.1消息類型和消息ID
Abaqus GUI工具包是通過目標/消息(target/message)機制實現GUI對象之間交互,所有的控件都可以發送消息給其他的控件,也可以接收來自其他控件的消息。一個消息一般包括兩部分:消息類型和消息ID。消息類型指發生事件的類型,消息ID表示消息的發送者。
Abaqus GUI工具包中的大部分控件都能指定目標和消息ID的變量,即使某種控件沒有指定目標和ID的變量,也可以通過setTarget和SetSelector方法來設定其目標和ID。
例如:
FXButton(parent,'Label',tgt=sef,sel=self.ID_1)#創建一個按鈕
groupBox = FXGroupBox(parent)#創建一個控件盒,自身無法設置目標和ID
groupBox.setTarget(self)#設置目標
groupBox.SetSelector(self.ID_2)#設置其消息ID
控件可以發送多種類型的消息,最常用的兩種消息類型是SEL_COMMAND
和SEL_UPDATE
.
SEL_COMMAND類型的消息一般表示某個控件被觸發,例如,用戶按下了按鈕。
SEL_UPDATE類型的消息一般是在某一控件需要請求其目標來更新自身狀態時才更新。在自動更新過程中,每個控件都會給他的目標發送一個SEL_UPDATE小時,請求自身被更新,通過這種方法來實現應用程序保持最新狀態。
2.2消息映射
一個消息通過消息映射傳遞給消息的處理方,用戶可以指定接收到某消息類型以及消息ID時所需要調用的方法(onCmdA,其中A表示方法名稱)
消息映射一般通過FXMAPFUNC()
函數來定義,函數具有四個變量,分別為self、消息類型(message type)、消息ID(message ID)以及調用的方法(method name),其中方法名必須由類名來指定。
當接收到的消息類型和消息ID與某一個FXMAPFUNC()
函數中定義的消息類型和消息ID匹配時,相應的方法就會被調用。另外,如果需要在消息映射中定義一段范圍內的ID,可以采用函數FXMAPFUNCS()
,該函數包括5個參數,分別為self、消息類型(message type)、消息起始ID(message ID)、消息結束ID(message ID)以及調用的方法(method name)。
另外,用戶可以使用SELTYPE
和SELID
函數從消息處理方法獲取消息類型和消息ID。
3. 控件創建
創建新的控件后,然后保存文件,重啟Abaqus,在Plug-ins菜單下回出現新的菜單。
可參照軟件的列子對程序進行相應的修改,例子如下所示。
注冊文件:createPlateWithhole_plugin.py
# -* - coding:UTF-8 -*-
from abaqusGui import *
from abaqusConstants import ALL
import osutils, os
###########################################################################
# Class definition
###########################################################################
class createPlateWithhole_plugin(AFXForm):
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def __init__(self, owner):
# Construct the base class.
#
AFXForm.__init__(self, owner)
self.radioButtonGroups = {}
self.cmd = AFXGuiCommand(mode=self, method='createPlateFunction',
objectName='createPlateModul', registerQuery=False)
pickedDefault = ''
self.partnameKw = AFXStringKeyword(self.cmd, 'partname', True, 'part-1')
self.widthKw = AFXFloatKeyword(self.cmd, 'width', True,100)
self.heightKw = AFXFloatKeyword(self.cmd, 'height', True,100)
self.radiusKw = AFXFloatKeyword(self.cmd, 'radius', True,5)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def getFirstDialog(self):
import createPlateWithholeDB
return createPlateWithholeDB.createPlateWithholeDB(self)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def doCustomChecks(self):
# Try to set the appropriate radio button on. If the user did
# not specify any buttons to be on, do nothing.
#
for kw1,kw2,d in self.radioButtonGroups.values():
try:
value = d[ kw1.getValue() ]
kw2.setValue(value)
except:
pass
return True
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def okToCancel(self):
# No need to close the dialog when a file operation (such
# as New or Open) or model change is executed.
#
return False
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Register the plug-in
#
thisPath = os.path.abspath(__file__)
thisDir = os.path.dirname(thisPath)
toolset = getAFXApp().getAFXMainWindow().getPluginToolset()
toolset.registerGuiMenuButton(
buttonText='創建帶孔板',
object=createPlateWithhole_plugin(toolset),
messageId=AFXMode.ID_ACTIVATE,
icon=None,
kernelInitString='import createPlateModul',
applicableModules=ALL,
version='N/A',
author='N/A',
description='N/A',
helpUrl='N/A'
)
界面文件:createPlateWithholeDB.py
# -* - coding:UTF-8 -*-
from abaqusConstants import *
from abaqusGui import *
from kernelAccess import mdb, session
import os
thisPath = os.path.abspath(__file__)
thisDir = os.path.dirname(thisPath)
#######################################################################
# Class definition
#######################################################################
class createPlateWithholeDB(AFXDataDialog):
ID_Mybutton = AFXDataDialog.ID_LAST #分配ID
def __init__(self, form):
AFXDataDialog.__init__(self, form, '帶孔板參數化建模程序',
self.OK|self.CANCEL, DIALOG_ACTIONS_SEPARATOR)
okBtn = self.getActionButton(self.ID_CLICKED_OK)
okBtn.setText('OK')
GroupBox_1 = FXGroupBox(p=self, text='參數', opts=FRAME_GROOVE)
AFXTextField(p=GroupBox_1, ncols=12, labelText='零件名 :',
tgt=form.partnameKw, sel=0)
AFXTextField(p=GroupBox_1, ncols=12, labelText='寬度(w):',
tgt=form.widthKw, sel=0)
AFXTextField(p=GroupBox_1, ncols=12, labelText='高度(h):',
tgt=form.heightKw, sel=0)
AFXTextField(p=GroupBox_1, ncols=12, labelText='半徑(r):',
tgt=form.radiusKw, sel=0)
GroupBox_3 = FXGroupBox(p=self, text='示意圖', opts=FRAME_GROOVE)
fileName = os.path.join(thisDir, r'planewithhole.png')
icon = afxCreatePNGIcon(fileName)
FXLabel(p=GroupBox_3, text='', ic=icon)
FXMAPFUNC(self, SEL_COMMAND, self.ID_Mybutton,
createPlateWithholeDB.onCmdMybutton)
FXButton(p=self, text='打印', ic=None, tgt=self,
sel=self.ID_Mybutton,
opts=BUTTON_NORMAL,
x=0, y=0, w=0, h=0, pl=0)
def onCmdMybutton(self, sender, sel, ptr):
if SELID(sel) == self.ID_Mybutton: #使用SELID函數獲取消息ID
print 'Button 1 was pressed.'
#在DOS界面下輸出提示信息
mw = getAFXApp().getAFXMainWindow()
mw.writeToMessageArea('Button 1 was pressed.' )
#在abaqus/CAE主窗口下方的提示區顯示提示信息
return 1
內核程序:createPlateModul.py
# -* - coding:UTF-8 -*-
from abaqus import *
from abaqusConstants import *
def createPlateFunction(partname, width, height, radius):
mdb.models['Model-1'].ConstrainedSketch(name='__profile__', sheetSize=200.0)
mdb.models['Model-1'].sketches['__profile__'].rectangle(point1=(0.0, 0.0),
point2=(width, height))
mdb.models['Model-1'].sketches['__profile__'].CircleByCenterPerimeter(center=(
width/2, height/2), point1=(width/2+radius, height/2))
mdb.models['Model-1'].Part(dimensionality=THREE_D, name=partname, type=
DEFORMABLE_BODY)
mdb.models['Model-1'].parts[partname].BaseShell(sketch=
mdb.models['Model-1'].sketches['__profile__'])
p = mdb.models['Model-1'].parts[partname]
session.viewports['Viewport: 1'].setValues(displayedObject=p)
del mdb.models['Model-1'].sketches['__profile__']
#幾何創建完成
mdb.models['Model-1'].Material(name='AL')
mdb.models['Model-1'].materials['AL'].Elastic(table=((70000.0, 0.3), ))
mdb.models['Model-1'].HomogeneousShellSection(name='al', preIntegrate=OFF,
material='AL', thicknessType=UNIFORM, thickness=1.0, thicknessField='',
idealization=NO_IDEALIZATION, poissonDefinition=DEFAULT,
thicknessModulus=None, temperature=GRADIENT, useDensity=OFF,
integrationRule=SIMPSON, numIntPts=5)
f = p.faces
faces = f.getSequenceFromMask(mask=('[#1 ]', ), )
region = p.Set(faces=faces, name='Set-2')
p.SectionAssignment(region=region, sectionName='al', offset=0.0,
offsetType=MIDDLE_SURFACE, offsetField='',
thicknessAssignment=FROM_SECTION)
#建立材料並賦予屬性
session.viewports['Viewport: 1'].partDisplay.setValues(mesh=ON)
session.viewports['Viewport: 1'].partDisplay.meshOptions.setValues(
meshTechnique=ON)
session.viewports['Viewport: 1'].partDisplay.geometryOptions.setValues(
referenceRepresentation=OFF)
#切換到mesh模塊
p = mdb.models['Model-1'].parts[partname]
p.seedPart(size=4.0, deviationFactor=0.1, minSizeFactor=0.1)
f = p.faces
pickedRegions = f.findAt(((width/2, 0.0, 0.0), ))
p.setMeshControls(regions=pickedRegions, elemShape=QUAD,algorithm=MEDIAL_AXIS)
#設定網格划分格式
p.generateMesh()
#網格划分
a = mdb.models['Model-1'].rootAssembly
session.viewports['Viewport: 1'].setValues(displayedObject=a)
session.viewports['Viewport: 1'].assemblyDisplay.setValues(
optimizationTasks=OFF, geometricRestrictions=OFF, stopConditions=OFF)
#切換到裝配模塊
a = mdb.models['Model-1'].rootAssembly
a.DatumCsysByDefault(CARTESIAN)
p = mdb.models['Model-1'].parts[partname]
a.Instance(name=partname+'-1', part=p, dependent=ON)
#創建裝配實例
mdb.models['Model-1'].StaticStep(name='Step-1', previous='Initial', nlgeom=ON)
session.viewports['Viewport: 1'].assemblyDisplay.setValues(step='Step-1')
#創建分析步
session.viewports['Viewport: 1'].view.setValues(nearPlane=335.564,
farPlane=385.546, width=212.48, height=142.547, viewOffsetX=13.3712,
viewOffsetY=-7.13345)
a = mdb.models['Model-1'].rootAssembly
e1 = a.instances[partname+'-1'].edges
edges1 = e1.findAt(((0.0, height/2, 0.0), ))
region = a.Set(edges=edges1, name='Set-1')
mdb.models['Model-1'].DisplacementBC(name='BC-1', createStepName='Step-1',
region=region, u1=0.0, u2=0.0, u3=0.0, ur1=0.0, ur2=0.0, ur3=0.0,
amplitude=UNSET, fixed=OFF, distributionType=UNIFORM, fieldName='',
localCsys=None)
#施加邊界條件
edges1 = e1.findAt(((width, height/2, 0.0), ))
region = a.Set(edges=edges1, name='Set-2')
mdb.models['Model-1'].DisplacementBC(name='BC-2', createStepName='Step-1',
region=region, u1=2.0, u2=UNSET, u3=UNSET, ur1=UNSET, ur2=UNSET, ur3=UNSET,
amplitude=UNSET, fixed=OFF, distributionType=UNIFORM, fieldName='',
localCsys=None)
#施加位移載荷
mdb.Job(name='Job-hole', model='Model-1', description='', type=ANALYSIS,
atTime=None, waitMinutes=0, waitHours=0, queue=None, memory=50,
memoryUnits=PERCENTAGE, getMemoryFromAnalysis=True,
explicitPrecision=SINGLE, nodalOutputPrecision=SINGLE, echoPrint=OFF,
modelPrint=OFF, contactPrint=OFF, historyPrint=OFF, userSubroutine='',
scratch='', multiprocessingMode=DEFAULT, numCpus=1, numGPUs=0)
#創建job