Attribute

Attribute

smichels
Enthusiast Enthusiast
1,407 Views
19 Replies
Message 1 of 20

Attribute

smichels
Enthusiast
Enthusiast
Can anyone help me with this?

I’m trying to fill one attribute tag from another attribute tag within the same dwg and having no luck!

I have no code, not sure were to start.
I would like to fill out SHT_TTL_L2 attribute tag in ford_a1 block with description attribute tag in det. callout block.
Attached is the dwg test.dwg

Any help would be appreciated greatly!
0 Likes
1,408 Views
19 Replies
Replies (19)
Message 2 of 20

HJohn1
Advocate
Advocate
Take a look at
{code}ThisDrawing.Utility.GetSubEntity{code} Retrieve the TextString of the selected AttributeRef. and set the TextString of the target AttributeRef. Hope it helps.
0 Likes
Message 3 of 20

smichels
Enthusiast
Enthusiast
Thanks,
Its a good start! I will read up on that!
0 Likes
Message 4 of 20

smichels
Enthusiast
Enthusiast
Having no luck with the GetSubEntity example in autocad 2008 developer help files!
I dont understand vb enough to do what Im looking for. Also search the discussion groups for an example with no luck.
Any clue to were I might find further help with this?

Thanks

Steve
0 Likes
Message 5 of 20

HJohn1
Advocate
Advocate
{code}I dont understand vb enough to do what Im looking for{code}
It is very hard to do something if you don't understand what you are doing. My suggestion, learn the basics first, get to know the ActiveX object model. Build more complex solutions as you get more experience. Here a simple example to get you started, note there is not error handling. Hope it helps.
{code}
Public Sub CopyAttTest()
Dim AttObj As AcadAttributeReference
Dim TransMatrix As Variant
Dim ContextData As Variant
Dim ent As AcadEntity
Dim str As String
Dim pt As Variant

ThisDrawing.Utility.GetSubEntity ent, pt, TransMatrix, ContextData, "Command: Select source attribute: "

Set AttObj = ent
str = AttObj.TextString

ThisDrawing.Utility.GetSubEntity ent, pt, TransMatrix, ContextData, "Select target attribute: "

Set AttObj = ent

AttObj.TextString = str
AttObj.Update

End Sub

{code}

What this does is that it allows to copy the content of the textstring in one attribute to another by selecting the attribute source and then the target attribute.
0 Likes
Message 6 of 20

smichels
Enthusiast
Enthusiast
HJohn1

Yes I agree...I have to start with the basics!

Are AutoCAD 2008 developers help files a good place to learn ActiveX object model?

Thanks for your help and the example code!

Steve
0 Likes
Message 7 of 20

HJohn1
Advocate
Advocate
Yes, absolutely. For me the developer help files have been the best material to get to know the ActiveX Object Model for AutoCAD. There might be things that are not fully documented or a bit obscure, but generally is your best bet. Also note that sometimes you need to learn general VB programming techniques that have nothing to do with AutoCAD, in this forum and the web you will find most of it. Finally, If I had to learn AutoCAD customization, I would skip AutoCAD VBA all together and go straight to .NET.
0 Likes
Message 8 of 20

arcticad
Advisor
Advisor
Here is some code that uses the getXX class Library. I've attached the library file.
I've made some small changes to return "ENTER" from the original.

If you want the original it's available here.
http://ingp.ca/index.php?en.SolCAOGetXX
http://dinardiengineering.com/downloads/autodesk.php

---------------------------------------------------------

Simply copy the Attached file into a new class file and call it GetXX

This code will let you pick an attribute and paste it multiple times into another block.
It will exit when you press ESC.

Then use this code in your module.

{code}
Public Sub CopyAtt()

Dim attSource As AcadAttributeReference
Dim attDest As AcadAttributeReference

If getAttribute("Select Source Attribute: ", attSource) Then
While getAttribute("Select Target Attribute: ", attDest)
attDest.TextString = attSource.TextString
attDest.Update
Wend
End If

End Sub


Function getAttribute(ByVal strPrompt As String, ByRef AttObject As AcadAttributeReference) As Boolean

Dim pt As Variant
Dim strHandle As String
Dim attText As String

strHandle = GetSubEntity(strPrompt, pt)

