Jump to content

Inserting Blocks with VBA...


frostrap

Recommended Posts

I've been looking but haven't found a solution to this one yet.

 

This may be hard to explain, so I'm going to throw some code out there, and hopefully someone can help me out.

 

Please ask questions and I'll clarify as needed.

 

Essentially this code initiates the insertion of a block, but only predetermines the scale, leaving the insertion point and rotation up to the user to determine.

 

I need the user to be able to visually rotate the block on screen before completing the insertion.

 

Is there any way of accomplishing what the following code does, in vba without using the .sendcommand method (perhaps with an insertblock method)?

 


ThisDrawing.SendCommand "-insert" & vbCr & thePath & vbCr & "S" & vbCr & theScale & vbCr

I can send the rest of the Sub if you would like to see it.

 

There are several reasons why I need to do this, I'll explain more as people ask... that way I wont have to write a larger book than I already have!

 

Thanks for everything

 

Joe

Link to comment
Share on other sites

  • Replies 21
  • Created
  • Last Reply

Top Posters In This Topic

  • frostrap

    7

  • SEANT

    5

  • Raggi_Thor

    3

  • LCE

    3

I think you cannot to do it without SendCommand (I can be wrong). Try something like this to complete your expression and continue of program execution:

 

ThisDrawing.SendCommand "(command " & Chr(34) & "._-insert" & Chr(34) & vbCr & Chr(34) & thePath & _
                         Chr(34) & " pause" & vbCr & Chr(34) & "1" & Chr(34) & vbCr & Chr(34) & theScale & Chr(34) & _
                         vbCr & Chr(34) & " pause" & Chr(34) & ")" & vbCr

Link to comment
Share on other sites

how about something like this:

 

Dim oBlock As AcadBlockReference
Dim Pt1 As Variant
Dim iAngle As Double

