明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 4298|回复: 9

AutoCAD开发常见问题

  [复制链接]
发表于 2004-5-11 10:14 | 显示全部楼层 |阅读模式
版本老了点,是R14的不过有些还有用 张朝阳
Autodesk China
问:有什么方式可以在AutoCAD启动的时候自动加载VBA工程?
答:当VBA加载时会在AutoCAD目录下寻找一个名叫acad.dvb的工程。如果找到,就会自动加载它。如果你想VBA和缺省工程在AutoCAD启动的时候每次都加载,你需要在acad.rx文件中生成一个入?。VBA被设计成命令加载方式(在没有激活一个VBA命令之前不占用任何内存和进程)。为了总是加载VBA和acad.dvb工程,请在acad.rx文件中包含下列一行: acadvba.arx
在AutoCAD
2000中支持嵌入工程,这样当你打开拥有嵌入工程的图形文件时该工程就会自动加载。所以定义嵌入工程也是一个很好的自动加载VBA工程的办法。
问:有办法可以在AutoCAD启动时自动运行一个VBA例程或宏吗? 答:当然。你可以从AutoCAD的acad.lsp文件的启动功能中通过VBARUN的命令行版本运行一个工程中的宏。首先,你需要准备acad.dvb文件以便自动加载。以drawline.dvb作为例子,用VBALOAD命令弹出VBA
IDE对话框。然后用VBA
IDE保存为菜单命令保存此工程为新的名字acad.dvb。下一步,激活notepad.exe并且建立或添加下列行到acad.lsp文件中:
(defun S::STARTUP() (command "_-vbarun" "drawline"))
问: AutoCAD支持VBA多工程的打开吗?
答:在2000中支持。但在14版中尚不支持。
问:我可以加密我的VBA模块代码吗?
答:虽然VBA不支持可执行文件的创建,但是它确实在一个工程的基础上提供了口令保护工程窗体、类和模块可见性的功能。你可以发现这个工程保护功能在VBA
IDE菜单中。选择 工具 > 工程属性 > 保护。如下图所示: 问:在VBA中如何在命令行上提示?
答:有一些方法允许在命令行提示输入以获取数据。这些方法以“GET”开头。你可以发现决大多数的方法(如果不是全部的话)通过对象浏览器搜索AutoCAD类型库。启动VBA
IDE。击F2功能键或者从视图菜单中选择对象浏览器。?对象浏览器窗口中使用库范围下拉列表把缺省的<所有库>改成AutoCAD。库列表下面的编辑列表框是用来搜索的。输入GET到那个编辑列表框中并且敲回车键。包含“GET”的类和成员函数就会显示在滚动列表中。AcadUtility的一些成员函数可以?命令行上提示用户输入。如下图所示:

评分

参与人数 1威望 +1 金钱 +10 贡献 +5 激情 +5 收起 理由
mccad + 1 + 10 + 5 + 5 【精华】好文章

查看全部评分

 楼主| 发表于 2004-5-11 10:15 | 显示全部楼层