If Not UCase(strHandle) = UCase("ENTER") Then
Set AttObject = ThisDrawing.HandleToObject(strHandle)
If Not TypeOf AttObject Is AcadAttributeReference Then
Call getAttribute(sttprompt, AttObject)
Else
getAttribute = True
Exit Function
End If
End If

End Function

Function GetSubEntity(prompt As String, ByRef pt) As String
Dim GetXX As New GetXX
Dim lError As Long
Set GetXX.Application = Application
GetSubEntity = GetXX.GetSubEntity(lError, pt, , , prompt)

End Function

{code}
---------------------------



(defun botsbuildbots() (botsbuildbots))
0 Likes
Message 9 of 20

smichels
Enthusiast
Enthusiast
Thanks for the suggestions on ActiveX and .Net. I did try your example code in my app and it worked only if the acad.dwg is open, also I added acaddoc.save () after AttObj.Update(). Without acaddoc.save () it would change the attribute then reset to the original value.

I think im using your example for the wrong application. What I would like to accomplish is to batch multiple acad dwgs, instead of manually picking the source and target attribute in each dwg.

Is there a way to alter your example and use it in my app to batch multiple dwgs automatically?

Attached is my code!

Thanks
Steve
0 Likes
Message 10 of 20

arcticad
Advisor
Advisor
You will need to use ObjectDBX to open the drawing
be sure and check if the file is in use before opening it.

{code}

Public Function getOdbx(ByRef acadApp As Autodesk.AutoCAD.Interop.AcadApplication, ByRef acadDBX As Object, ByVal FileName As String)

Try
acadDBX = acadApp.GetInterfaceObject("ObjectDBX.AxDbDocument.17")
Catch ex As exception
MessageBox.Show("Error Connecting to AutoCAD", "Autocad Message", MessageBoxButtons.OK, MessageBoxIcon.Stop)
End Try

Try
acadDBX.Open(Filename)

' do stuff

acadDBX.saveas(FileName)

Return True
Catch ex As Exception
Return False
End Try

End Function

Public Function isFileInUse(ByVal sFile As String) As Boolean

If System.IO.File.Exists(sFile) Then
Try
Dim F As Short = FreeFile()
FileOpen(F, sFile, OpenMode.Binary, OpenAccess.ReadWrite, OpenShare.LockReadWrite)
FileClose(F)
Catch

Return True
End Try
End If
End Function

{code}
---------------------------



(defun botsbuildbots() (botsbuildbots))
0 Likes
Message 11 of 20

smichels
Enthusiast
Enthusiast
I apologize but I’m confused ...I’m not sure how to use the code you posted with my application below.
Is it possible to use GetSubEntity without user input?


Imports Autodesk.AutoCAD.Interop
Imports System.Data.Common
Imports Autodesk.AutoCAD.Interop.Common

Public Class Form1

Public WithEvents AcadApp As Autodesk.AutoCAD.Interop.AcadApplication
Dim acadDoc As Autodesk.AutoCAD.Interop.AcadDocument

Public Sub GetAcadApplication()
Try
AcadApp = GetObject(, "AutoCAD.Application.17.1")
AcadApp.Visible = True
Catch
Try
AcadApp = CreateObject("AutoCAD.Application.17.1")
AcadApp.Visible = True
Catch ex As Exception
MsgBox(ex.ToString, MsgBoxStyle.Critical)
Exit Sub
End Try
End Try
End Sub

Private Sub RetrieveDwgs_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RetrieveDwgs.Click
Dim openFileDialog1 As New OpenFileDialog()
Try
openFileDialog1.InitialDirectory = "j:\"
Catch
openFileDialog1.InitialDirectory = "c:\"
End Try
openFileDialog1.Filter = "dwg files (*.dwg)|*.dwg"
openFileDialog1.FilterIndex = 2
openFileDialog1.RestoreDirectory = True
openFileDialog1.Multiselect = True
If openFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
Dim count As Integer = openFileDialog1.FileNames.Length.ToString
Dim I
For I = 0 To count - 1
ListBox1.Items.Add(openFileDialog1.FileNames.GetValue(I).ToString)
Next
End If
End Sub

Private Sub ClearList_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearList.Click
ListBox1.Items.Clear()
End Sub

