□文 /張海濤
VBA(Visual Basic for Application)是一種面向?qū)ο蟮木幊陶Z言,它的基本語法完全繼承于VB,所以具有語法簡單易懂、編程邏輯清晰的特點(diǎn),非常適合程序的快速開發(fā)。VBA的強(qiáng)大優(yōu)勢在于將VB的編程環(huán)境與被開發(fā)程序同時(shí)運(yùn)行,利用面向?qū)ο缶幊谭椒ǎ∣OP),在接口的庫中將軟件中的重要部分對象化、參數(shù)化,在VBA中直接調(diào)用軟件中豐富的對象進(jìn)行操作以實(shí)現(xiàn)編程目的。因此,VBA作為一種通用型語言,能廣泛應(yīng)用于Windows下的Office系列軟件、AutoCAD等專業(yè)商業(yè)軟件的二次開發(fā)、Windows腳本編程(VBS)等。
AutoCAD是目前應(yīng)用最為廣泛的交互式計(jì)算機(jī)輔助繪圖與設(shè)計(jì)軟件,其優(yōu)勢在于通用性、多工業(yè)標(biāo)準(zhǔn)和開放的體系結(jié)構(gòu),廣泛應(yīng)用于土木建筑、裝飾設(shè)計(jì)、機(jī)械工程等領(lǐng)域。雖然AutoCAD功能強(qiáng)大,但在解決一些專業(yè)問題,尤其在需要結(jié)合設(shè)計(jì)計(jì)算、數(shù)據(jù)處理、復(fù)雜圖形繪制時(shí)就會(huì)顯得力不從心,這時(shí)候在程序基礎(chǔ)上對AutoCAD進(jìn)行二次開發(fā)成為解決上述問題的有效補(bǔ)充手段[1]。AutoCAD常見的二次開發(fā)工具包括Auto LISP/Visual LISP、基于ActiveX Automation技術(shù)的VB/VBA、采用C++語言的Object ARX技術(shù)、基于微軟.Net技術(shù)的VB.Net和C#語言開發(fā)。這幾種語言各有優(yōu)劣,具體特點(diǎn)及使用方法可參考相關(guān)介紹[2]。相較而言,VBA具有編程簡單、快速開發(fā)、運(yùn)行效率高、功能強(qiáng)大等特點(diǎn)使其擁有不同于其他二次開發(fā)工具的特殊優(yōu)勢,也使其在各專業(yè)工程人員中的推廣和繼承具有了生命力。
基于VBA的這些優(yōu)勢,二次開發(fā)技術(shù)在橋梁工程中得以廣泛應(yīng)用[3]。本文對AutoCAD和Excel進(jìn)行聯(lián)合開發(fā),利用Excel獲取CAD圖形數(shù)據(jù)生成橋梁工程專業(yè)計(jì)算軟件橋博的腳本,輔助橋博軟件的建模,提高了工作效率。在此基礎(chǔ)上本文著重介紹了包括VBA理論模塊、程序設(shè)計(jì)方法和關(guān)鍵技術(shù),為相關(guān)工程的二次開發(fā)提供參考。
首先,二次開發(fā)的操作是基于對AutoCAD提供對象(Object)的操作,這些對象的種類非常豐富并且包含各種屬性(Properties)和方法(Methods)。對象本質(zhì)上是一種特殊的變量,可以進(jìn)行定義、賦值、釋放。AutoCAD中的對象按性質(zhì)可以主要?jiǎng)澐譃橐韵聨追N[4]。
1)圖形對象,如直線(Line)、文本(Text)、標(biāo)注(Dimensions)等。
2)樣式設(shè)置對象,如線型(Linetype)、文字樣式(TextStyle)。
3)組織結(jié)構(gòu),如圖層(Layers)、塊(Blocks)。
4)圖形顯示對象,如視圖(View)和視口(Viewport)。
5)AutoCAD 應(yīng) 用 程 序 (Application) 和 文 檔(Document)。
這些對象基本涉及到了AutoCAD的各方面并可以在VBA的對象瀏覽器中查詢。各對象之間并不是隨意排列,大多數(shù)都存在父對象和子對象的樹形衍生關(guān)系,常用對象見圖1。
圖1 AutoCAD對象
如圖1所示,AutoCAD中的圖形對象基本都囊括在ModelSpace中,比如常用的各類線、文字等,用Add方法可以向AutoCAD的Document對象中添加各種圖元,完成圖形的繪制,而另外一個(gè)重要的對象Utility則集合了一系列的內(nèi)部實(shí)用工具,比如獲取兩點(diǎn)間距(GetDistance)、獲取對象(GetEntity)、獲取坐標(biāo)(GetPoint)等方法函數(shù),用于獲取圖形中的各類信息。這兩個(gè)基本類可以完成對AutoCAD的大部分常用操作。關(guān)于其余對象的定義、屬性、方法及示例都可以在AutoCAD提供的官方幫助文件里查詢。
使用VBA開發(fā)軟件可以分為內(nèi)部調(diào)用和外部調(diào)用兩種方式。AutoCAD內(nèi)置了VB的開發(fā)環(huán)境VBE(高版本需要安裝VBA開發(fā)包),可以在VBE中直接開發(fā)VBA,這樣能夠在程序內(nèi)部直接運(yùn)行程序并查看在窗口中的運(yùn)行結(jié)果,這是VBA相較其他開發(fā)語言的優(yōu)勢之一。缺點(diǎn)是內(nèi)置的VBA沒有辦法進(jìn)行封裝,只能將代碼部分通過加密的方式進(jìn)行簡單保護(hù)。
由于在AutoCAD中無法通過內(nèi)部命令的方式直接運(yùn)行內(nèi)部VBA,所以通常會(huì)用LISP給VBA編寫一個(gè)調(diào)用命令,可采用如下形式:
(defun c:CM()
(command“_vbarun”“cm_vba”)
)
這樣,在加載這個(gè)lsp文件和dvb格式的源文件后,就可以通過在命令行中直接輸入“CM”來內(nèi)部調(diào)用名稱為“cm_vba”的VBA程序。
在另外一些情況下,如果將部分代碼封裝為動(dòng)態(tài)鏈接庫后外部引用或者從其他程序的VBE、VB6.0和Visual Studio等開發(fā)工具進(jìn)行外部控制時(shí),則需要進(jìn)行外部調(diào)用,首先要在窗口的“工具”-“引用”中調(diào)用基本庫[5],然后在代碼部分聲明引用對象,獲得軟件的控制權(quán)限。
例如,當(dāng)采用外部創(chuàng)建CAD文件時(shí),可采用以下代碼,依次獲得對軟件和新建文檔的控制權(quán):
DimAcadApp as AcadApplication
DimAcadDoc as AcadDocument
Set AcadApp
=CreateObject(“AutoCAD.Application”)
AcadApp.Visible=True
Set AcadDoc=AcadApp.ActiveDocument
外部調(diào)用的缺點(diǎn)是沒有辦法直接在AutoCAD中直接運(yùn)行程序查看結(jié)果且需要考慮程序運(yùn)行過程中輸入、輸出的接口問題。但是外部調(diào)用為AutoCAD與其他程序的交互提供了實(shí)施方法。
AutoCAD的優(yōu)勢在于對圖形的處理,當(dāng)涉及到其他方面的工作時(shí),單一依賴AutoCAD或者完全靠VB本身的功能與函數(shù)去構(gòu)建復(fù)雜的程序會(huì)拖累整體的運(yùn)行效率。所以,與其他專業(yè)軟件進(jìn)行交互,是VBA的一項(xiàng)重要功能,見圖2。
圖2 VBA交互體系
Excel是微軟公司開發(fā)的專業(yè)辦公軟件,所以O(shè)ffice已經(jīng)內(nèi)置了VBA的開發(fā)環(huán)境[6]。Excel協(xié)助AutoCAD能夠完成數(shù)據(jù)提取、整理、運(yùn)算、輸出等一系列工作,結(jié)合Excel和AutoCAD可以避免大量使用VB窗口及控件,從而節(jié)省復(fù)雜的窗口設(shè)計(jì)工作。關(guān)于Excel的對象結(jié)構(gòu)此處不多做介紹,具體參閱相關(guān)教材與手冊。
在設(shè)計(jì)程序時(shí),需要選擇VBA基于的軟件主體:如果程序的主要功能是運(yùn)算和數(shù)據(jù)處理,需要從Au-toCAD定向獲取、輸出圖形信息,可以選擇從Excel控制AutoCAD,借用Excel的內(nèi)置功能對數(shù)據(jù)信息進(jìn)行處理;如果程序的主要任務(wù)是繪圖,只是借助Excel的末端功能完成簡單數(shù)據(jù)匯總、數(shù)據(jù)傳遞功能等,可以選擇從AutoCAD控制Excel;如果希望編譯獨(dú)立可執(zhí)行程序,可以直接用VB6.0、Visual Studio等開發(fā)工具調(diào)用其他VBA兼容軟件。
因?yàn)閂BA語言本身沒有劃分模塊的語法結(jié)構(gòu),所以在程序設(shè)計(jì)初期就應(yīng)當(dāng)考慮把程序定義成不同模塊,以方便后期對程序進(jìn)行定向維護(hù)和擴(kuò)展,有以下幾個(gè)基本原則可參考。
1)劃分程序的主次,將具體執(zhí)行各部分功能的操作歸納于不同的子程序中,而主程序用于控制所有子程序的運(yùn)算流程,這里將最終腳本輸出函數(shù)Genegrate_Script()作為主程序,而子程序負(fù)責(zé)各個(gè)部分腳本信息的統(tǒng)計(jì)和生成,見圖3。
圖3 程序模塊
2)將自編的一些通用型功能函數(shù)歸納成各類函數(shù)模塊,方便在不同的子程序中直接使用,也方便向其他程序進(jìn)行移植,比如排序函數(shù)、插值函數(shù)、向量計(jì)算函數(shù)等。
Sub Array_Shrink(ByRefarr As Variant)
'清除多段線中重復(fù)節(jié)點(diǎn)
......
For i=2 Tonum-1 Step 2
tmp_array(m)=arr(i)
tmp_array(m+1)=arr(i+1)
Ifarr(i)=arr(i-2)And arr(i+1)=arr(i-1)Then
ReDimPreserve tmp_array(num-2)
Else
m=m+2
End If
Next i
arr=tmp_array
End Sub
3)VB不具備C++/C#等語言方便定義類的功能,但是依然可以利用Type語句在“模塊”中自定義數(shù)據(jù)類型,可以將一些變量盡量對象化置于模塊中,以方便對同對象變量進(jìn)行識(shí)別,比如此處將箱梁截面定義成對象,包含截面的序號(hào)、坐標(biāo)、插入點(diǎn)屬性。
Public Type bdSection '定義箱梁截面
indexAs Integer '截面序號(hào)
Pt_List As Variant'截面組成坐標(biāo)
InsertPt As Variant'截面插入點(diǎn)坐標(biāo)
End Type
以Excel為主體,通過VBA外部控制AutoCAD獲取模型信息,自動(dòng)生成橋博的腳本文件。主程序主要負(fù)責(zé)匯總各部分信息并輸出為橋博腳本dbs類型文本。型式參照以下總體信息部分代碼,引用的是init_ZTXX()函數(shù)
Print#1,"http://總體信息*************"
Print#1,"GEN.PrjTitle=""橋梁博士腳本"";"
Print#1,"GEN.CalType="&init_ZTXX.CalType&";" '函數(shù)獲取總體信息
Print#1,"GEN.BPrestress="&init_ZTXX.bPrestress&";"
Print#1,"GEN.SelfHumi=0.8;
Print#1,"GEN.Code="&init_ZTXX.Code&";"
Print#1,"GEN.cU="&init_ZTXX.cU&";"
從Excel內(nèi)部控制AutoCAD需要識(shí)別已打開的CAD文件,使用的是GetObject()函數(shù),型式如下
DimAcadApp as AcadApplication
DimAcadObj As AcadDocument
Set AcadApp=GetObject(,"AutoCAD.Application")
Set AcadObj=AcadApp.ActiveDocument
進(jìn)入AutoCAD之后,由于模型空間的圖形類型豐富,需要對選定對象類別進(jìn)行限制,可以用FilterType、FilterData兩個(gè)數(shù)組限定選擇對象為多段線或者直線等圖元類型
DimFilterType(0)As Integer
DimFilterData(0)As Variant
FilterType(0)=0
FilterData(0)="LWPOLYLINE"
Plset.SelectOnScreen FilterType,FilterData
在AutoCAD中通過鼠標(biāo)點(diǎn)擊獲取坐標(biāo)參考原點(diǎn),使用Utility下的Getpoint()函數(shù),但需要注意由于是外部控制程序,涉及對象語句必須前置主體對象A-cadObj,也就是CAD文件本身:
base_pt=AcadObj.Utility.GetPoint(,"選擇參考基點(diǎn):")
這里程序會(huì)返回一個(gè)三維雙精度數(shù)組,表示點(diǎn)在三個(gè)方向的坐標(biāo)值。
通過選擇獲得多段線對象后,即可以通過其Coordinates屬性得到多段線上全部的節(jié)點(diǎn)坐標(biāo),返回值為一個(gè)數(shù)組,然后再返回給Excel
Num=Plset.count
For i=0 Tonum-1
Pl_cdn=plObj(i).Coordinates
Call Array_Shrink(Pl_cdn)
'自定義函數(shù)刪除多段線上重復(fù)節(jié)點(diǎn)
Pl_num= (UBound(Pl_cdn)+1)/2
For j=0 ToPl_num-1
Cells(j+12,4*i+1).Value=j+1
Cells(j+12,4*i+2).Value=Round((Pl_cdn(2*j)-base_pt(0))/1000,3)
Cells(j+12,4*i+3).Value=Round((Pl_cdn(2*j+1)-base_pt(1))/1000,3)
Cells(j+12,4*i+4).Value=0
Next j
Next i
從AutoCAD中得到的圖形信息本質(zhì)就是節(jié)點(diǎn)坐標(biāo),利用Excel的數(shù)據(jù)統(tǒng)計(jì)功能可以方便的對這些坐標(biāo)做自動(dòng)化處理
DimSec_numAs Integer'截面類型數(shù)量
DimSections()As bdSection'截面類型
Sec_num=WorksheetFunction.CountA (Range("B4:B100"))
ReDimSections(1 ToSec_num)
這樣就定義了一個(gè)截面對象數(shù)組,包含全部類型截面的坐標(biāo)信息。
VBA編程主要具有以下幾個(gè)優(yōu)點(diǎn):
1)語法簡單清晰、邏輯性強(qiáng),能夠協(xié)助工程人員快速掌握并開發(fā)程序,不需要花費(fèi)大量時(shí)間去學(xué)習(xí)復(fù)雜的語法和數(shù)據(jù)結(jié)構(gòu)原理方面的知識(shí);
2)VBA具有通用性,可以用于二次開發(fā)Auto-CAD、Office等一系列軟件,更可以用來聯(lián)合不同功能的軟件進(jìn)行組合編程,實(shí)現(xiàn)功能上的互補(bǔ);
3)利用二次開發(fā)技術(shù),在面對需要批量化、重復(fù)性、數(shù)據(jù)處理類的工作時(shí),能夠明顯提高完成速度。
當(dāng)然,VBA的一些缺點(diǎn)限制了它的應(yīng)用和發(fā)展,比如大部分使用者由于是非編程專業(yè)領(lǐng)域出身的工程人員,加之VB語法本身不夠緊湊,很容易寫出龐大繁冗的程序。VBA的類定義功能不全,它的優(yōu)勢在于對接口提供的類庫進(jìn)行直接應(yīng)用而并不是深化創(chuàng)造,使得它在二次開發(fā)領(lǐng)域的應(yīng)用擴(kuò)展性比較受限。
但總而言之,對于工程領(lǐng)域的從業(yè)者來說,VBA實(shí)現(xiàn)的部分功能是一種極為高效簡便的解決方案,本文簡單介紹了其在橋博建模中的一種應(yīng)用方法,可為在其他更廣泛領(lǐng)域內(nèi)的使用提供參考。