PDA

View Full Version : Inserting Blocks with VBA...



frostrap
20th May 2008, 12:38 am
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

ASMI
20th May 2008, 07:27 am
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

ska67can
20th May 2008, 01:45 pm
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

ASMI
20th May 2008, 01:50 pm
> ska67can

Read first post


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

LCE
20th May 2008, 02:07 pm
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...

frostrap
21st May 2008, 01:21 am
I think I'm going to end up fudging it as LCE suggests.

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

SEANT
21st May 2008, 11:40 am
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?

frostrap
21st May 2008, 08:36 pm
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?

LCE
21st May 2008, 08:40 pm
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.

SEANT
21st May 2008, 09:13 pm
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

LCE
21st May 2008, 09:36 pm
Sorry, I missed that it was 04 being used.

Raggi_Thor
24th May 2008, 11:06 pm
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"

SEANT
26th May 2008, 10:55 am
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

Raggi_Thor
27th May 2008, 10:51 am
Thanks. Great :-)

frostrap
29th May 2008, 01:03 am
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

SEANT
29th May 2008, 10:26 am
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.

frostrap
7th Jun 2008, 02:13 am
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.

Raggi_Thor
9th Jun 2008, 08:20 pm
(command "-insert" "blockname=filename")

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

frostrap
21st Jun 2008, 05:26 am
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

SEANT
22nd Jun 2008, 01:05 pm
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.

frostrap
23rd Jun 2008, 02:52 am
Jigging eh?

I read the EULA info. Technically it looks like you can install the same licence on up to two computers. One licence at work and the other at home, only if used by the same person, and not at the same time.

I don't really know beyond that how AutoDesk tracks that sort of thing for compliance.

Do you know anything about that?

Joe

Lukijan
12th Jul 2012, 07:27 am
Well, I have an issue with ThisDrawing.SendCommand... it gives Runtime error '424' : Object required

Any ideas? Thanx