Private Sub ListBox1_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles ListBox1.MouseDoubleClick
ListBox1.Items.Remove(ListBox1.SelectedItem)
End Sub

Sub ProcessDirectory(ByVal targetDirectory As String)
Dim fileEntries As String() = System.IO.Directory.GetFiles(targetDirectory)
Dim fileName As String
For Each fileName In fileEntries
If LCase(System.IO.Path.GetExtension(fileName)) = ".dwg" Then
ListBox1.Items.Add(fileName)
End If
Next fileName
Dim subdirectoryEntries As String() = System.IO.Directory.GetDirectories(targetDirectory)
Dim subdirectory As String
For Each subdirectory In subdirectoryEntries
ProcessDirectory(subdirectory)
Next subdirectory
End Sub

Private Sub WholeDirectory_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles WholeDirectory.Click
If FolderBrowserDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
ProcessDirectory(FolderBrowserDialog1.SelectedPath)
End If
End Sub

Private Sub Go_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Go.Click
If ListBox1.Items.Count < 1 Then
MsgBox("You haven't selected any drawings to process.", MsgBoxStyle.Information, "Totals")
Exit Sub
End If
Call GetAcadApplication()
Dim I
Dim R As Integer = 0
Dim DwgName As String = ""
For I = 0 To ListBox1.Items.Count - 1
Try
acadDoc = AcadApp.ActiveDocument
Catch
'acadDoc = AcadApp.Documents.Add
End Try
DwgName = ListBox1.Items.Item(0)
ProcessDwg(DwgName)
Try
acadDoc.Close(False, DwgName)
Catch ex As Exception
'MsgBox("Some Error closing the drawing." & vbCrLf & ex.ToString)
End Try
ListBox1.Items.RemoveAt(0)
R = R + 1
Next
MsgBox("Processed " & R & " Drawings")
End Sub
Dim TransMatrix As Object
Dim ContextData As Object
Dim ent As AcadEntity
Dim str As String
Dim pt As Object
Dim attSource As AcadAttributeReference
Dim attDest As AcadAttributeReference
Sub ProcessDwg(ByVal ThisDwg As String)
acadDoc.Application.Documents.Open(ThisDwg)
acadDoc = AcadApp.ActiveDocument

Dim AttObj As AcadAttributeReference

acadDoc.Utility.GetSubEntity(ent, pt, TransMatrix, ContextData, "Command: Select source attribute: ")

AttObj = ent
str = AttObj.TextString

acadDoc.Utility.GetSubEntity(ent, pt, TransMatrix, ContextData, "Select target attribute: ")

AttObj = ent

AttObj.TextString = str
AttObj.Update()
acadDoc.Save()
'acadDoc.Close()
End Sub

End Class


Confused!!!!
0 Likes
Message 12 of 20

arcticad
Advisor
Advisor
You can search though the drawing, find the block, find the Attibute tag and set the text.
without opening the file in the editor.

{code}

Public Sub SetAttribute(ByVal strFileName As String)

Dim strAttTag As String = "SHT_TTL_L2"
Dim strAttText As String = "Some Text"
Dim strBlockName As String = "Ford_A1"

If Not isFileInUse(strFileName) Then

Try
Dim acApp As Autodesk.AutoCAD.Interop.AcadApplication = GetObject(, "AutoCAD.Application.17.2")
Dim doc As AxDbDocument = acApp.GetInterfaceObject("ObjectDBX.AxDbDocument.17")
doc.Open(strFileName)

For Each obj As AcadEntity In doc.ModelSpace
If TypeOf obj Is AcadBlockReference Then
Dim Block As AcadBlockReference = obj
' Check if BlockName matches
If Block.Name.ToUpper = strBlockName.ToUpper Then
If Block.HasAttributes Then
If Block.HasAttributes Then
For Each att As AcadAttributeReference In Block.GetAttributes
If att.TagString = strAttTag Then
' Change Attribute String
att.TextString = strAttText
End If
Next
End If
End If
End If
End If
Next

doc.SaveAs(strFileName)

doc = Nothing
acApp = Nothing

Catch ex As Exception
MsgBox("Error getting Autocad")
End Try
End If


End Sub

{code}
---------------------------



(defun botsbuildbots() (botsbuildbots))
0 Likes
Message 13 of 20

smichels
Enthusiast
Enthusiast
You make it look so easy!

