原文转载自:http://through-the-interface.typepad.com/through_the_interface/jigs/(该口已无法访问)
可访问转载入口:http://bbs.mjtd.com/thread-75618-1-1.html(转载自明镜通道by雪山飞狐_lzh)
原kean博客已经无法看到,故转载明经通道 雪山飞狐_lzh 老师整理内容
1.kean原文翻译
March 18, 2009
Jigging an AutoCAD block with attributes using .NET
利用.net做AutoCAD的属性块拖动
Thanks, once again, to Philippe Leefsma, a DevTech engineer based in Prague, for contributing the code for this post.再次感谢 Philippe Leefsma 一名位于布拉格的开发技术工程师,贡献了这篇文章中的代码
While researching an issue he was working on Philippe stumbled across a comment on this previous post where I more-or-less said jigging attributes wasn’t possible. 在研究一个他工作中的问题的时候,Philippe
突然发现在之前的文章中发表的一个评论,或多或少的提到拖动属性块是不可能的
Ahem. Anyway, Philippe decided to – quite rightly – prove me wrong, and the result is today’s post. :-)
Philippe决定用正确的方式证明我是不对的,所有就有了个今天这篇帖子
It turns out that the trick to jigging a block with attributes is to add the block reference to the database prior to running the jig.他证实拖动属性块的技巧是在进行拖动之前先将块参照添加到数据库中
I’d been coming at this from another direction – working out how to call through to the right version of the ObjectARX function, the one that allows the block reference to be in-memory rather than db-resident – but Philippe’s approach means that’s no longer needed.对于这个问题我一直朝着另一个方向,通过如何调用正确的ObjectARX 功能来完成一个允许将块属性保存在内存中而不是宿主在图形数据库中,这也就是意味着Philippe采用的方法不再被需要啦
I see this technique as potentially being useful when jigging other entities that benefit from being database resident (Solid3d objects spring to mind), so I really appreciate Philippe’s hard work on this.我知道这个技术在拖拽其他受益于宿主图形数据库中的实体是非常有用的,所有我真的很欣赏Philippe对于这方面做出的努力
Here’s the C# code which I’ve edited for posting:
-
using Autodesk.AutoCAD.Runtime;
-
using Autodesk.AutoCAD.ApplicationServices;
-
using Autodesk.AutoCAD.DatabaseServices;
-
using Autodesk.AutoCAD.EditorInput;
-
using Autodesk.AutoCAD.Geometry;
-
using System.Collections.Generic;
-
namespace BlockJig
-
{
-
class CBlockJig : EntityJig
-
{
-
private Point3d _pos;
-
private Dictionary<string, Point3d> _attPos;
-
private Transaction _tr;
-
public CBlockJig(Transaction tr, BlockReference br)
-
: base(br)
-
{
-
_pos = br.Position;
-
// Initialize our dictionary with the tag /
-
// AttributeDefinition position
-
_attPos = new Dictionary<string, Point3d>();
-
_tr = tr;
-
BlockTableRecord btr =
-
(BlockTableRecord)_tr.GetObject(
-
br.BlockTableRecord,
-
OpenMode.ForRead
-
);
-
if (btr.HasAttributeDefinitions)
-
{
-
foreach (ObjectId id in btr)
-
{
-
DBObject obj =
-
tr.GetObject(id, OpenMode.ForRead);
-
AttributeDefinition ad =
-
obj as AttributeDefinition;
-
if (ad != null)
-
{
-
_attPos.Add(ad.Tag, ad.Position);
-
}
-
}
-
}
-
}
-
protected override bool Update()
-
{
-
BlockReference br = Entity as BlockReference;
-
br.Position = _pos;
-
if (br.AttributeCollection.Count != 0)
-
{
-
foreach (ObjectId id in br.AttributeCollection)
-
{
-
DBObject obj =
-
_tr.GetObject(id, OpenMode.ForRead);
-
AttributeReference ar =
-
obj as AttributeReference;
-
// Apply block transform to att def position
-
if (ar != null)
-
{
-
ar.UpgradeOpen();
-
ar.Position =
-
_attPos[ar.Tag].TransformBy(br.BlockTransform);
-
}
-
}
-
}
-
return true;
-
}
-
protected override SamplerStatus Sampler(JigPrompts prompts)
-
{
-
JigPromptPointOptions opts =
-
new JigPromptPointOptions(" Select insertion point:");
-
opts.BasePoint = new Point3d(0, 0, 0);
-
opts.UserInputControls =
-
UserInputControls.NoZeroResponseAccepted;
-
PromptPointResult ppr = prompts.AcquirePoint(opts);
-
if (_pos == ppr.Value)
-
{
-
return SamplerStatus.NoChange;
-
}
-
_pos = ppr.Value;
-
return SamplerStatus.OK;
-
}
-
public PromptStatus Run()
-
{
-
Document doc =
-
Application.DocumentManager.MdiActiveDocument;
-
Editor ed = doc.Editor;
-
PromptResult promptResult = ed.Drag(this);
-
return promptResult.Status;
-
}
-
}
-
public class Commands
-
{
-
[CommandMethod("BJ")]
-
static public void BlockJig()
-
{
-
Document doc =
-
Application.DocumentManager.MdiActiveDocument;
-
Database db = doc.Database;
-
Editor ed = doc.Editor;
-
PromptStringOptions pso =
-
new PromptStringOptions(" Enter block name: ");
-
PromptResult pr = ed.GetString(pso);
-
if (pr.Status != PromptStatus.OK)
-
return;
-
Transaction tr =
-
doc.TransactionManager.StartTransaction();
-
using (tr)
-
{
-
BlockTable bt =
-
(BlockTable)tr.GetObject(
-
db.BlockTableId,
-
OpenMode.ForRead
-
);
-
BlockTableRecord space =
-
(BlockTableRecord)tr.GetObject(
-
db.CurrentSpaceId,
-
OpenMode.ForRead
-
);
-
if (!bt.Has(pr.StringResult))
-
{
-
ed.WriteMessage(
-
" Block "" + pr.StringResult + "" not found.");
-
return;
-
}
-
space.UpgradeOpen();
-
BlockTableRecord btr =
-
(BlockTableRecord)tr.GetObject(
-
bt[pr.StringResult],
-
OpenMode.ForRead);
-
// Block needs to be inserted to current space before
-
// being able to append attribute to it
-
BlockReference br =
-
new BlockReference(new Point3d(), btr.ObjectId);
-
space.AppendEntity(br);
-
tr.AddNewlyCreatedDBObject(br, true);
-
if (btr.HasAttributeDefinitions)
-
{
-
foreach (ObjectId id in btr)
-
{
-
DBObject obj =
-
tr.GetObject(id, OpenMode.ForRead);
-
AttributeDefinition ad =
-
obj as AttributeDefinition;
-
if (ad != null && !ad.Constant)
-
{
-
AttributeReference ar =
-
new AttributeReference();
-
ar.SetAttributeFromBlock(ad, br.BlockTransform);
-
ar.Position =
-
ad.Position.TransformBy(br.BlockTransform);
-
ar.TextString = ad.TextString;
-
br.AttributeCollection.AppendAttribute(ar);
-
tr.AddNewlyCreatedDBObject(ar, true);
-
}
-
}
-
}
-
// Run the jig
-
CBlockJig myJig = new CBlockJig(tr, br);
-
if (myJig.Run() != PromptStatus.OK)
-
return;
-
// Commit changes if user accepted, otherwise discard
-
tr.Commit();
-
}
-
}
-
}
-
}
When you run the BJ command (short for BlockJig) and specify the name of a block in the current drawing which contains attributes, you’ll now see the attributes with their default values shown as part of the block being jigged.当你运行一个BJ命令并且制定一个块名在当前包含特性的图形中,你会看到定义的属性值作为作为被拖拽块的一部分被显示
Implementing the code to allow editing of those attributes after insertion is left as an exercise for the reader.
编写一段代码允许编辑已经插入的属性留给读者作为练习完成
练习部分由我完成
Update:
This code didn't work for a few situations, such as when using justification (attributes would end up at the origin after being dragged) or with MText attributes (which would start at the origin until the mouse was moved).
这个代码不能工作在一些情况,例如当你使用对正(再被拖拽后属性将会回到原点处)或多行文本(当鼠标被移动是属性将从原点开始)等情况
A big thanks to Roland Feletic from PAUSER ZT-GMBH for helping identify and diagnose the various cases.
Here's the updated C# code:
-
using Autodesk.AutoCAD.Runtime;
-
using Autodesk.AutoCAD.ApplicationServices;
-
using Autodesk.AutoCAD.DatabaseServices;
-
using Autodesk.AutoCAD.EditorInput;
-
using Autodesk.AutoCAD.Geometry;
-
using System.Collections.Generic;
-
namespace BlockJigApplication
-
{
-
class AttInfo
-
{
-
private Point3d _pos;
-
private Point3d _aln;
-
private bool _aligned;
-
public AttInfo(Point3d pos, Point3d aln, bool aligned)
-
{
-
_pos = pos;
-
_aln = aln;
-
_aligned = aligned;
-
}
-
public Point3d Position
-
{
-
set { _pos = value; }
-
get { return _pos; }
-
}
-
public Point3d Alignment
-
{
-
set { _aln = value; }
-
get { return _aln; }
-
}
-
public bool IsAligned
-
{
-
set { _aligned = value; }
-
get { return _aligned; }
-
}
-
}
-
class BlockJig : EntityJig
-
{
-
private Point3d _pos;
-
private Dictionary<ObjectId, AttInfo> _attInfo;
-
private Transaction _tr;
-
public BlockJig(
-
Transaction tr,
-
BlockReference br,
-
Dictionary<ObjectId, AttInfo> attInfo
-
) : base(br)
-
{
-
_pos = br.Position;
-
_attInfo = attInfo;
-
_tr = tr;
-
}
-
protected override bool Update()
-
{
-
BlockReference br = Entity as BlockReference;
-
br.Position = _pos;
-
if (br.AttributeCollection.Count != 0)
-
{
-
foreach (ObjectId id in br.AttributeCollection)
-
{
-
DBObject obj =
-
_tr.GetObject(id, OpenMode.ForRead);
-
AttributeReference ar =
-
obj as AttributeReference;
-
// Apply block transform to att def position
-
if (ar != null)
-
{
-
ar.UpgradeOpen();
-
AttInfo ai = _attInfo[ar.ObjectId];
-
ar.Position =
-
ai.Position.TransformBy(br.BlockTransform);
-
if (ai.IsAligned)
-
{
-
ar.AlignmentPoint =
-
ai.Alignment.TransformBy(br.BlockTransform);
-
}
-
if (ar.IsMTextAttribute)
-
{
-
ar.UpdateMTextAttribute();
-
}
-
}
-
}
-
}
-
return true;
-
}
-
protected override SamplerStatus Sampler(JigPrompts prompts)
-
{
-
JigPromptPointOptions opts =
-
new JigPromptPointOptions(" Select insertion point:");
-
opts.BasePoint = new Point3d(0, 0, 0);
-
opts.UserInputControls =
-
UserInputControls.NoZeroResponseAccepted;
-
PromptPointResult ppr = prompts.AcquirePoint(opts);
-
if (_pos == ppr.Value)
-
{
-
return SamplerStatus.NoChange;
-
}
-
_pos = ppr.Value;
-
return SamplerStatus.OK;
-
}
-
public PromptStatus Run()
-
{
-
Document doc =
-
Application.DocumentManager.MdiActiveDocument;
-
Editor ed = doc.Editor;
-
PromptResult promptResult = ed.Drag(this);
-
return promptResult.Status;
-
}
-
}
-
public class Commands
-
{
-
[CommandMethod("BJ")]
-
static public void BlockJigCmd()
-
{
-
Document doc =
-
Application.DocumentManager.MdiActiveDocument;
-
Database db = doc.Database;
-
Editor ed = doc.Editor;
-
PromptStringOptions pso =
-
new PromptStringOptions(" Enter block name: ");
-
PromptResult pr = ed.GetString(pso);
-
if (pr.Status != PromptStatus.OK)
-
return;
-
Transaction tr =
-
doc.TransactionManager.StartTransaction();
-
using (tr)
-
{
-
BlockTable bt =
-
(BlockTable)tr.GetObject(
-
db.BlockTableId,
-
OpenMode.ForRead
-
);
-
if (!bt.Has(pr.StringResult))
-
{
-
ed.WriteMessage(
-
" Block "" + pr.StringResult + "" not found.");
-
return;
-
}
-
BlockTableRecord space =
-
(BlockTableRecord)tr.GetObject(
-
db.CurrentSpaceId,
-
OpenMode.ForWrite
-
);
-
BlockTableRecord btr =
-
(BlockTableRecord)tr.GetObject(
-
bt[pr.StringResult],
-
OpenMode.ForRead);
-
// Block needs to be inserted to current space before
-
// being able to append attribute to it
-
BlockReference br =
-
new BlockReference(new Point3d(), btr.ObjectId);
-
space.AppendEntity(br);
-
tr.AddNewlyCreatedDBObject(br, true);
-
Dictionary<ObjectId, AttInfo> attInfo =
-
new Dictionary<ObjectId,AttInfo>();
-
if (btr.HasAttributeDefinitions)
-
{
-
foreach (ObjectId id in btr)
-
{
-
DBObject obj =
-
tr.GetObject(id, OpenMode.ForRead);
-
AttributeDefinition ad =
-
obj as AttributeDefinition;
-
if (ad != null && !ad.Constant)
-
{
-
AttributeReference ar =
-
new AttributeReference();
-
ar.SetAttributeFromBlock(ad, br.BlockTransform);
-
ar.Position =
-
ad.Position.TransformBy(br.BlockTransform);
-
if (ad.Justify != AttachmentPoint.BaseLeft)
-
{
-
ar.AlignmentPoint =
-
ad.AlignmentPoint.TransformBy(br.BlockTransform);
-
}
-
if (ar.IsMTextAttribute)
-
{
-
ar.UpdateMTextAttribute();
-
}
-
ar.TextString = ad.TextString;
-
ObjectId arId =
-
br.AttributeCollection.AppendAttribute(ar);
-
tr.AddNewlyCreatedDBObject(ar, true);
-
// Initialize our dictionary with the ObjectId of
-
// the attribute reference + attribute definition info
-
attInfo.Add(
-
arId,
-
new AttInfo(
-
ad.Position,
-
ad.AlignmentPoint,
-
ad.Justify != AttachmentPoint.BaseLeft
-
)
-
);
-
}
-
}
-
}
-
// Run the jig
-
BlockJig myJig = new BlockJig(tr, br, attInfo);
-
if (myJig.Run() != PromptStatus.OK)
-
return;
-
// Commit changes if user accepted, otherwise discard
-
tr.Commit();
-
}
-
}
-
}
-
}
A few comments on this code:
It's been refactored to make a single pass through the block definition to both create the block reference and collect the attribute information to store in our dictionary.
The attribute information is now held in a class, which allows us to store more than just the position in our dictionary (without using multiple dictionaries), I went to the effort of exposing public properties for the various private members, as this is generally a good technique to use (if a little redundant, here).
The dictionary now stores this attribute information against an ObjectId rather than the tag string. Roland made the excellent point that blocks can contain attributes with duplicate tags, so this is much safe. We also had to use the ObjectId of the AttributeReference, as later on inside the jig's Update() function we no longer have access to the AttributeDefinition.
一些对于这些代码的评价
它被重构用来定义一个块来创建块参照并收集属性信息存储在我们的字典。
属性信息现在被约束在一个类中,它可以让我们存储更多的不仅仅是位置在我们的字典中(在不使用多个词典的情况下),我们努力为更多的私有成员暴漏他们的公有属性,因为这通常是一个良好的技术使用(但是在这有点多余)。
字典存储现在针对的ObjectId,而不是标记字符串该属性信息。罗兰提出,块可以包含重复的标记属性非常好的一点,所以这是非常安全的。我们也可以用AttributeReference的的ObjectId,作为后来拖拽的更新()函数中我们不再有机会获得AttributeDefinition。