ObjectAdded question

Discussion in 'AutoCAD' started by Gordon Price, Jan 9, 2004.

  1. Gordon Price

    Gordon Price Guest

    I am trapping the ObjectAdded event and I am noticing something unseemly.
    When I copy/past a simple block (literally just a pline) I get four
    ObjectAdded events
    IAcadEntity
    IAcadEntity (yes, twice)
    IAcadBlock
    IAcadBlockReference

    THEN I actually pick a point for the insertion, and then I get rwo MORE
    IAcadBlockReference

    For a total of SIX events for a single block insert.

    Can someone explain this too me? Especially the doubling up stuff? I wanted
    to use VBA to handle layer management, but since there is no CommandCanceled
    event I can't do much there (without leaving layers active) so I thought I
    would just trap the ObjectAdded and filter for the object types I wan't to
    deal with. SNo such luck it seems?

    On a different approach (back to the first really) can you use the
    EndCommand event, and somehow figure out what object was just added, so you
    can change the layer of that object?

    Hoping for some input so I can finish this beast over the week-end.

    best,
    Gordon
     
    Gordon Price, Jan 9, 2004
    #1
  2. Copy/Paste involve inserting a drawing into the current
    drawing (such as when using the INSERT command), so there
    may be other objects that may be added (namely blocks or
    entities in blocks).

    The problem with these events is that they fire for just
    about all objects, including 'transient' ones that may
    only exist on a temporary basis. So, the trick to using
    the event effectively lies in the ability to distinguish
    between the objects you're really interested in and those
    that are irrelevant. That alone requires you to do some
    work in the ObjectAdded event that will result in serious
    performance degradation.

    Don't think "flag", think C++
     
    Tony Tanzillo, Jan 9, 2004
    #2
  3. I second that. I wrote a COM server for a company in Canada that simply
    maintains a C++ STL container ( map<AcDbObjectId, vector<AcDbObjectId> >
    ) mapping all entities that were modified to their layer id.

    Moving the entire contents of a drawing with over 10,000 entities showed
    no appreciable lag over and above the same move without the reactor
    installed :)

    If you really need to do this sort of thing, C++ is the way to go :)

    --
    Best regards,

    Byron Blattel
    CADwerx--Applications for AutoCAD
    Autodesk Registered Developer
    Contact Info @ http://www.cadwerx.net
    Custom Programming Services - ObjectARX/C++/MFC/ASP/STL/ATL/ISAPI...
     
    Byron Blattel, Jan 9, 2004
    #3
  4. Gordon Price

    Gordon Price Guest

    Unfortunately, I need to have something that works long before I could learn
    C++ ;) I have some comments and examples from others using VLisp reactors. I
    will take a look at that and go from there.
    That said, I was planning on learning C#.net this year anyway. I assume I
    can do most anything in C# that could be done in C++? Maybe not quite as
    quick, or as elegant, but at least I could learn C# in this lifetime.

    Best,
    Gordon
     
    Gordon Price, Jan 9, 2004
    #4
  5. Gordon,
    Here is a bit of example code to be placed in the ThisDrawing class. It
    will place all blocks inserted into the drawing via the INSERT command on
    layer "blocks", assuming of course that layer "blocks" exists. I use
    something very similar to this to enforce our CAD layering standards. My
    ObjectAdded event contains checks for several other commands and entity
    types and my users experience no performance degradation. You may want to
    test this route before making the jump to a C++/ARX solution.


    Option Explicit

    Const blockLayer As String = "blocks"

    Private entityToLayer As AcadEntity

    Private Sub AcadDocument_ObjectAdded(ByVal Object As Object)
    Dim activeCommands As String
    activeCommands = ThisDrawing.GetVariable("CMDNAMES")

    If activeCommands Like UCase("*insert*") Then
    If TypeOf Object Is AcadBlockReference Then
    Set entityToLayer = Object
    End If
    End If
    End Sub

    Private Sub AcadDocument_EndCommand(ByVal CommandName As String)
    If Not entityToLayer Is Nothing Then
    entityToLayer.Layer = blockLayer

    Set entityToLayer = Nothing
    End If
    End Sub

    It is important to note that things get a little more interesting if you are
    trying to auto-layer entities where the commands to add them are capable of
    adding more than one before the command ends. If you're interested in
    seeing that, I'll be back on Monday :)
     
    Bobby C. Jones, Jan 9, 2004
    #5
  6. I *highly* recommend that you learn a .NET language. There will be a time
    in the future where you will be very pleased that you did so. However, at
    this time C# does *not* open up the ARX libraries for us. You will still
    need to go through the COM server :-(
     
    Bobby C. Jones, Jan 9, 2004
    #6
  7. Gordon Price

    Gordon Price Guest

    Ah, more stuff to play with over the weekend. Cool. Thanks a million.
    Well, yeah! I definitely want to see it. I did get an email from someone
    saying that VLisp reactors are a better way to go, with things like
    CommandCanceled events, and as long as you don't use persistent reactors
    they are as stable or more stable than VBA events. I get the impression you
    might not agree ;)

    As for .net, I certainly plan to learn c# this year. Maybe by R2006 we will
    have full ARX access via .net, and by then I might actually know how to do
    more than 'Hell WOrld' in C#.

    Best,
    Gordon
     
    Gordon Price, Jan 9, 2004
    #7
  8. You need to be careful with statements you're hearing from
    others here who may not consider how you work, or what you
    do with AutoCAD. There are plenty of applications where there
    can be significant copying or creation of new objects in a
    drawing, where the ball-and-chain ObjectXxxxx events of the
    AcadDocument will do nothing but bring AutoCAD to its knees,
    especially if you're not using a fast programming language.

    For simple end user activities where they are inserting one
    entity at a time using basic commands, there will be no
    significant performance degredation, but for other types of
    operations (like copying a large number of objects), there
    can be a massive performance hit.

    C# isn't going to help you here, because it has little to
    no advantages over VB in this regard.
     
    Tony Tanzillo, Jan 9, 2004
    #8
  9. Gordon Price

    Gordon Price Guest

    Tony,
    thanks for the further info. I am slowly but surely getting a handle on this
    programming thing. I have done a lot of stuff, but for little offices where
    I could be pretty sure of what a user is going to do. Now I am learning how
    to actually make stable, predictible tools ;)
    As for C#, my understanding is that a future version of Acad (post Neo) will
    expose most everything via .net, and C3.net will be viable. Given that it
    will take some time just to learn C# I am ok with that I guess. Untill then
    I make do with what I know about lisp and VBA, try to learn VLisp and hope I
    use the right language for each thing I do. The newsgroups have been a huge
    help there.

    Thanks,
    Gordon
     
    Gordon Price, Jan 9, 2004
    #9
  10. Hi Gordon,
    Here is that example that I promised on Friday. I added the ability to
    handle text and mtext entities. The DTEXT command is of course able to add
    several text entities to the drawing inside a single call to the command.
    In order to handle this we cannot simply store single object references.
    This one stores a collection of object references and then iterates over
    that collection to change the objects layers. Notice that if the user
    starts entering text via the DTEXT command and cancels prior to finishing
    the command, any text objects that the command entered will not be placed on
    the correct layer.

    Although this example is set up to run in the Thisdrawing object, I'd
    suggest pulling all of this logic into a separate class or set of classes.
    Exactly how you do so will depend on your particular needs and without a
    doubt it can get complex. For instance my auto-layering code monitors for
    objects such as text, mtext, dimensions, and several different types of acad
    entities including some custom entities. The layer that these objects go to
    is affected by what task the end user is performing at the time the entities
    are created. Text and dimensions for example can go on electrical,
    structural, or several other layers depending on what the end user is
    drafting at that moment. Sometimes these entities are not added by acad
    commands, but via code. There's also an option for the end user to toggle
    auto-layering on and off. As you can see handling all of that complexity in
    one long monolithic procedure just isn't practical. But coming up with a
    design that's easily maintainable and meets all of your needs such as
    accuracy and performance is the most rewarding part of this job. At least
    it is for me :)

    One final note on performance. I too was very skeptical of utilizing some
    of the events exposed by the object model after seeing just how often they
    are fired. So I did some experimenting and determined that yes, they are
    fired often. And no, for what I was doing with them, they didn't adversely
    affect performance. So experiment away and see for yourself if you can use
    these in your application.

    As for C#, I love it! .NET is a terrific platform and it's going to open a
    lot of doors as it gains popularity and acceptance into mainstream
    applications.


    Option Explicit

    Const blockLayer As String = "blocks"
    Const textLayer As String = "text"

    Private entitiesToLayer As Collection
    Private targetLayerName As String

    'Prepare to store objects added to the database
    Private Sub AcadDocument_BeginCommand(ByVal CommandName As String)
    Set entitiesToLayer = New Collection
    End Sub

    'Save references to the objects
    Private Sub AcadDocument_ObjectAdded(ByVal Object As Object)
    Dim activeCommands As String
    activeCommands = UCase(ThisDrawing.GetVariable("CMDNAMES"))

    If activeCommands Like "*INSERT*" Then
    targetLayerName = blockLayer
    If TypeOf Object Is AcadBlockReference Then
    entitiesToLayer.Add Object
    End If
    ElseIf activeCommands Like "*TEXT*" Then
    targetLayerName = textLayer
    If TypeOf Object Is AcadText Or _
    TypeOf Object Is AcadMText Then
    entitiesToLayer.Add Object
    End If
    End If
    End Sub

    'Modify the stored objects layers
    Private Sub AcadDocument_EndCommand(ByVal CommandName As String)
    If Not entitiesToLayer Is Nothing Then
    Dim entity As AcadEntity
    For Each entity In entitiesToLayer
    entity.Layer = targetLayerName
    Next entity

    Set entitiesToLayer = Nothing
    End If
    End Sub


    Have a good one!
     
    Bobby C. Jones, Jan 12, 2004
    #10
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.