Thanks for all your help! This is great...I will try in the am!

Smichels
0 Likes
Message 14 of 20

Anonymous
Not applicable
Hi arcticad,

You may not have noticed, but this is the VBA newsgroup. While it is
perfectly legitimate to offer a .NET solution, it would be courteous to
point out to a new programmer that this is .NET code and that it will
not be of much use in VBA.

Regards


Laurie Comerford

arcticad wrote:
> You can search though the drawing, find the block, find the Attibute tag
> and set the text. without opening the file in the editor. {code} Public
> Sub SetAttribute(ByVal strFileName As String) Dim strAttTag As String =
> "SHT_TTL_L2" Dim strAttText As String = "Some Text" Dim strBlockName As
> String = "Ford_A1" If Not isFileInUse(strFileName) Then Try Dim acApp As
> Autodesk.AutoCAD.Interop.AcadApplication = GetObject(,
> "AutoCAD.Application.17.2") Dim doc As AxDbDocument =
> acApp.GetInterfaceObject("ObjectDBX.AxDbDocument.17")
> doc.Open(strFileName) For Each obj As AcadEntity In doc.ModelSpace If
> TypeOf obj Is AcadBlockReference Then Dim Block As AcadBlockReference =
> obj ' Check if BlockName matches If Block.Name.ToUpper =
> strBlockName.ToUpper Then If Block.HasAttributes Then If
> Block.HasAttributes Then For Each att As AcadAttributeReference In
> Block.GetAttributes If att.TagString = strAttTag Then ' Change Attribute
> String att.TextString = strAttText End If Next End If End If End If End
> If Next doc.SaveAs(strFileName) doc = Nothing acApp = Nothing Catch ex
> As Exception MsgBox("Error getting Autocad") End Try End If End Sub {code}
0 Likes
Message 15 of 20

Anonymous
Not applicable
Hi Smichels,

If you need VBA code for this task, then don't waste your time with the
.NET code posted by articad.

I think you will find an adequate guide to getting and setting attribute
data in the VBA help files. Step through the sample code below to see
how it works.



Sub Example_HasAttributes()
' This example first creates a block without attributes.
' It then inserts the block and checks whether it has attributes.
' It then adds attributes to the block and inserts it again.
' Then it checks the new block reference for attributes.

' Create the block
Dim blockObj As AcadBlock
Dim insertionPnt(0 To 2) As Double
insertionPnt(0) = 0#: insertionPnt(1) = 0#: insertionPnt(2) = 0#
Set blockObj = ThisDrawing.Blocks.Add(insertionPnt, "CircleBlock")

' Add a circle to the block
Dim circleObj As AcadCircle
Dim center(0 To 2) As Double
Dim radius As Double
center(0) = 0: center(1) = 0: center(2) = 0
radius = 1
Set circleObj = blockObj.AddCircle(center, radius)

