zzyong00 发表于 2015-4-26 00:57:12

vba/vb取得autocad对象的组码对应值

本帖最后由 zzyong00 于 2015-4-26 01:02 编辑

众所周知,vba/vb6二次开发autocad插件,都是基于autocad的对象模型,对象模型中给出大部分autocad的对象类型,但并不是全部,比如,有个对象是AcDbWipeoutVariables,vba中没有给出对应的对象,而它的70组码控制着wipeout的边框是否显示,在autocad2013以后的版本,有一个系统变量WIPEOUTFRAME控制着wipeout的边框是否显示,但在autocad2013以前的版本,却没有这个变量。用vba编程时,很难知道当前图的wipeout边框是否显示!但用lisp却很容易知道,详见:http://bbs.xdcad.net/thread-4040-1-1.html,造成这个问题的关键原因是,vba不能直接获取对象的组码值。用vba编写autocad插件,一般很少用到组码,只有选择实体时能用到,还有就是getxdata和setxdata函数,可以获取和设置1000以上组码值。而对于选择,autocad只能选择实体,像AcDbWipeoutVariables,属于词典类型(但不能把赋值给dictionary类型的变量),无法选择!也就是说,无法通过选择来判断组码的值!用vba/vb做这事儿,真是无能为力(我认为)!好在,有vlax.cls类,使得vba/vb可以调用lisp,这使得vba/vb取得autocad对象的组码对应值成为可能!经过我多次测试,把代码写出来,看起来也非常简单:

'工程中加载vlax.cls,如没有可从明经通道可以下载到
''By zzyong00
''2015.04.26
Public Function GetEntDxf(ByVal handle As String, ByVal DxfCode As Long)
    Dim objVLAX As VLAX
    Set objVLAX = New VLAX
    Dim retval
    With objVLAX
      '.EvalLispExpression "(setq retval (cdr (assoc '" & DxfCode & " (entget (handent " & Chr(34) & handle & Chr(34) & ")))))"
      .SetLispSymbol "handle", handle
      .EvalLispExpression "(setq retval (cdr (assoc '" & DxfCode & " (entget (handent handle)))))"
      retval = .GetLispSymbol("retval")
      .NullifySymbol "handle", "retval"
    End With
    GetEntDxf = retval
End Function

调用以上GetEntDxf,获取wipeout的边框是否显示:

Dim d As AcadObject
Dim obj As AcadObject
    For Each d In ThisDrawing.Dictionaries
      If d.ObjectName = "AcDbWipeoutVariables" Then
            Set obj = d
'            Debug.Print obj.handle
            Exit For
      End If
    Next
    If obj Is Nothing Then Exit Sub
    Dim ret1 As Long
    ret1 = CLng(GetEntDxf(obj.handle, 70))‘取得组码为70对应的值
    MsgBox ret1

GetEntDxf只能用于组码对应值为一个简单值的情况,如组码对应值为关联表,哪就不行。而在我实际测试过程中,发现vlax.cls也无法对返回值为关联表的函数正确执行,找了很多资料,都没能解决!如下面代码,是设置AcDbWipeoutVariables的70组码值为1的,用到subst 和entmod,都返回关联表的,用vlax.cls始终无法正确执行!好在这里不需要返回值,于是就用sendcommand了
Dim d As AcadObject
Dim obj As AcadObject
    For Each d In ThisDrawing.Dictionaries
      If d.ObjectName = "AcDbWipeoutVariables" Then
            Set obj = d
'            Debug.Print obj.handle
            Exit For
      End If
    Next
    If obj Is Nothing Then Exit Sub
    ThisDrawing.SendCommand "(entmod (subst '(" & "70" & " . " & "1" & ") (assoc " & "70" & " (entget (handent " & Chr(34) & obj.handle & Chr(34) & "))) (entget (handent " & Chr(34) & obj.handle & Chr(34) & ")))) "
    ThisDrawing.Regen acAllViewports




本人写个帖子,是由于这个同学的启示而写的:http://bbs.mjtd.com/thread-113374-1-1.html

希望能对他也有点帮助!

zzyong00 发表于 2015-4-26 01:23:43

