Allowing interactive dragging of a selection of AutoCAD objects using .NET

In the last post we created a simple MText object containing sections of text with different colours. The object was located at a hard-coded location, so now we want to use a simple technique to allow placement of our MText (or any object, for that matter) in the current user coordinate system.

Rather than implementing a full jig class – whether a DrawJig or an EntityJig (the latter being most appropriate for this scenario) – we're going to use the  .NET equivalent of the old (draggen) or acedDragGen() functionality: the overload of Editor.Drag() which takes a selection set, prompt and callback delegate (we might also have used a PromptDragOptions object, to get further options).

Here's the updated C# code, with changed/added lines in red (you can also get the source file without line numbers here):

    1 using Autodesk.AutoCAD.ApplicationServices;

    2 using Autodesk.AutoCAD.EditorInput;

    3 using Autodesk.AutoCAD.DatabaseServices;

    4 using Autodesk.AutoCAD.Runtime;

    5 using Autodesk.AutoCAD.Geometry;

    6 

    7 namespace MTextCreationAndJigging

    8 {

    9   public class Commands

   10   {

   11     [CommandMethod("COLTXT2")]

   12     static public void CreateColouredMText()

   13     {

   14       Document doc =

   15         Application.DocumentManager.MdiActiveDocument;

   16       Database db = doc.Database;

   17       Editor ed = doc.Editor;

   18 

   19       // Variables for our MText entity's identity

   20       // and location

   21 

   22       ObjectId mtId;

   23       Point3d mtLoc = Point3d.Origin;

   24 

   25       Transaction tr =

   26         db.TransactionManager.StartTransaction();

   27       using (tr)

   28       {

   29         // Create our new MText and set its properties

   30 

   31         MText mt = new MText();

   32         mt.Location = mtLoc;

   33         mt.Contents =

   34           "Some text in the default colour...\\P" +

   35           "{\\C1;Something red}\\P" +

   36           "{\\C2;Something yellow}\\P" +

   37           "{\\C3;And} {\\C4;something} " +

   38           "{\\C5;multi-}{\\C6;coloured}\\P";

   39 

   40         // Open the block table, the model space and

   41         // add our MText

   42 

   43         BlockTable bt =

   44           (BlockTable)tr.GetObject(

   45             db.BlockTableId,

   46             OpenMode.ForRead

   47           );

   48 

   49         BlockTableRecord ms =

   50           (BlockTableRecord)tr.GetObject(

   51             bt[BlockTableRecord.ModelSpace],

   52             OpenMode.ForWrite

   53           );

   54 

   55         mtId = ms.AppendEntity(mt);

   56         tr.AddNewlyCreatedDBObject(mt, true);

   57 

   58         // Select the last entity added (our MText)

   59 

   60         PromptSelectionResult psr = ed.SelectLast();

   61 

   62         // Assuming that worked, we'll drag it

   63 

   64         if (psr.Status ==
PromptStatus.OK)

   65         {

   66           // Launch our drag jig

   67 

   68           PromptPointResult ppr =

   69             ed.Drag(

   70               psr.Value,

   71               "\nSelect text location: ",

   72               delegate(Point3d pt, ref Matrix3d mat)

   73               {

   74                 // If no change has been made, say so

   75 

   76                 if (mtLoc == pt)

   77                   return SamplerStatus.NoChange;

   78                 else

   79                 {

   80                   // Otherwise we return the displacement

   81                   // matrix for the current position

   82 

   83                   mat =

   84                     Matrix3d.Displacement(

   85                       mtLoc.GetVectorTo(pt)

   86                     );

   87                 }

   88                 return SamplerStatus.OK;

   89               }

   90             );

   91 

   92           // Assuming it works, transform our MText

   93           // appropriately

   94 

   95 
60;        
if (ppr.Status == PromptStatus.OK)

   96           {

   97             // Get the final translation matrix

   98 

   99             Matrix3d mat =

  100               Matrix3d.Displacement(

  101                 mtLoc.GetVectorTo(ppr.Value)

  102               );

  103 

  104             // Transform our MText

  105 

  106             mt.TransformBy(mat);

  107 

  108             // Finally we commit our transaction

  109 

  110             tr.Commit();

  111           }

  112         }

  113       }

  114     }

  115   }

  116 }

When we use the new COLTXT2 command, we see the MText object now follows the cursor around until we select the eventual destination:

Dragging our multi-coloured multi-line text

This technique could easily be adapted to using any set of objects, although more work may be needed to transform the results. We had the MText itself, making this easy, but otherwise it might be needed to open the objects to transform them or to P/Invoke the acedXformSS() function.

In the next post we'll take this one step further and launch the In-Place Editor for MText, to allow final editing once placed.

  1. Adri Groeneveld Avatar
    Adri Groeneveld

    Hi Kean,

    I'm having trouble with translating the lambda expression into VB.NET. The code converter sites i used can't translate it. Can you say how it is done in VB.NET?

    Regards, Adri

  2. Juan Carlos Velez Avatar
    Juan Carlos Velez

    kean
    It is possible to do a tutorial of as it is the procedure for loading your routines and libraries should use for this.
    Because they are interesting to start in the world of the developers.to newbies is difficult know how load this in C# or C++

  3. Kean Walmsley Avatar

    Hi Adri,

    The simplest would probably be to define a method in the Commands class and pass a DragCallback delegate for it to the Drag function.

    I'd need to spend some time looking at this, which won't be until tomorrow at the earliest - hopefully someone out there can post a solution in the meantime.

    Regards,

    Kean

  4. Kean Walmsley Avatar

    Juan Carlos,

    This post should be of help to you.

    Regards,

    Kean

  5. David Osborne Avatar

    You just pull the delegate out to a separate function with this signature:

    Private Function MyDragCallback(ByVal pt As Point3d, ByRef mat As Matrix3d) As SamplerStatus

    Change the PromptPointResult line like so:
    Dim ppr As PromptPointResult = ed.Drag(psr.Value, vbLf & "Select text location: ", New DragCallback(AddressOf MyDragCallback))

    And to make that work you have to pull the declaration of mtLoc out to the class level so it can be accessed by the delegate function

  6. David Osborne Avatar

    ...I should also mention that I had to change the double backslashes to single backslashes in the content string for mine to come out right. Not sure why VB and C# are different there?

    Thanks for another interesting post, Kean.

  7. Excellent - thanks, David!

    Yes - VB doesn't require (or allow) backslash as an "escape" character to indicate in-line character codes (you'd typically use Chr(10) instead of "\n", for instance). So while we need double-backslash in a C# string to generate a single backslash on the output, only one is needed in VB.

    Tip: if you prefix your string with @ in C#, it's considered literal (in the sense backslashes will not denote control characters). Very useful when defining literal paths:

    string path = @"C:\Users\walmslk\Documents";

    Cheers,

    Kean

  8. Hi Kean,
    Why is it that when it is called from a modeless dialog it fails, even if inserting LockDocument(). Can you say how it is done?

    Regards, Fulton

  9. Hi Fulton,

    I have no idea, although I always recommend calling a command from yoru modeless UI via SendStringToExecute(), rather than putting the code there directly.

    It avoids all kind of subtle issues (such as this one).

    Regards,

    Kean

Leave a Reply to Adri Groeneveld Cancel reply

Your email address will not be published. Required fields are marked *