' Insert the block
Dim blockRefObj As AcadBlockReference
insertionPnt(0) = 2#: insertionPnt(1) = 2#: insertionPnt(2) = 0
Set blockRefObj = ThisDrawing.ModelSpace.InsertBlock(insertionPnt,
"CircleBlock", 1#, 1#, 1#, 0)
ThisDrawing.Application.ZoomAll
MsgBox "This block reference " & IIf(blockRefObj.HasAttributes,
"has attributes.", "does not have attributes."), , "Has Attributes Example"


' Add attributes to the block definition.
' Define the attribute definition.
Dim attributeObj As AcadAttribute
Dim height As Double
Dim mode As Long
Dim prompt As String
Dim insertionPoint(0 To 2) As Double
Dim tag As String
Dim value As String
height = 1#
mode = acAttributeModeVerify
prompt = "Attribute Prompt"
insertionPoint(0) = 1#: insertionPoint(1) = 1#: insertionPoint(2) = 0
tag = "Attribute Tag"
value = "Attribute Value"

' Create the attribute definition
Set attributeObj = blockObj.AddAttribute(height, mode, prompt,
insertionPoint, tag, value)

' Insert the block again
Dim blockRefObj2 As AcadBlockReference
insertionPnt(0) = 3#: insertionPnt(1) = 3#: insertionPnt(2) = 0
Set blockRefObj2 = ThisDrawing.ModelSpace.InsertBlock(insertionPnt,
"CircleBlock", 1#, 1#, 1#, 0)
ZoomAll
MsgBox "The first block reference " &
IIf(blockRefObj.HasAttributes, "has attributes.", "does not have
attributes.") & vbCrLf & _
"The second block reference " &
IIf(blockRefObj2.HasAttributes, "has attributes.", "does not have
attributes."), , "Has Attributes Example"

End Sub



Regards


Laurie Comerford

smichels wrote:
> You make it look so easy! Thanks for all your help! This is great...I
> will try in the am! Smichels
0 Likes
Message 16 of 20

arcticad
Advisor
Advisor
Laurie Comerford,

I would also like to point out that the caller switched his language from VBA to .net.
Sorry, I didn't want to upset the VBA Temple Guards. The angry horde is at the gate.

If you look at the code HE offered you will see this is vb.net code and not VBA

{code}
Imports Autodesk.AutoCAD.Interop
Imports System.Data.Common
Imports Autodesk.AutoCAD.Interop.Common
{code}
---------------------------



(defun botsbuildbots() (botsbuildbots))
0 Likes
Message 17 of 20

smichels
Enthusiast
Enthusiast
Laurie,

Thanks for your help, I will have to sort thru the examples posted when I have time and find the one that works for me!

Looks like I have plenty of learning to do!

SMichels
0 Likes
Message 18 of 20

smichels
Enthusiast
Enthusiast
Thanks for the help Arcticad!
0 Likes
Message 19 of 20

arcticad
Advisor
Advisor
Your Welcome.

I noticed that Autocad will not Release the file once it has been modified with ObjectDBX
I had to close Autocad.

This will release the file when it is finished

{code}

Public Sub runCode()
Dim strFilename = ("c:\test.dwg")
If Not isFileInUse(strFileName) Then
SetAttribute (strFileName)
End If
End Sub

Public Function SetAttribute(ByVal strFileName As String) As Boolean

Dim BT As BlockTable
Dim Btr As BlockTableRecord
Dim ent As entity
Dim bDwg As New Database(False, True)
Dim rtnValue As Boolean

Dim strAttTag As String = "SHT_TTL_L2"
Dim strAttText As String = "SOMETEXT"
Dim strBlockName As String = "Ford_A1"

bDwg.ReadDwgFile(strFileName, System.IO.FileShare.ReadWrite, True, "")
Dim db As Database = bDwg

Dim tr As Autodesk.AutoCAD.DatabaseServices.TransactionManager = bDwg.TransactionManager

Using tr.StartTransaction()
' get Block table
BT = CType(db.BlockTableId.GetObject(DatabaseServices.OpenMode.ForWrite), BlockTable)
' get Modelspace
Btr = CType(BT(BlockTableRecord.ModelSpace).GetObject(OpenMode.ForWrite), BlockTableRecord)
' get Iteration for modelspace
Dim iter As BlockTableRecordEnumerator = Btr.GetEnumerator

While iter.MoveNext
' get each object in the modelspace
ent = iter.Current.GetObject(OpenMode.ForRead)

If TypeOf ent Is BlockReference Then
Dim Block As BlockReference = ent
' Check if the block name matches
If Block.name = strBlockName Then
For Each Id As ObjectId In Block.AttributeCollection
' get Attribute
Dim AttEnt As Entity = Id.GetObject(Autodesk.AutoCAD.DatabaseServices.OpenMode.ForWrite)

' Check each Attribute for matching name
If TypeOf AttEnt Is AttributeReference Then
Dim attRef As AttributeReference = AttEnt
If attRef.Tag = strAttTag Then
' Change text String
attRef.TextString = strAttText
' Save Changes
bDwg.SaveAs(strFileName, DwgVersion.Current)
' Set Return value
rtnValue = True
' get out of the loop
Exit While
End If

End If
Next
End If
End If
End While
End Using

' Close File
bDwg.CloseInput (True)
' Release file inuse
bDwg.Dispose()
' Clear Reference
bDwg = Nothing
' Return Value
Return rtnValue

End Function
{code}
---------------------------



(defun botsbuildbots() (botsbuildbots))
0 Likes
Message 20 of 20

smichels
Enthusiast
Enthusiast
Great... Thanks again!

SMichels
0 Likes