attributes again?

Discussion in 'AutoCAD' started by kemp, Mar 22, 2005.

  1. kemp

    kemp Guest

    I know this has been addressed a million times already but I can't seem
    to make it work.

    I want to edit an attribute value of a block that has been inserted by
    vb, the code I have hacked from this NG is this:

    'Change scale attribute of blockObj
    atts = blockObj.GetAttributes
    For i = LBound(atts) To UBound(atts)
    If UCase(atts(i).TagString) = UCase(strTag)
    atts(i).TextString = strAttValue
    Exit For
    End If
    Next

    Is this correct? It is taken straight from a post on the newsgroup but
    it doesn't work. Maybe my declarations are incorrect? I have tried the
    following (and some variations of them) to no avail.

    Dim i As Integer
    Dim atts As AcadAttribute
    Dim blockObj As Object
    Dim strTag As String
    Dim strAttValue As String

    Or maybe the way I am setting the string values is all screwy...

    Set strTag = "SCALE"
    Set strAttValue = "testing"


    Whatever it is, I'm all confused and an obvious VB newbie, so any help
    sorting this out will be very appreciated!

    kemp
     
    kemp, Mar 22, 2005
    #1
  2. Hi Kemp

    After of your code maybe need Update the Object, by example

    'Change scale attribute of blockObj
    atts = blockObj.GetAttributes
    For i = LBound(atts) To UBound(atts)
    If UCase(atts(i).TagString) = UCase(strTag)
    atts(i).TextString = strAttValue
    Exit For
    End If
    Next
    blockObj.Update

    you try it.
     
    Eduardo Chávez Vallín, Mar 22, 2005
    #2
  3. kemp

    Norman Yuan Guest

    How does it not work? You get error or it runs through but the attribute
    value is not changed?
    I bet that the code does not run through because of syntex error:

    1. You need change "Dim atts As AcadAttribute" to "Dim atts As Variant"
    2. "Dim blockObj As Object" is OK if you are sure the block assgined to this
    variable IS an AcadBlockreference object with Attributes
    3 You do not use "Set" to assign value to a string variable, so, Set
    strTag="SCALE" should be changed to strTag="SCALE".

    The code for changing attribute value is correct, but you'd better add
    "blockObj.Update" as the other post suggested.
     
    Norman Yuan, Mar 23, 2005
    #3
  4. Rather than try and figure out your problem, use the code below. Just pass
    the function a valid block name, valid attribute tag name, new string
    value.

    As for the question, and the answers, of what to declare your variables as,
    don't use variant because that is technically incorrect. Variant is a vb6
    cludge that is a bad habit to use if you don't need to.

    If you read the help file, GetAttributes returns a Variant array of
    AcadAttributereRerences. What is variant is not the data type, but the
    number of AcadAttributeReferences that are returned. Therefore, the
    appropriate dimensioning is:

    Dim oAttRefs() As AcadAttributeReference
    oAttRefs = oMyBlk.GetAttributes

    This holds true for other Get methods such as getpoint. It is a good habit
    to get into this approach especially if you plan to move to the .NET world
    where variant is no longer accepted.

    -- Mike
    ___________________________
    Mike Tuersley
    ___________________________
    the trick is to realize that there is no spoon...

    Option Explicit

    Private Declare Function timeGetTime Lib "winmm.dll" () As Long

    Private Function Att_Update(sBLName As String, sAttTag As String,
    sNewAttVal As String) As Boolean
    '+-- Change an Attributes' value given the block name and attribute tag
    Dim oBlkRef As AcadBlockReference
    Dim oSelSet As AcadSelectionSet
    Dim oAttRef() As AcadAttributeReference
    Dim iCodes(0 To 1) As Integer
    Dim vCodeValues(0 To 1) As Variant
    Dim iCntr As Integer
    Dim ssName As String
    ssName = CStr(timeGetTime)
    Set oSelSet = ThisDrawing.SelectionSets.Add(ssName)
    iCodes(0) = 0
    vCodeValues(0) = "INSERT"
    iCodes(1) = 2
    vCodeValues(1) = sBLName
    'set default return value
    Att_Update = False
    'get the blocks
    oSelSet.Select Mode:=acSelectionSetAll, _
    filtertype:=iCodes, _
    filterdata:=vCodeValues
    If sNewAttVal = "" Then sNewAttVal = " "
    For Each oBlkRef In oSelSet
    If oBlkRef.HasAttributes = True Then
    oAttRef = oBlkRef.GetAttributes
    For iCntr = LBound(oAttRef) To UBound(oAttRef)
    If UCase(oAttRef(iCntr).TagString) = UCase(sAttTag) Then
    oAttRef(iCntr).TextString = sNewAttVal
    oAttRef(iCntr).Update
    Exit For
    End If
    Next
    Erase oAttRef
    End If
    Next

    Exit_Here:
    oSelSet.Delete
    Erase oAttRef
    If Not oBlkRef Is Nothing Then Set oBlkRef = Nothing
    Exit Function
    Error_Control:
    Select Case Err.Number
    Case -2147024809
    'block doesn't exist
    Resume Exit_Here
    Case Else
    MsgBox Err.Description, vbCritical
    Err.Clear
    Resume Exit_Here
    End Select
    End Function
     
    Mike Tuersley, Mar 23, 2005
    #4
  5. kemp

    MP Guest

    Thats interesting.
    I would have thought that would give the error "can't assign to an array"

    Because it's declared 'undimensioned' it's some magic kind of array that
    acts like a variant?
    I was not aware of that. Can you elaborate?

    In any case it's nice to know that method - that's the first time I've seen
    that published.
    Thanks as always
    Mark
     
    MP, Mar 23, 2005
    #5
  6. Thats interesting.
    Nope, as I said, the method returns a variant array of atts - not a variant
    No, it works because its not confined, or limited. Since the GetWhatever
    methods return an unknown number of instances, the array can grow to the
    size required to hold them. Haven't you ever created an array that you
    wanted to change later:

    Dim myArray()

    .......code......

    Redim myArray(9)
    ....etc....

    You can't use redim if you have already confined the area. Same policy is
    followed in calling the GetWhatever methods. Its important to understand
    that even if you know how many will be returned, you still have to declare
    the array unconfined otherwise it'll error because AutoCAD doesn't know how
    many items there will be until it executes the method.

    -- Mike
    ___________________________
    Mike Tuersley
    ___________________________
    the trick is to realize that there is no spoon...
     
    Mike Tuersley, Mar 23, 2005
    #6
  7. kemp

    MP Guest

    Wow this is fantastic!
    Being a complete novice at this stuff, learning comes in little pieces.
    I had read that a Variant was a data type that could hold any type of data.
    So to me a Variant was a Variant - a variant array was, in my thinking, a
    variant containing an array.
    I had also read (and confirmed) that you cannot assign to an array.
    You have to assign to elements of an array.
    So I had no Idea you *Can* assign to an undimensioned Dynamic array.
    (even a typed one at that)
    That is absolutely amazing!
    So who needs variants any more
    :)


    Yes, I have used "Dynamic arrays"
    Dim DynArr() as whatever
    ReDim DynArr(longValue)
    But I have only assigned the values thusly
    DynArr(x) = something
    I had no idea you could do
    DynArr = FunctionReturningAnArray

    So thank you again.
     
    MP, Mar 23, 2005
    #7
  8. kemp

    Jeff Mishler Guest

    I found this interesting also, Mark. However, maybe I'm approaching this
    wrong.

    In the following code (snagged from a post in another forum) I modified it
    to be as Mike suggests. This first occurance of PickPoint carries on without
    error, even though in the locals window it shows that it does NOT get set as
    expected, but then in the AddCircle it errors out since it never got set.

    Sub testline()
    Dim objPick(0) As AcadLine
    Dim PickPoint() As Double
    Dim strPrompt As String

    strPrompt = vbCr & "Select line: "
    ThisDrawing.Utility.GetEntity objPick(0), PickPoint, strPrompt

    'Next code is to test where my pickpoint is
    ThisDrawing.ModelSpace.AddCircle PickPoint, 10#
    End Sub

    How can this be made to work without using variants?

    Thanks,
     
    Jeff Mishler, Mar 23, 2005
    #8
  9. Hey Jeff,

    GetEntity returns an Object NOT a variant array of objects. Even if it did,
    you have constricted your array so it won't work. The arrays always have to
    be () with no value between the parenthesis.

    Now why PickPoint is not working is a completely different matter. This is
    what's frustrating about the Acad API. It should work as you've written
    but it doesn't. For some reason, some of the utility functions actually do
    kick back variants. Using your same basic code, try this:

    Sub testline()
    Dim PickPoint() As Double
    PickPoint = ThisDrawing.Utility.GetPoint
    ThisDrawing.ModelSpace.AddCircle PickPoint, 10#
    End Sub

    Now in the help file, both GetEntity and GetPoint return the point as a
    variant array of doubles, so why does one work and the other not? That is
    the question ;-) Typically, most of the methods do not return actual
    variants.

    -- Mike
    ___________________________
    Mike Tuersley
    ___________________________
    the trick is to realize that there is no spoon...
     
    Mike Tuersley, Mar 23, 2005
    #9
  10. kemp

    MP Guest

    that's exactly why I was so surprised what he showed worked
    per the help on GetEntity (as you know)
    PickedPoint

    Variant (three-element array of doubles); output-only


    so PickedPoint must be declared as a variant (and it will end up being
    filled with an array of doubles)

    however if you write a Function that returns an array

    Public Function GetTablesADOX(strDatabase As String) As String()
    ....

    End Function

    Then it is possible to use an undimensioned Dynamic array "as if it were a
    variant"

    (I only say "as if it were a variant" since I've seen nowhere in any VB
    help/Msdn that said anything other than you *cannot* assign directly to an
    array)

    Obviously you *can* assign directly to an undimensioned array.

    Dim DynArr() as String

    DynArr = GetTablesADOX

    however, that still doesn't help if Acads' methods were declared like

    Sub GetEntity (ByRef Obj as Object, ByRef PickedPoint as Variant, Optional
    Prompt as String)

    ....

    you will still need to feed it a variant as an argument in that case

    however you say you didn't get an error so I don't know

    I would have expected you'd get a Type mismatch error at the line
    ???

    very strange indeed
     
    MP, Mar 23, 2005
    #10
  11. kemp

    Jeff Mishler Guest

    Actually, that part of the code works, since it explicitly calls for the
    objPick(0) in the GetEntity.
    Strange.....So now that I've finally gotten off my other end and picked up a
    copy of vb.NET, how would you go about using GetEntity in that environment?
    CAUTION: I have not done anything with vb.NET other than run a few Tutorials
    in the "Getting started with Visual Basic .NET", so if this is obvious once
    I get going I apologize in advance...... ;-)

    Jeff
     
    Jeff Mishler, Mar 23, 2005
    #11
  12. Just declare your variable as an Object --

    Dim myVar As Object

    -- Mike
    ___________________________
    Mike Tuersley
    ___________________________
    the trick is to realize that there is no spoon...
     
    Mike Tuersley, Mar 23, 2005
    #12
  13. kemp

    kemp Guest

    Thanks for all your help guys, I have a much better understanding of how
    things work now, and my function works now too!

    kemp
     
    kemp, Mar 24, 2005
    #13
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.