另外,本论坛的efan2000给出了用LastPrompt系统变量取组码的方法!
http://bbs.mjtd.com/forum.php?mod=redirect&goto=findpost&ptid=19897&pid=101902

lennie 发表于 2015-4-29 13:39:12

lennie 发表于 2015-4-29 14:17:55

本帖最后由 lennie 于 2015-4-29 14:32 编辑

程序精简了一下:Public Function WipeOutFrame() As Boolean   '返回wipout边界是否打开的状态,打开返回True
    Dim obj As Object
    For Each obj In ThisDrawing.Dictionaries
      If obj.ObjectName = "AcDbWipeoutVariables" Then
            WipeOutFrame = CBool(GetDXFCodeValue(obj, 70))
      End If
    Next
End Function这里用到一个修改后的函数 GetDXFCodeValue:Public Function GetDXFCodeValue(Ent As Object, gCode As Integer) As Variant
    Dim retval
    Dim obj As New CL
      retval = obj.EvalLispExpression("(cdr (assoc " & gCode & " (entget (handent " & Chr(34) & Ent.Handle & Chr(34) & "))))")
      GetDXFCodeValue = retval
      Set obj = Nothing
End Function另外,用SendCommand的方法命令窗口会跳出一堆文字,毕竟不美观。以下是我来获取天正对象坐标(组码10)的函数:Function GetDxfPoint(Ent As Object, gCode As Integer) As Variant
    Select Case TypeName(Ent)
      Case "IComSymbElev", "IComLineText", "IComSpace"
            Dim retval
            Dim aPoint(2) As Double
            Dim obj As New CL
            retval = obj.EvalLispExpression("(car(cdr (assoc " & gCode & " (entget (handent " & Chr(34) & Ent.Handle & Chr(34) & ")))))")
            aPoint(0) = retval
            retval = obj.EvalLispExpression("(car (cdr (cdr (assoc " & gCode & " (entget (handent " & Chr(34) & Ent.Handle & Chr(34) & "))))))")
            aPoint(1) = retval
            retval = obj.EvalLispExpression("(car (cdr (cdr (cdr (assoc " & gCode & " (entget (handent " & Chr(34) & Ent.Handle & Chr(34) & ")))))))")
            aPoint(2) = retval
            GetDxfPoint = aPoint
            Set obj = Nothing
      Case "IAcadText", "IAcadMText"
            GetDxfPoint = Ent.InsertionPoint
    End Select
End Function

lennie 发表于 2015-4-29 14:38:06


找到这个字典以后,监视窗口里对象居然是空白的。

VB局限性太大了,而且64位CAD的话原来做的Dll文件都不能用了。好处是采用后绑定的方法可以通吃多个CAD版本。这里要鄙视微软,鄙视自动桌子。

zzyong00 发表于 2015-4-29 14:41:57

本帖最后由 zzyong00 于 2015-4-29 14:49 编辑

现在用vlax.cls,可以读取实体的组码了,但是,修改实体组码时,还是会有一些问题,如以下lsp
"(entmod (subst '(" & "70" & " . " & "1" & ") (assoc " & "70" & " (entget (handent " & Chr(34) & obj.handle & Chr(34) & "))) (entget (handent " & Chr(34) & obj.handle & Chr(34) & ")))) "
就无法用vlax.cls执行,不得以只好用SendCommand了

lennie 发表于 2015-4-29 15:33:37

lennie 发表于 2015-4-29 14:38 static/image/common/back.gif
找到这个字典以后,监视窗口里对象居然是空白的。

VB局限性太大了,而且64位CAD的话原来做的Dll文件都 ...

dll里面涉及object对象作为参数传递 基本上都有问题。

zzyong00 发表于 2015-4-29 15:42:10

http://bbs.mjtd.com/thread-111871-1-1.html
你看看我哪个帖子里的dll,就是传对象进去,一点问题没有

zzyong00 发表于 2015-4-29 15:43:07

还有这个http://bbs.mjtd.com/thread-113517-1-1.html

yyzhan12 发表于 2015-12-11 22:11:44

'工程中加载vlax.cls,如没有可从明经通道可以下载到
''By zzyong00
''2015.04.26

方便给出vlax.cls的下载链接吗?没搜索
页: [1] 2
查看完整版本: vba/vb取得autocad对象的组码对应值