找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 964|回复: 0

[分享] Embedding fields in an AutoCAD table using .NET

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-5-11 17:09:36 来自手机 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 csharp 于 2014-5-12 08:04 编辑

http://through-the-interface.typepad.com/through_the_interface/2007/06/embedding_field.html

Embedding fields in an AutoCAD table using .NET
This post is in response to a few requests I've received to show how to embed fields in tables. It follows on from this previous post, where we looked at how to embed a block preview icon in a table. The technique I'm showing in this post is far from being specific to tables, however. You could very easily use it for any other text object that supports fields inside AutoCAD (MText, Text, Attributes, etc.)
Fields are very cool objects: they allow you to access a very wide array of information and embed them inside textual objects in AutoCAD. A field is an object, but can be defined by a text string containing angled-brackets etc. that AutoCAD interprets and regenerates at different times during execution (on regen, on drawing load etc. - check out the FIELDEVAL system variable for more details on that). The simplest way to create field objects in your applications is simply to embed a correctly formatted string: all being well, AutoCAD will understand it to represent a field and will create the corresponding object behind the scenes. Easy! :-)
To understand in detail how the field mechanism works, I'd suggest checking out the TextFileField sample on the ObjectARX SDK. This is a C++ sample I created back when fields were first introduced (2005, if I recall correctly), to show how to implement your own custom field. This particular one links to a text file and embeds the file's contents in the container object.
There are various standard fields available inside AutoCAD. You can access document-level information (such as the author of the drawing) or system-level information (such as the current date). To get started with fields, I recommend using the FIELD command to bring up the field-definition dialog (also accessible from the MTEXT toolbar, among other places). This dialog allows you to configure the vast majority of fields, including formatting codes, which are not explicitly documented.
0.jpg
Of the various standard fields that come with AutoCAD, the one I find most appealing - as a programmer - is the AcObjProp field, which provides the ability to access COM properties from a field object. This is really very cool - you basically pass in the object ID of the object you'd like to access, and the COM Automation property you'd like to read, and the field does the rest. This opens up enormous possibilities, as it ultimately allows you access to *any* object property, assuming it's exposed through COM (and developers often expose their custom objects via COM as it allows integration with the Property Palette and the ability to manipulate these objects via VBA).
Let's look at the string we'd like to add to our code. The plan is to add a column to our table that includes a boolean (Yes/No) indicating whether the block definition is dynamic, or not.
Here's an example of a string we can embed directly in the table cell to do this:
%<\AcObjProp Object(%<\_ObjId 2130399456>%).IsDynamicBlock>%
Breaking it down:
  • The first and last two characters tell AutoCAD the extents of the field definition
  • The AcObjProp string tells AutoCAD we're dealing with an object property
  • The Object string tells AutoCAD we're about to refer to an object
  • The _ObjId field points to an object by it's internal Object ID
  • The property we want to access is IsDynamicBlock
Object IDs are only valid for a particular session, so this number can never be hard-coded. AutoCAD is clever enough to remap these throughout the drawing whenever it is loaded, however, which allows you to reopen drawings and the properties still to be accessible by fields.
If you were to see this field embedded in a text object, it would display a grey box containing either "0" or "1", the results of calling the IsDynamicBlock property for a particular block definition (which is what needs to be pointed at by that particular Object ID, by the way). This isn't ideal, as we'd like to use a text string. You can apply formatting codes to the results of the AcObjProp field, by specifying /f. The specific codes - as mentioned previously - are not documented, but the FIELD command allows you to find out what they should be. The trick is to find a property that is of the same datatype as yours, and copy the formatting code.
For instance, I used the MText.BackgroundFill property (also a Boolean) to help me work out that the formatting code I need for my property is "%bl2". Here's the FIELD dialog showing me this information:
1.jpg
So I now know that we want to add the following string (with the Object ID changed appropriately) for each of our blocks:
%<\AcObjProp Object(%<\_ObjId 2130399456>%).IsDynamicBlock \f "%bl2">%
Alright, we're finally ready for some code... :-)
Here's the updated C# code. I haven't numbered the lines, this time, as that makes me lose a few valuable columns of width, but the changed code should be easy enough to identify - it's simply adding an additional column to our previous table (although I did put some lines in to add some column headings):
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