Pt1 = ThisDrawing.Utility.GetPoint(, "Select Basepoint: ")
iAngle = ThisDrawing.Utility.GetAngle(Pt1, "Select Rotation Angle: ")
Set oBlock = ThisDrawing.ModelSpace.InsertBlock(Pt1, thePath, 1#, 1#, 1#, iAngle)

 

ska

Link to comment
Share on other sites

> ska67can

 

Read first post

 

I need the user to be able to visually rotate the block on screen before completing the insertion.
Link to comment
Share on other sites

You could fudge it.

Insert the block first, then use move to set the insertion point, and rotate with reference to set the angle...

Then confirm it and it will keep the block, else delete it...

Like I said, fudging it...

Link to comment
Share on other sites

I think I'm going to end up fudging it as LCE suggests.

 

ska, how does "._-insert" differ from "-insert"?

Link to comment
Share on other sites

The “.” preceding a command will force Autocad to use its own core command. This feature is there because it is possible to redefine a command of a given name.

 

As a matter of fact it may be just what’s required if the situation described here:

 

http://www.cadtutor.net/forum/showthread.php?t=23403

 

is the problem at hand. Normally, employing that “SendCommand” configuration does not modify the FILEDIA variable; is it possible that the INSERT command has been redefined on your setup?

Link to comment
Share on other sites

I've looked through the lisp files that could contain a redefinition of insert and also have looked at the command alias's, but didn't find anything.

 

Actually, the reason I'm searching for alternatives to the insert command are not directly related to the mysterious filedia problem from the other post.

 

There are two reasons that I was looking to not use sendcommand.

 

One: I need the blocks being inserted to be inserted on a layer other than the current default layer. To accomplish this, I was temporarily changing the default layer to the insertion layer, inserting the block, then changing the default layer back to the original layer. Unfortunately, this isn't always working. If, after the insert command is issued, but before the block is inserted, the user tries to pan, AutoCAD resets the default layer to the original layer, away from the layer that I want the block to go on. To resolve this I will just change the block's layer after it's been inserted, rather than initially changing the layer that the block is being put on.

 

Two: This VBA program is initiated by a small lisp routine. This allows the user to initialize the macro via the command line command "TTY". Once the user is done inserting the block they want, the VBA program closes. When the user hits enter (if TTY was the last command typed) AutoCAD should run the TTY command, and launch the block manager. Unfortunately, if I have issued a command (such as "._-insert") in the VBA code, AutoCAD will recognize that command as the last command instead of "TTY", so the user, expecting to relaunch the block manager, unintentionally launches the insert command.

 

I have a workaround for this in my mind, but haven't tested it yet, and was hoping to get some more suggestions from the folks on here.

 

That was a mouthful! Any other ideas?

Link to comment
Share on other sites

I would strongly advise that you look into the use of VB.NET, rather than VBA as it will help with a lot of what you have explained above. No need to run it from a lisp as the command is defined in the vb.net app. and you can call commands without sending them to the command line. So the last command would be your defined command, rather than any that you call from your app.

Link to comment
Share on other sites

Using .NET is good advice – unfortunately 2004 predates that API.

 

Is “dynamic feedback” actually that important? Sure, it would be nice but withholding that bit of eye candy to avoid SENDCOMMAND seems worth it.

 

Something like this may give sufficient reference:

 

 

Sub InsertWithReference()
Dim varInsertPt As Variant
Dim varInsertPtTran As Variant
Dim entInsert As AcadBlockReference
Dim dblOr(2) As Double
Dim dblX(2) As Double
Dim dblZ(2) As Double
Dim varZ As Variant
Dim varX As Variant
Dim dblAngle As Double
Dim entRay As AcadRay
  dblX(0) = 1#
  dblZ(2) = 1#
  With ThisDrawing
     varZ = .Utility.TranslateCoordinates(dblZ, acUCS, acWorld, 1)
     varInsertPt = .Utility.GetPoint(, "Insertion Point: ")
     varInsertPtTran = .Utility.TranslateCoordinates(varInsertPt, acWorld, acUCS, 0)
     varX = .Utility.TranslateCoordinates(dblX, acOCS, acUCS, 1, varZ)
     dblAngle = .Utility.AngleFromXAxis(dblOr, varX)
     varX(0) = varInsertPtTran(0) + 1
     varX(1) = varInsertPtTran(1)
     varX(2) = varInsertPtTran(2)
     Set entInsert = .ModelSpace.InsertBlock(varInsertPt, "A", 1#, 1#, 1#, -dblAngle)'adjust block name as needed
     Set entRay = .ModelSpace.AddRay(varInsertPt, .Utility.TranslateCoordinates(varX, acUCS, acWorld, 0))
     entRay.Highlight True
     varX = .Utility.GetPoint(varInsertPtTran, "Adjust angle: ")
     varInsertPtTran = .Utility.TranslateCoordinates(varInsertPt, acWorld, acOCS, 0, varZ)
     varX = .Utility.TranslateCoordinates(varX, acWorld, acOCS, 0, varZ)
     dblAngle = .Utility.AngleFromXAxis(varInsertPtTran, varX)
     entInsert.Rotation = dblAngle
     entRay.Delete
  End With
End Sub

Link to comment
Share on other sites

I am having trouble updating a block from file without using SendCommand.

Even if I supply if full filename in the InsertBlock method AutoCAd (2208) will use the local compy.

So I have to do a "SendCommand blkname=blkaname"

Link to comment
Share on other sites

I am having trouble updating a block from file without using SendCommand.

Even if I supply if full filename in the InsertBlock method AutoCAd (2208) will use the local compy.

So I have to do a "SendCommand blkname=blkaname"

 

The general method shown below will update the geometry of a block. Extra steps would be required if attached Attributes are also modified.

 

Make note of the line:

 

Set ACDbx = ThisDrawing.Application.GetInterfaceObject("ObjectDBX.AxDbDocument.16") 'set to appropriate version

 

in the attached code.

 

Sub SetBlocks() 'Change as required
Dim strPath As String
Dim strBlockName As String
Dim objBlock As AcadBlock
  strBlockName = "Tester"
  strPath = "C:\"
  BlockRedefine strBlockName, strPath
End Sub

Private Sub BlockRedefine(strBlockName As String, strPath As String)
Dim strFullDef As String
Dim objBlock As AcadBlock
Dim entEnt As AcadEntity
  On Error GoTo BlockNotAvailable
  Set objBlock = ThisDrawing.Blocks.Item(strBlockName)
  On Error GoTo 0
  For Each entEnt In objBlock
     entEnt.Delete
  Next
  strFullDef = strPath & strBlockName & ".dwg"
  DbxTransfer strFullDef, objBlock
  For Each entEnt In objBlock
     entEnt.Update
  Next
  For Each entEnt In ThisDrawing.ModelSpace
     entEnt.Update
  Next
     For Each entEnt In ThisDrawing.PaperSpace
     entEnt.Update
  Next
BlockNotAvailable:
End Sub

Private Sub DbxTransfer(strFullFile As String, objBlock As AcadBlock)
Dim entEntities() As Object
Dim varReturn As Variant
Dim ACDbx As AxDbDocument
Dim intCount As Integer
  Set ACDbx = ThisDrawing.Application.GetInterfaceObject("ObjectDBX.AxDbDocument.16") 'set to appropriate version
  ACDbx.Open strFullFile
  intCount = ACDbx.ModelSpace.Count
  ReDim entEntities(intCount - 1)
  For intCount = 0 To ACDbx.ModelSpace.Count - 1
     Set entEntities(intCount) = ACDbx.ModelSpace.Item(intCount)
  Next
  ACDbx.CopyObjects entEntities, objBlock
End Sub

Link to comment
Share on other sites

One of the reasons that i want to be able to envoke the insert command without using a command is because I don't want autocad to recall "-insert" as the last command that was used.

 

Since it looks like the only way to get dynamic feedback is by envoking the insert command, is there any way to effectively change what autocad recalls was the last command used?

 

I don't think there's a way to do this using just VBA, but perhaps Lisp or Vlisp has some answer?

 

Since I don't know C++ and there's no .Net API for r16, ARX options are probably out of the picture for the time being. Unless you think the switch from VBA to C++ is one that could be made without too much craziness.

 

There must be a solution for this because I've seen this done by a program that already exists (i'm trying to reverse engineer portions of it).

 

Thanks again.

 

joe

Link to comment
Share on other sites

I would imagine any of those other language options would accomplish the task more easily than VBA. Quite frankly, with Dynamic Feedback and Command Line interaction, you are dealing with two of VBA’s most celebrated shortcomings.

 

The drawback to employing one of the other options is the overhead dealing with the mixed code base – if you plan on maintaining your existing VBA code. Not insurmountable, I understand, but no doubt a PITA.

Link to comment
Share on other sites

  • 2 weeks later...

Is there any way to do what I'm looking to do in VisualLisp?

 

The program I'm using as a model to improve upon seems to be a compiled vlx file, and it is capable of handling dynamic insertions... there must be a way to do what I'm looking to do.

Link to comment
Share on other sites

(command "-insert" "blockname=filename")

 

I always mix the order of blockname and filename, but you have the method there.

Link to comment
Share on other sites

  • 2 weeks later...

Well, in order to solve a few issues, I ended up passing the filename/path, and a slew of other variables to a lisp routine via the "USER**" variables.

 

That routine picks up where the VBA falls short and handles the ghosting and whatnot just great. I had to get a little tricky with the NOMUTT variable to get things to look right, but it seems to work like a charm.

 

Am I right in assuming that vb.net or C++ would have been able to do the ghosting without scripting the .-insert command via Lisp?

 

Thanks for all of your help!

 

Joe

Link to comment
Share on other sites

JIGGING is the .Net term for ghosting. Jigs allow .net the ability to display temporary graphics before commiting the elements to the drawing database.

 

In the case of block insertion, I believe Autodesk.AutoCAD.EditorInput.DrawJig or

Autodesk.AutoCAD.EditorInput.EntityJig would be the ticket.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...