问:我怎样从AutoCAD菜单中激活一个VBA例程?
答:你需要编辑菜单和添加VBARUN模块子例程。首先确认正确的VBA工程已经加载。
问:我怎样从AutoCAD菜单中启动一个VBA对话框(窗体)?
答:除了创建一个VBA窗体,你还需要创建一个VBA子例程来显示这个窗体。而这个子例程需要用VBARUN命令激活。1. 启动VBA IDE;2.
从菜单中选择 插入 > 用户窗体(缺省名称为UserForm1);3. 添加合适的控件到你的窗体中; 4. 下一步,从菜单中选择 插入 >
模块;5. 输入以下的代码到缺省的Module1模块中:Sub Foo() UserForm1.showEnd Sub6.
最后,编辑AutoCAD菜单调用以下命令来激活对话框: -VBARUN Module1.foo.
问:我已经写了一个VBA例程用ThisDrawing.Utility.GetPoint获取一个点。当我从一个VBA对话框中启动这个例程时,我可以在命令行上看到提示。但是我不能在AutoCAD屏幕上点取一个点。我作错了什么? 答:首先需要关闭对话框,然后才能从AutoCAD获取数据。添加以下的代码到ThisDrawing.Utility.GetPoint之前的任何地方以关闭对话框,然后你就可以获得一个点了。 Me.Hide
问:有方法加载一个VBA工程而在加载后不显示VBA IDE吗? 答:如果你设置AutoCAD系统变量FILEDIA为0,或者在你加载一个工程的时候把<打开VBA编辑器>的开关关闭,你就不会?加载之后看到VBA
IDE了。这是一个标准的AutoCAD转换机制。
问:VBA和AutoLISP有何不同,两者如何转换?
答:如果你已经熟知AutoLISP并且想学习VBA,通过把VBA和AutoLISP表达式联系起来的方法就可以容易地做到。以下就是一个关于两种语言的比较。由于大量的AutoLISP代码可以利用,转换一个已有的AutoLISP代码段为VBA远比重新编制VBA代码来得容易。如果两者的变量名字保持一致,那么比较两者的代码也就变得容易了。 点:
在AutoLISP中,你用(setq)函数来设置一个点。下面这一行把点(0,0,0)分配给PT1变量。(0,0,0)代表这个点位置的x,y,z坐标。 (setq PT1 '(0 0 0))
在VBA中,这个操作需要更多的代码行来完成:
Dim PT1(0 To 2) As Double
PT1(0) = 0#
PT1(1) = 0#
PT1(2) = 0#
在VBA中,你使用Dim语句来声明变量。点总是保存在一个三维双精度值数组中。一个数组也就是一个变量列表。在数组中的变量都拥有相同的名字。数组中的第一个元素使用索引值0,即PT1(0)。第二个元素使用索引值1,即PT1(1)。依次类推。 VBA使用#号作为双精度值类型的后缀字符。在这个数组中,PT1(0)保存x坐标值,PT1(1)保存y坐标值,PT1(2)保存z坐标值。
既然你已经知道如何保存一个点,我们就可以写一个VBA宏来在两点之间画一条线。
在AutoLISP中,你使用(defun)来定义一个名叫Line1的T诤智暗腃:
意味着拥护可以直接从AutoCAD命令行上执行这个函数。下一步,分配两个点,然后用AutoCAD的LINE命令?两点之间画一条线了。
在VBA中,一个子例程创建一个与AutoLISP相当的函数。下面是AutoLISP和VBA的源代码。
AutoLISP code

(defun CINE1 ()
(setq PT1 '(0 0 0))
(setq PT2 '(4 4 0))
(command "._line" PT1 PT2 "")
) VBA code

Sub Line1()
Dim NewLine As Object
Dim PT1(0 To 2) As Double
Dim PT2(0 To 2) As Double
PT1(0) = 0#
PT1(1) = 0#
PT1(2) = 0#
PT2(0) = 4#
PT2(1) = 4#
PT2(2) = 0#
Set NewLine = ModelSpace.AddLine(PT1, PT2)
End Sub 子例程的第一行声明变量NewLine为一个对象。对象是一个应用程序的一个元素。线,视图和层都是对象的例子。下一步,点数组声明了两个点值。最后,AutoCAD从(0,0,0)到(4,4,0)画一条线。添加一条线到模型空间中,你需要使用ModelSpace对象集合中的AddLine方法和一条线的起始和终止点。 获取点:
用AutoLISP,你经常需要提示拥护选择一个点。你可以在VBA中用Utility对象的GetPoint方法达到这个目的。你需要声明一个额外的VarRet变量来保存返回值。以下是Line2的AutoLISP和VBA的代码对照:
 楼主| 发表于 2004-5-11 10:15 | 显示全部楼层
AutoLISP code

(defun CINE2 ()
(setq PT1 (getpoint "\nStart Point: "))
(setq PT2 (getpoint PT1 "\nEnd Point: "))
(command "._line" PT1 PT2 "")
) VBA code

Sub Line2()
Dim VarRet As Variant
Dim NewLine As Object
Dim PT1(0 To 2) As Double
Dim PT2(0 To 2) As Double
VarRet = Utility.GetPoint(, "Start Point: ")
PT1(0) = VarRet(0)
PT1(1) = VarRet(1)
PT1(2) = VarRet(2)
VarRet = Utility.GetPoint(PT1, "End Point: ")
PT2(0) = VarRet(0)
PT2(1) = VarRet(1)
PT2(2) = VarRet(2)
Set NewLine = ModelSpace.AddLine(PT1, PT2)
End Sub 这一次,GetPoint方法返回一个Variant数据类型。这种数据类型可以保存任何类型的数据。为了使用你选择的并且保存在变量VarRet之中的开始和终止点,你必须转换Variant数据为一个双精度值的数组并且把他们付值给PT1和PT2。 现在两个VBA子例程已经建立起来了,如何运行它们呢?
启动AutoCAD,打开一个新图;
加载工程;
选择 工具|宏|运行宏;
选择宏位置(缺省为所有活动图形和工程);
5. 从窗口中选择宏名称;
6. 点击运行按钮。
 楼主| 发表于 2004-5-11 10:18 | 显示全部楼层
AutoCAD开发常见问题(二) 张朝阳
Autodesk China

问:能够给AutoCAD的VBA宏传递参数吗?
答:从AutoCAD直接传递参数到一个VBA宏中是不可能的。但是你可以用VBA的GetString 方法和LISP的(command)函数来传递信息。 举例:
首先定义一个VBA宏:
Sub testparams()
Dim str, str2 As String
str=ThisDrawing.Utility.GetString(False)
str2=ThisDrawing.Utility.GetString(False)
MsgBox str
MsgBox str2
End Sub
然后用以下LISP语句调用此宏:
(command "-VBARUN" "testparams" "param1" "param2")
 
问:.MNU和.LSP文件的调用顺序是怎样的?
答:他们在AutoCAD 2000的调用顺序是这样的:
当AutoCAD启动时:
- acadr2000.lsp
- acad.lsp
对于每个新打开的文档:
- acad.lsp, 如果在AutoCAD的配置对话框中的系统标签下做了相应的选项设定。
- acaddoc2000.lsp
- acaddoc.lsp
- .MNU菜单文件和它们的关联.MNL文件。
 楼主| 发表于 2004-5-11 10:19 | 显示全部楼层
问:我已经写了一个VisualLisp函数和一个VBA宏。这个VBA宏显示一个对话框,并且有一些按钮允许有用户输入(例如:输入一个字符串)。现在我从VisualLisp用(vl-vbarun)调用这个VBA宏。当AutoCAD执行到这一行时,LISP停在这一行。但是一旦我在此宏中使用了一个用户输入函数,LISP就不等VBA对话框出现,而继续执行下面的LISP函数。有些时候甚至首先执行LISP的输入函数,然后再执行VBA宏中的输入语句。怎样才能使我的LISP函数和VBA宏同步? 答:现在只有一个解决办法。在你的LISP函数中(vl-vbarun)
函数必须最后调用。当关闭VBA对话框或者从VBA宏中返回时,你得调用另一个你想继续执行的LISP函数。你可以象下面这样做。
首先:你需要一个LISP函数调用这个VBA宏:
(defun c:test ()
;; Call a VBA macro which displays
;; a dialog and writes a file.
(vl-vbarun "test")
;;If you uncomment the following line, then AutoCAD will prompt you
;;to select an entity first, input a string second.
;;(entsel)
(princ)
)
然后你需要第二个LISP函数以供你的VBA宏返回时调用:
(defun c:test_cont ()
;; Here you can continue.
(print “ I am continuing.”)
(princ)
)
以下是这个VBA宏的示例:
Sub test()
' Show a dialog which uses some
' user input functions.
UserForm1.Show
' Call the lisp function which should
' be now executed.
' You can use the SendCommand method:
' ThisDrawing.SendCommand ("test_cont ")
' or use the ActiveX interface of VisualLisp:
' In order to use it, please remember to reference vl.tlb file which is in
Acad2000 folder
' into your VBA project and execute (vl-load-com) on the AutoCAD command
line first.
Dim vl As Object
Set vl = CreateObject("VL.Application.1")
vl.ActiveDocument.functions.Item("c:test_cont").funcall
End Sub
 
问:怎样用Visual Basic生成一个用户接口模块以供Visual LISP方便地调用?
答:最简单和最有效的方法是为AutoCAD写一个内过程(in-process)的自动客户(Automation Client)。例如:一个VB
ActiveX DLL。这个DLL 以后可以从 Visual LISP, VBA, Java
(通过Automation)和ObjectARX加载。它可以是一个AutoCAD的自动客户,也可以是一个任何的自动服务器( Automation
server),或者多重服务器。
1. 启动Visual Basic 5 or 6;
2. 在New Project Wizard中选择ActiveX DLL;
3. 把工程名改为"MyProject";
4. 在工程中有一个缺省的类模块,把它的名称改为"MyClass";
5. 添加一个函数或者子例程到类模块中。例如:
' This function takes two arguments, and will return a list of data to the
calling function
Public Function MyFn(ByRef arg1 as Integer, ByRef arg2 as Double) As
Variant
myForm.Show vbModal
' Create a list of items to return to the caller (the items are in this
case purely arbitrary)
MyFn = Array(1.0,"Arbitrary string",2)
End Function
(这里,myForm是一个你必须添加到工程中的表格。同时切记MyFn是一个函数,它将返回一个值或者一组值给调用例程。)
6. 点取File -> Make
MyProject.dll。这就会生成一个DLL并且把它注册为COM。(如果你想在其他机器上运行此DLL,你需要首先确认在所有的机器上安装并注册了这个DLL。这通常需要你用Visual
Basic生成一个安装包。)
7. 如果你想从Visual LISP中使用此DLL,你需要定义一个简单的函数,并且把他加载到AutoCAD中:
(defun showDialog (/ acadApp vbApp retVal retList)
;; required in AutoCAD 2000, not R14
(if (car (atoms-family 1 '("vl-load-com"))) (vl-load-com))
;; get the main AutoCAD application object
(setq acadApp (vlax-get-acad-object))
;; load VB ActiveX DLL into AutoCAD's address space (either line will
work)
;;(setq vbApp (vlax-invoke acadApp "GetInterfaceObject"
"MyProject.MyClass")
(setq vbApp (vla-GetInterfaceObject acadApp "MyProject.MyClass"))
(if (not vbApp)
(princ "\nError loading ActiveX DLL.")
(vlax-invoke vbApp "MyFn"
7 ; arg1, an integer
1.5 ; arg2, a 'double'
)
)
)
为了调用已经暴露出的ActiveX方法,在命令行上输入:
(showDialog)
将把下列内容返回给AutoCAD:
(1.0 "Arbitrary string" 2)
你会发现你可以给VB对话框传递参数并且在AutoCAD中处理返回值。这对于生成选项对话框非常有用,因为有些参数需要初始化并且修改后的值需要返回给AutoCAD。 7. 如果你想从VBA使用这个DLL,你需要把此DLL添加到引用中。(用COM注册它,就会把它添加到ActiveX
服务器的列表中。然后它就可以被VBA引用,不然就请浏览并且选择MyProject.dll。)
8. 然后你就可以用下面的机制加载这个内过程 ActiveX DLL,并且调用其中的函数:
Sub MyVBAProject()
Dim oMyApp as Object
dim vReturn as Variant
set oMyApp = ThisDrawing.Application.GetInterfaceObject(
"MyProject.MyClass"
)
vReturn = oMyApp.MyFn(7,1.5)
End Sub
 
问:可以在VBA中获得带有预览图象的AutoCAD "Open File Dialog"对话框吗?
答:在VBA没有直接的方法这样做。但是,你可以通过LISP和AutoCAD之间的通讯来完成。在LISP中有一个名叫getfiled的函数,它可以预览DWG并且与AutoCAD的"Open
File Dialog"表现一样。
首先,通过SendCommand方法发送getfiled表达式给AutoCAD命令行并且定义一个系统变量USERS1以保存文件名。然后,你可以用GetVariable方法获得这个系统变量。最后,象使用其它任何变量一样使用它。 Public Sub OpenDialog()
Dim fileName As String
ThisDrawing.SendCommand "(setvar " & """users1""" & "(getfiled " &
"""Select a DWG File""" & """c:/program files/acad2000/""" & """dwg""" &
"8)) "
fileName = ThisDrawing.GetVariable("users1")
MsgBox "You have selected " & fileName & "!!!", , "File Message"
End Sub
 楼主| 发表于 2004-5-11 10:19 | 显示全部楼层
问:
如何在AutoLISP调用完一个VBA宏后,卸载包含它的VBA工程?我想首先加载这个工程,调用一个宏,然后卸载它。下面是我使用的代码,但是VBAUNLOAD在Test宏结束之前被发送到命令行。 (command "-VBARUN" "Test")
(command "vbaunload")
答:主要的问题是你的宏当中有要求用户输入的语句,这时LISP试图执行下一条命令,即VBAUNLOAD。我们需要等待LISP语句执行完毕,或者让LISP在调用VBARUN命令后什么也不做,而让VBA卸载它自己。下面是这两种方法: 1) 在LISP中等待。
(defun c:RunMacro( / oldFileDia oldCmdEcho)
(setq oldFileDia (getvar "FILEDIA")
oldCmdEcho (getvar "CMDECHO")
)
(setvar "FILEDIA" 0)
(setvar "CMDECHO" 0)
(command "_VBALOAD" "c:\\test.dvb")
(command "_-VBARUN" "Test")
(while (= "-VBARUN" (getvar "CMDNAMES"))
(command pause)
)
(command "_VBAUNLOAD")
(setvar "FILEDIA" oldFileDia)
(setvar "CMDECHO" oldCmdEcho)
(princ)
)
2) VBA中自动卸载。
你可以使VBA代码强制卸载它自己。在你的宏的最后(例如:UserForm_Terminate()),使用下列代码可以达到此目的:
AppActivate ThisDrawing.Application.Caption
SendKeys "_VBAUNLOAD" + Chr$(13)
以上的代码在AutoCAD R14.01中工作良好,但是AutoCAD
2000允许加载多个工程。相应地,VBAUNLOAD增加了一个额外参数。有两个新的函数可以加载和运行VBA
代码:(vl-vbaload)和(vl-vbarun)。你可以通过在宏名中指定工程名字把这两种操作联合在一起。
(defun c:RunMacro2000( / oldFileDia oldCmdEcho)
(setq oldFileDia (getvar "FILEDIA")
oldCmdEcho (getvar "CMDECHO")
)
(setvar "FILEDIA" 0)
(setvar "CMDECHO" 0)
(vl-vbarun "c:\\test.dvb!Test")
(while (= "-VBARUN" (getvar "CMDNAMES"))
(command pause)
)
(command "VBAUNLOAD" "c:\\test.dvb")
(setvar "FILEDIA" oldFileDia)
(setvar "CMDECHO" oldCmdEcho)
(princ)
)
第二种方法也需要做一些小的改动。我们可以通过自动接口向AutoCAD发送命令,并且这比SendKeys更安全:
ThisDrawing.SendCommand "_VBAUNLOAD C:\TEST.DVB" + Chr$(13)
如果我们卸载另一个工程,我们可以使用自动接口 (ThisDrawing.Application.UnloadDVB "test.dvb"
)。但是在这种情况下我们需要使用SendKeys或SendCommand来卸载其本身。
 
问:在R13中,我可以通过检查DWK文件知道DWG文件是否被锁定了。在R14中,没有一个ARX函数来检查文件锁定状态。有什么其它办法吗?
答:因为我们现在使用了操作系统支持的文件锁定方式,你可以通过用_fsopen()打开图形文件来检查文件是否锁定。使用模式"r+"和共享标志SH_DENYWR,如果失败,这个图形就已经被打开并且是写的状态。如果成功,千万不要忘记关闭此文件,然后再让AutoCAD打开它。 同时你也需要检查.DWK文件,因为这个文件也可能被另外的R13例程所打开。
2) 用LISP运行一些VBA代码打开这个文件,通过一个系统变量返回一个成功或者失败标志给LISP。例如:下面的VBA代码可以做这件事情。
Sub Test_File_Data()
Dim FileNum As Integer
Dim MyFileName As String
Dim sysVarName As String
Dim sysVarData As Variant
On Error GoTo ErrHandler
FileNum = 1
MyFileName = "D:\PROGRAM FILES\AUTOCAD R14\ARCTEXT.DWG"
sysVarName = "USERI1"
sysVarData = 0
ThisDrawing.SetVariable sysVarName, sysVarData
Open MyFileName For Binary Access Read Lock Read Write As FileNum
Close 1
sysVarData = 1
ThisDrawing.SetVariable sysVarName, sysVarData
Exit Sub
ErrHandler:
MsgBox "Error Number = " & Err.Number
MsgBox "Error Description = " & Err.Description
Err.Clear
sysVarData = 0
ThisDrawing.SetVariable sysVarName, sysVarData
End Sub
 楼主| 发表于 2004-5-11 10:20 | 显示全部楼层
问:有什么方法可以检测一个VBA宏是否加载?
答:在AutoCAD
2000中,你可以获取一个属性名叫VBE的ActiveX应用程序对象。它使你可以访问VBAIDE扩展对象。这个对象拥有方法和属性允许你判断一个工程是否已经加载。 如果你想深入学习,就请启动VBAIDE,添加一个对"Microsoft Visual Basic for Applications
Extensibility"的引用,然后你就可以在你的ObjectBrowser (F2)浏览此对象了。
以下是四个例子。第一个"loadMyProcedure"检测所有已经加载的工程名。如果没有发现"TestMenuEcho",就加载它。
第二个例子"testMacros"在每一个加载的模块中搜索每一行并且在立即窗口中 (cntrl +
G)打印true或者false。目的在于寻找文本"test4"(宏的名字)。
第三个例子"displayLoadedProjects"在信息窗口中显示所有已加载的工程。
第四个例子是一个LISP例程。它使用相同的ActiveX对象判断一个工程是否已经加载,如果没有,就加载它。
Public Sub loadMyProcedure()
Dim int1 As Integer
Dim bProjectLoaded As Boolean
' Iterate through all the projects
For int1 = 1 To Application.VBE.VBProjects.Count
' Make the test boolean variable to true if the Project I want to load
' is already loaded, Change TestMenuEcho to the name of your project
If Application.VBE.VBProjects(int1).Name = "TestMenuEcho" Then
' Debug.Print Application.VBE.VBProjects(int1).Name
bProjectLoaded = True
End If
Next int1
' Display a message if my the project is already loaded
' if it isn't then load it, change the directory and
' name to that of your project
If bProjectLoaded = True Then
MsgBox "TestMenuEcho is already loaded"
Else
MsgBox "Going to load the project TestMenuEcho"
Application.LoadDVB "D:\Vba-apps\a-2000\menuecho in menu.dvb"
End If
End Sub
 
Public Sub testMacros()
Dim int1 As Integer
Dim int2 As Integer
' Iterate through all the loaded projects
For int1 = 1 To Application.VBE.VBProjects.Count
' Name of loaded project
Debug.Print Application.VBE.VBProjects(int1).Name
' Iterate through the text of each module looking for "test4"
For int2 = 1 To Application.VBE.VBProjects(int1).VBComponents.Count
' Get the number of lines in each module - use in the
' find method below
Dim L As Long
L = Application.VBE.VBProjects(int1).VBComponents(int2) _
.CodeModule.CountOfLines
Debug.Print Application.VBE.VBProjects(int1).VBComponents(int2) _
.CodeModule.Find("test4", 1, 1, L, 1, False, False)
Next int2
Next int1
End Sub
 
Public Sub displayLoadedProjects()
Dim strProjectNames
Dim int1 As Integer
strProjectNames = "Names of loaded projects " & vbCrLf
For int1 = 1 To Application.VBE.VBProjects.Count
strProjectNames = strProjectNames + Application.VBE.VBProjects(int1).Name
& vbCrLf
Next int1
MsgBox strProjectNames
End Sub
(defun c:loadMyProject ()
;; This routine will load a project if it is not already loaded
;; the VBE (VB extensibility) ActiveX object is used to reference
;; the loaded projects
;; Load ActiveX
(vl-load-com)
;; Get the VBE extisibility object
(setq acadObject (vlax-get-acad-object))
(setq acadVbe (vla-get-vbe acadObject))
(setq acadVbeProjects (vlax-get-property acadVbe 'VBProjects))
;; Get the number of loaded VBA projects
(setq int1 (vlax-get-property acadVbeProjects 'count))
;; Counter and test variable named loaded
(setq int2 1)
(setq loaded "False")
;; Repeat for each project
(repeat int1
;; Itereate through the projects, getting the name of
;; next project, each time through
(setq Item (vlax-invoke-method acadVbeProjects 'Item int2))
(setq pName (vlax-get-property Item 'Name))
 
;; Test the name for the name of the project I want to load
;; If it is already loaded the set the test variable to True
(if (= pName "my_test_project")
(progn
(prompt "\nmy_test_project is already loaded\n")
(Setq Loaded "True")
)
)
;; Increment the number used to get the next Project
(setq int2 (+ int2 1))
)
;; Load project if it is not already loaded by testing
;; the Loaded variable
(if (= Loaded "False")
(progn
(princ "\nLoading my_test_project")
(command "-VBALOAD"
"D:/vba-apps/a-2000/already loaded test.dvb"
)
)
 
附:我已将所有本文中的VBA和VLISP代码及此文打包成一个ZIP压缩文件。你可以从以下的网址免费下载。
http://china.autodesk.com/support/china.html的‘文件下载’
 楼主| 发表于 2004-5-11 10:21 | 显示全部楼层
AutoCAD开发常见问题AutoCAD开发常见问题(三)
张朝阳 (Bill Zhang)
 
问:我想对一个圆弧进行操作。但是当我运行下面的VBA宏时,出现一个编号为451的运行错误。它的意思是‘对象不是一个集合’。这是一个关于变体型数组(Variant
Array)的常见VBA问题吗?有什么方法可以解决?
Sub showArcPoints()
Dim oEnt As Object
For Each oEnt In ThisDrawing.ModelSpace
If (TypeOf oEnt Is AcadArc) Then
' This causes Runtime error 451 - Object Not a Collection
' if oEnt is not late bound it works ok
MsgBox "StartPoint(0) is =" & oEnt.StartPoint(0)
End If
Next
End Sub
答:当VBA从一个一般对象返回变体型数组的时候,如果这个对象是晚束缚(late
bound)的话,VBA不能通过这个对象的属性返回数组的一个元素。如果这个对象是早束缚(early bound)的话,那么就不受限制。
有两种办法可以解决这个问题。其一、用AcadArc 来对此对象进行早束缚。修改好的代码如下:
Sub showArcPoints()
Dim oEnt As Object
Dim oArc As AcadArc
For Each oEnt In ThisDrawing.ModelSpace
If (TypeOf oEnt Is AcadArc) Then
'This works well since it is early bound.
Set oArc = oEnt
MsgBox "StartPoint(0) = " & oArc.StartPoint(0)
End If
Next
End Sub
其二、声明一个临时的变体型变量并且把它设置为需要操作的对象属性。修改的代码如下:
Sub showArcPoints()
Dim oEnt As Object
For Each oEnt In ThisDrawing.ModelSpace
If (TypeOf oEnt Is AcadArc) Then
'This also works well.
Dim pv_temp As Variant
pv_temp = oEnt.StartPoint
MsgBox "StartPoint(0) = " & pv_temp(0)
End If
Next
End Sub
 楼主| 发表于 2004-5-11 10:21 | 显示全部楼层
问:我想在VBA中使用Microsoft的DAO。如何使用?
答:请注意DAO并不是随VBA提供的。所以首先你必须确认DAO在所有需要它运行的机器上正确安装。并且你得使用相应的Microsoft方法来获得DAO的使用许可,然后才可以使用。你会发现位于Microsoft网站上的这篇文档也许有用: http://msdn.microsoft.com/library/techart/msdn_redistmdac.htm
根据不同版本的DAO安装在不同版本的AutoCAD上,安装程序将覆盖一个MFC
DLL文件MFC42.DLL。这可能引起AutoCAD或者其他的应用程序的一些问题。所以请小心对待。如果你已经正确安装了DAO,下列的VBA代码应该运行良好。这是一个用VBA在AutoCAD中访问Microsoft
Access MDB数据库的例子。
Private Sub CommandButton1_Click()
Dim daoWs As Workspace
Dim daoDb As Database
Dim daoRs As Recordset
Dim daoFields As Fields
Dim recordValue As String
' Create a DAO workspace object
Set daoWs = CreateWorkspace("", "admin", "", dbUseJet)
' Open a MDB file (and get a database object)
Set daoDb = daoWs.OpenDatabase("")
' Get a recordset from the database
Set daoRs = daoDb.OpenRecordset("")
' Move to the first record in this set
daoRs.MoveFirst
' Get all fields from the first record
Set daoFields = daoRs.Fields
' Get the value from one field.
' For the index you can use an integer
' or the name of the table field.
recordValue = daoFields("")
MsgBox ("Value: " & recordValue)
'
' Close every DAO object
'
' Close the recordset object
daoRs.Close
' Close the database object
daoDb.Close
' Close the workspace object
daoWs.Close
End Sub
问:我怎样在AutoCAD中调用具有参数的VBA函数?我知道VB/A宏没有参数。Microsoft就是这样设计的。然而,VB/A函数可以带参数。我想知道是否存在命令行或者LISP的一种途径来调用VBA函数以便从AutoCAD传递必需的参数。 答:在AutoCAD R14中, 这是不可能的。但是在AutoCAD
2000利用VBASTMT命令可以完成这项任务。这种方法仅当所调用的函数(f_test)定义在一个VBA模块中,而不是在ThisDrawing对象中有效。以下的例子说明如何具体去做。这个函数需要一个字符串参数。 Function f_test(ByVal sCommand As String)
MsgBox "This was sent from the AutoCAD Command Line: " & sCommand
End Function
在AutoCAD命令行,用VBASTMT命令。
Command: vbastmt
Expression: f_test "line 1,1 5,5 "
或者用以下的LISP代码:
(command "vbastmt" "f_test \"line 1,1 5,5 \"")
问:块(Block)对象的AddDimAligned方法创建不正确的标注(Dimension)对象。我怎样才能正确地添加一个标注(Dimension)实体到一个块(Block)对象中? 答:块对象的AddDimAligned方法和其它的AddDimxxx方法导致添加的标注实体不正确。这是已知的一个AutoCAD缺陷。然而,下面的方法可以克服这个缺陷。首先,在模型空间中生成一个标注实体,拷贝这个实体到所需块对象中,最后,删掉原始的标注实体。以下的事例代码生成一个块"test",然后添加了一个DimRotated实体到块中,最后把这个块插入到模型空间中。 Sub f_SolAddDiminBlocks()
'Work around for Adding dimensions to block AutoCAD 2000
Dim po_rotDim As AcadDimAligned
Dim po_block As AcadBlock
Dim pd_ext1(0 To 2) As Double
Dim pd_ext2(0 To 2) As Double
Dim pd_lineLoc(0 To 2) As Double
Dim po_array(0) As Object
pd_ext1(0) = 3: pd_ext1(1) = 3: pd_ext1(2) = 0
pd_ext2(0) = 10: pd_ext2(1) = 3: pd_ext2(2) = 0
pd_lineLoc(0) = 5: pd_lineLoc(1) = 4: pd_lineLoc(2) = 0
'create dimeionsion object
Set po_rotDim = ThisDrawing.ModelSpace.AddDimAligned(pd_ext1, pd_ext2,
pd_lineLoc)
'create a new block by name test
Set po_block = ThisDrawing.Blocks.Add(pd_ext1, "test")
'insert a block reference
ThisDrawing.ModelSpace.InsertBlock pd_ext1, "test", 1, 1, 1, 0
'copy dimension object
Set po_array(0) = po_rotDim
ThisDrawing.CopyObjects po_array, po_block
po_rotDim.Delete
'release the references
Set po_block = Nothing
Set po_rotDim = Nothing
End Sub
问:怎样才能获得当前配置的AutoCAD绘图仪列表?
答:下面的VBA函数列举出所有的PC3的绘图仪。你可以在你的应用程序中使用它。
Public Function GetPlotters() As Collection
Set GetPlotters = New Collection
Dim strPlotter As String
strPlotter = Dir(Application.Preferences.Files.PrinterConfigPath + "\*.pc3")
While Not strPlotter = ""
GetPlotters.Add strPlotter
strPlotter = Dir
Wend
End Function
有一个方法用来枚举所有的系统打印机。这些打印机在AutoCAD的绘图对话框中也可以使用。请参看Microsoft知识库文档: Q166008 在以下的网页:
发表于 2013-12-29 21:19 | 显示全部楼层
有什么方式可以
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-4-26 05:12 , Processed in 0.292374 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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