namespace TableCreation
{
  public class Commands
  {
    [CommandMethod("CRT")]
    static public void CreateTable()
    {
      Document doc =
        Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;

      PromptPointResult pr =
        ed.GetPoint("\nEnter table insertion point: ");
      if (pr.Status == PromptStatus.OK)
      {
        Transaction tr =
          doc.TransactionManager.StartTransaction();
        using (tr)
        {
          BlockTable bt =
            (BlockTable)tr.GetObject(
              doc.Database.BlockTableId,
              OpenMode.ForRead
            );

          Table tb = new Table();
          tb.TableStyle = db.Tablestyle;
          tb.NumRows = 5;
          // Added an additional column for the block image
          // and one for the "is dynamic" flag
          tb.NumColumns = 5;
          tb.SetRowHeight(3);
          tb.SetColumnWidth(15);
          tb.Position = pr.Value;

          // Create a 2-dimensional array
          // of our table contents
          string[,] str = new string[5, 4];
          str[0, 0] = "Part No.";
          str[0, 1] = "Name ";
          str[0, 2] = "Material ";
          str[1, 0] = "1876-1";
          str[1, 1] = "Flange";
          str[1, 2] = "Perspex";
          str[2, 0] = "0985-4";
          str[2, 1] = "Bolt";
          str[2, 2] = "Steel";
          str[3, 0] = "3476-K";
          str[3, 1] = "Tile";
          str[3, 2] = "Ceramic";
          str[4, 0] = "8734-3";
          str[4, 1] = "Kean";
          str[4, 2] = "Mostly water";

          // Use a nested loop to add and format each cell
          for (int i = 0; i < 5; i++)
          {
            for (int j = 0; j < 3; j++)
            {
              tb.SetTextHeight(i, j, 1);
              tb.SetTextString(i, j, str[i, j]);
              tb.SetAlignment(i, j, CellAlignment.MiddleCenter);
            }
            // Adding title information for additional columns
            if (i == 0)
            {
              tb.SetTextHeight(i, 3, 1);
              tb.SetTextString(i, 3, "Block Preview");
              tb.SetAlignment(i, 3, CellAlignment.MiddleCenter);

              tb.SetTextHeight(i, 4, 1);
              tb.SetTextString(i, 4, "Is Dynamic?");
              tb.SetAlignment(i, 4, CellAlignment.MiddleCenter);
            }
            // If a block definition exists for a block of our
            // "name" field, then let's set it in the 4th column
            if (bt.Has(str[i, 1]))
            {
              ObjectId objId = bt[str[i, 1]];
              tb.SetBlockTableRecordId(i, 3, objId, true);

              // And then we use a field to check on whether
              // it's a dynamic block or not
              string strObjId = objId.ToString();
              strObjId = strObjId.Trim(new char[] {'(',')'});
              tb.SetTextHeight(i, 4, 1);
              tb.SetTextString(
                i,
                4,
                "%<\\AcObjProp Object(%<\\_ObjId "
                  + strObjId
                  +">%).IsDynamicBlock \\f \"%bl2\">%"
              );
              tb.SetAlignment(i, 4, CellAlignment.MiddleCenter);

            }
          }
          tb.GenerateLayout();

          BlockTableRecord btr =
            (BlockTableRecord)tr.GetObject(
              bt[BlockTableRecord.ModelSpace],
              OpenMode.ForWrite
            );
          btr.AppendEntity(tb);
          tr.AddNewlyCreatedDBObject(tb, true);
          tr.Commit();
        }
      }
    }
  }
}

And here are the results of running the CRT command, assuming the KEAN block is the only dynamic one of the four:
2.jpg


论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2025-1-6 01:24 , Processed in 0.329726 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表