英语原 X
查看原始 X

第6课:循环和持久性

beplay官网客服电话涉及的产品和版本
AutoCAD

我的第一个AutoCAD插件概述>>第一课>>教训2>>第三课>>4课>>5课>>第六课>>第七课>>8课

在这节课中,你将学习循环(持续执行一段代码,直到满足逻辑条件);以及如何使用扩展实体数据(EED)在DWG文件中保存信息,以便在DWG重新打开时再次使用它。您将编辑您的代码以过滤您的否决Xdata而不是objectid;最后,您将实现第二个自定义命令,以便稍后从BlockReference的AttributeReferences阻止它被否决

提供反馈:请通过电子邮件提供关于本次AutoCAD培训或本课的反馈:myfirstplugin@autodesk.com

课程下载

lesson6_AutoCAD_2023_projects(zip - 22kb)
lesson6_archive_2022_and_earlier_project_files(zip - 187kb)

扩展实体数据

如果你在上一课之后关闭了Visual Studio Community,现在重新启动它并打开你的KeepAttributesHorizontal项目。

现在,您将向要添加的项目中添加代码Xdata您想要否决的attributerreference。Xdata是一种将应用程序的自定义数据添加到绘图中各个dbobject的方法。添加了Xdata之后,当绘图保存到DWG文件时,Xdata将自动保存,当DWG文件重新打开时,Xdata将再次对应用程序可用。Xdata是一种'扩展实体数据”。另一种类型称为anXrecord.在本教程中,您不会使用Xrecords。

将以下变量声明添加到Command类中。

公共类命令

             
类变量来存储我们的否决规则的实例
Private Shared myOverrule As keep直toverrule
Xdata的注册应用程序Id
常量mXdataName作为字符串“ADSK_ATTRIBUTE_ZERO_OVERRULE”

一个常量变量存储不可更改的值。这是存储将在应用程序中反复使用的常量(不变)数据的有用方法。这里存储的是将要用作Xdata的名称注册申请编号.通过使用常量字符串变量,您可以在整个代码中使用变量名,如果您想更改字符串中的文本内容,则只需更改声明。这样你只需要在一个地方编辑你的代码。

可能有多个插件向同一个实体添加Xdata。您使用一个已注册的应用程序Id来标识哪些数据是您的。事实上,AutoCAD要求您添加的所有Xdata都有一个注册的应用程序Id作为其第一个元素。要使用已注册的应用程序Id,必须先注册它,因此将以下代码行添加到ImplementOverrule()方法:

Dim objIds()作为ObjectId
Dim db As Database = doc。数据库

             
AddRegAppId (db)

             
使用trans As Transaction =
db.TransactionManager.StartTransaction

Visual Studio智能感知系统用蓝色强调AddRegAppId(),以告诉您它不识别此方法。如果您将鼠标悬停在它上面,Visual Studio会告诉您它对问题的最佳猜测,并尝试为您提供解决方案。

为了解决这个问题,在Command类中添加以下新方法:

终止子

             
私有共享子AddRegAppId(ByVal db作为数据库)

             
使用trans As Transaction =
db.TransactionManager.StartTransaction ()

             
首先创建我们的RegAppId(如果它不存在)
Dim appTbl As RegAppTable =
trans.GetObject (db。RegAppTableId,OpenMode.ForRead)

             
appTbl.Has(mXdataName) Then
Dim appTblRec作为新的RegAppTableRecord
appTbl.UpgradeOpen ()
appTblRec。的名字=mXdataName
appTbl.Add (appTblRec)
反式。一个ddNewlyCreatedDBObject(appTblRec, True)
如果
trans.Commit ()
结束使用
终止子

             
结束课

这个方法正在注册我们的“已注册应用程序Id”。它通过添加一个newRegAppTableRecord到数据库的RegAppTable

随着您对AutoCAD .NET API的了解越来越多,您会发现许多对象被存储为记录.例如:

  • 块定义存储为BlockTables中的blocktable记录
  • Line类型存储为linetypetablerrecords在LinetypeTables中
  • 层存储为LayerTables中的layertablerrecords
  • 文本样式存储为TextStyleTables中的textstyletablerrecords
  • 等等……

所有这些通常被称为符号表记录和符号表。(实际上,它们都派生自这两个类)。

你的代码:

  • 开始一个新的事务(再次注意Using关键字);
  • 使用事务打开RegAppTable(数据库有一个RegAppTableId存储RegAppTable的ObjectId的属性);
  • 检查一个RegAppTableRecord与我们注册的应用程序Id名称是否已经存在;如果没有,就添加一个新的;
  • 提交事务。

这是您第一次向数据库添加新的DBObject。方法将新的RegAppTableRecord添加到RegAppTableRegAppTable.Add ()方法。方法将DBObject添加到事务内的数据库时,还必须将其添加到事务中Transaction.AddNewlyCreatedObject ()方法。

还要注意这个方法是私人-这意味着它只能由命令类中的另一个方法调用。

重构代码

接下来,您将重构项目,将创建和注册否决规则的代码移动到单独的函数中。现在这样做是因为稍后要添加两个新命令——这两个命令都需要使用相同的代码。将代码从ImplementOverrule ()到一个新的类方法,像这样:

结束使用

             
“创建并登记我们的否决,并打开否决。
ActivateOverrule ()
终止子

             
<CommandMethod (ActivateOverrule) >
公共共享子激活否决()

             
'我们只想创建一次overrule实例,
’所以我们在创建它之前检查它是否已经存在
’(也就是说,这可能是我们第二次执行该命令)
如果myOverrule是Nothing那么
实例化我们的overrule类
myOverrule = New keep直控规则
“宣告无效
否决。一个ddOverrule(
RXClass.GetClass(方法(AttributeReference)),
myOverrule假)
如果

             
'指定哪些属性将被否决
myOverrule.SetXDataFilter (mXdataName)
确保“否决”被打开,这样我们的“否决”才能生效
否决。否决=真

             
终止子

在创造新事物的同时ActivateOverrule ()方法,您已经向它添加了一个调用ImplementOverrule ()类时运行相同的代码KEEPSTRAIGHT命令。你还添加了一个CommandMethod属性的ActivateOverrule ()方法定义另一个自定义命令,以允许用户创建和注册否决并启用否决,而无需选择BlockReference否决。当我们开始在绘图中保存Xdata时,这将非常重要——这样用户就可以对他们刚刚打开的绘图打开您的否决。

现在,您已经准备好了基本的管道,可以将Xdata添加到BlockReference的过程中用户进行选择KEEPSTRAIGHT命令。这需要更多的改变ImplementOverrule ()方法:

Dim db As Database = doc。数据库

             
AddRegAppId (db)

             
使用trans As Transaction =
db.TransactionManager.StartTransaction

             
打开BlockReference以供读取。
“我们知道它是一个BlockReference,因为我们设置了一个过滤器
'我们的PromptEntityOptions
Dim blkRef As BlockReference =
trans.GetObject (res。ObjectId,OpenMode.ForRead)
'记录所有AttributeReferences的ObjectIds
’附加到BlockReference。
Dim attRefColl As AttributeCollection =
blkRef。一个ttributeCollection
'遍历所有AttributeReferences的ObjectIds
’附加到BlockReference,打开每一个
' AttributeReference并向其添加xdata。
For Each objId As ObjectId In attRefColl .
Dim attRef As AttributeReference =
反式。GetObject (objId OpenMode.ForWrite)
'创建包含否决过滤器名称的新xdata
使用resBuf作为新的ResultBuffer(
新TypedValue (
DxfCode。ExtendedDataRegAppName mXdataName),
新TypedValue (
DxfCode。ExtendedDataAsciiString, "虚拟文本"))

             
添加xdata
attRef。XData = resBuf
结束使用
下一个
trans.Commit ()

             
结束使用

             
“创建并登记我们的否决,并打开否决。
ActivateOverrule ()

             

循环

您只是将插件更改为使用Xdata筛选器来决定哪个AttributeReferences将其否决应用于。您通过传递Xdata注册的应用程序Id(存储在常量变量中)来实现这一点mXdataName)到最高裁决SetXDataFilter ()方法在你的新ActivateOverrule ()方法。这将取代SetIdFilter ()您以前使用的方法。

您还更改了代码,将Xdata添加到每个组件中AttributeReferenceAttributeCollectionBlockReference用户选择。遍历每一个AttributeReferenceAttributeCollection,你使用了循环-在这种情况下,你用的是为每个…下一个循环。通过在调试器中逐步检查代码,可以最容易地了解这是如何工作的。删除项目中已经存在的任何断点,并在开始的行中添加一个新断点对于每一个…

是时候再次测试代码了:

  • 新闻F5从调试器启动AutoCAD;
  • NETLOAD你的插件;
  • 打开样图;
  • 调用KEEPSTRAIGHT命令;
  • 选择矩形BlockReference

调试器应该在断点处停止:

//www.ocatasi.com/knowledge/sites/default/files/breakpoint.gif

接下来,打开Watch窗口(如果它还没有打开的话)(调试菜单- >窗户->),点击下方的名字在Watch窗口中激活编辑框,键入attDef。TextString,按:

//www.ocatasi.com/knowledge/sites/default/files/attRef.TextString.gif

遍历代码,直到执行点到达以。开始的行使用resBuf.的价值attRef。TextString现在应该读Top_Left文本如上图所示。

继续遍历代码,直到执行行到达下一个关键字:

//www.ocatasi.com/knowledge/sites/default/files/next.gif

在你跨过这条线之前,试着猜猜当你这样做时会发生什么。

你猜对了吗?

BlockReference您所选择的有四个属性。这意味着AttributeCollection拥有objectidAttributeReferences.的为每一个语句告诉.NET运行时执行后面的代码(直到下一个关键字)。Next关键字告诉运行时将执行移回循环的开始位置(回到为每一个行),直到每个代码都运行AttributeReferenceAttributeCollection

为每一个Line中还有一个变量声明。类型变量ObjectId被称为objId是否分配了每个的值AttributeReference的ObjectId依次,然后可以在循环内部使用。

中的代码为每个…下一个循环打开每一个AttributeReference事务(使用它ObjectId),然后将Xdata赋值给它。的Transaction.GetObject ()方法打开AttributeReferenceForWrite因为你要编辑它,你要向它添加Xdata。

Xdata本身由ResultBuffer链。这只是Xdata(和Xrecords)中使用的数据格式。如果您以前使用过LISP或使用过DXF,那么您已经知道这种格式。如果不是,我们简要解释ResultBuffer数据格式下面

在调试器中遍历代码,直到执行行再次位于开始的行使用resBuf.看看它的价值attRef。TextString属性在观察窗口-它被更改为秒的值AttributeReference.继续执行循环的所有四次迭代,观察如何执行attRef。TextString的变化。

循环是一种强大的方法,可以一直执行相同的代码,直到满足某些逻辑条件。没有为每个…下一个循环时,上面的代码必须像这样写:

Dim attRef As AttributeReference =
trans.GetObject (attRefColl.Item (0), OpenMode.ForWrite)
...
Dim attRef As AttributeReference =
trans.GetObject (attRefColl.Item(1)、OpenMode.ForWrite)
...
Dim attRef As AttributeReference =
trans.GetObject (attRefColl.Item(2)、OpenMode.ForWrite)
...
等。

除了你不知道里面有多少项attRefColl直到您运行插件并且用户选择了一个块。

在Visual Basic . net中有几种类型的循环可用。它们将被更详细地解释下面

是时候继续测试代码了:

  • 新闻F5继续插件执行
  • 旋转矩形块。注意,当您执行旋转时,属性保持与x轴平行-这是因为当AutoCAD复制块以在过程中拼接时,会复制Xdata旋转命令。
  • 以另一个名称保存绘图(SAVEAS命令)。
  • 关闭AutoCAD。
  • 从调试器重新启动AutoCAD。
  • NETLOAD您的插件并打开您保存的绘图。
  • 试着旋转还是矩形块,属性并不与x轴平行。这是因为你还没有打开你的否决。
  • 调用第二个自定义命令-ACTIVATEOVERRULE旋转又是块,这一次属性被否决了。的ACTIVATEOVERRULE命令注册了你的否决,它检测到你在绘图中保存的Xdata。

Unfiltering

现在停止调试。现在是时候实现另一个自定义命令了。您可以使用命令将Xdata添加到属性中,还可以使用命令开启否决,而不必在绘图中选择新块。最后一个命令将从所选块的属性中删除Xdata,因此它们将不再被否决。

添加这个CommandMethod实现到命令类:

<CommandMethod (DontKeepStraight) >
公共共享子RemoveXdata()

             
Dim doc As Document =
Application.DocumentManager.MdiActiveDocument
Dim ed As Editor = doc。编辑器

             
选择一个块引用

             
暗淡的选项作为新的提示选项(
vbLf & "选择一个块引用:")
选择。SetRejectMessage(vbLf & "必须是块引用…")
opts.AddAllowedClass(方法(BlockReference),真的)

             
Dim res As PromptEntityResult = ed.GetEntity(opts)

             
如果res.Status <> PromptStatus. sh那好吧
退出子
如果

             
Dim db As Database = doc。数据库

             
AddRegAppId (db)

             
使用trans As Transaction =
db.TransactionManager.StartTransaction

             
打开BlockReference以供读取。
“我们知道它是一个BlockReference,因为我们设置了一个过滤器
'我们的PromptEntityOptions
Dim blkRef As BlockReference =
trans.GetObject (res。ObjectId,OpenMode.ForRead)
'记录所有AttributeReferences的ObjectIds
’附加到BlockReference。
Dim attRefColl As AttributeCollection =
blkRef。一个ttributeCollection

             
'遍历所有AttributeReferences的ObjectIds
’附加到BlockReference,打开每一个
' AttributeReference并向其添加xdata。
For Each objId As ObjectId In attRefColl .
Dim attRef As AttributeReference =
反式。GetObject (objId OpenMode.ForWrite)

             
'创建包含否决过滤器名称的新xdata
使用resBuf作为新的ResultBuffer(
新TypedValue (
DxfCode。ExtendedDataRegAppName, mXdataName))
添加xdata。
因为除了regappid,其他部分都是空的,
'它会擦除我们之前添加的任何Xdata。
attRef。XData = resBuf
结束使用
下一个
trans.Commit ()

             
结束使用

             
终止子

测试这段代码:

  • 从项目中删除任何断点。
  • 新闻F5从调试器启动AutoCAD。
  • NETLOAD您的插件。
  • 打开您保存的修改过的样品图纸。
  • 调用ACTIVATEOVERRULE命令。
  • 调用DONTKEEPSTRAIGHT命令。
  • 选择矩形BlockReference
  • 旋转矩形块,你会看到属性再次随着块旋转。
  • 保存,关闭和重新打开绘图,如果你想完全测试它。

通读代码和注释,了解这个新函数的功能。如有必要,在调试器中添加断点并对代码进行步进。

RemoveXdata ()方法中已经存在的大量代码将被重用ImplementOverrule ()方法。的方法一样,我们将重构这两个方法以将公共代码放入单独的帮助器方法中作为练习ActivateOverrule ()方法。

恭喜你!现在您已经创建了第一个插件,并完成了本教程。在接下来也是最后一课中,您将了解如何继续学习使用AutoCAD . net API编程。

额外的话题

条件语句
你已经学了一些条件语句——你已经用过如果……已经在代码中构造了多次。然而,还有一些微妙之处您还没有发现。为了完整起见,我们还检查了您可能使用的另一个条件语句——the选择……情况声明。点击下面的子标题可以直接链接到MSDN文档。

如果……

下面是一个更全面的例子如果……声明。(如果您愿意,可以将代码放入一个测试项目中,并使用调试器逐步调试它)。

Dim num As Integer = 1
如果num = 1则
做点什么
ElseIf num = 2则
做点别的事
其他的
“什么也别做
如果
  • 当代码执行到如果语句,逻辑条件(Num = 1)进行测试。
  • 如果该条件的计算结果为True(确实如此,因为我们在上面的行中将num设置为1),则您放入语句中的任何代码都会代替做某事(直到ElseIf语句)执行。执行然后跳转到如果线。
  • 如果你设置全国矿工工会到1以外的值,那么该代码将不会被执行,而是跳转到ElseIf线。
  • 的逻辑条件ElseIf线(Num = 2)将受到考验。如果为True,注释所在的代码做点别的事将被处决;然后执行将转移到如果声明。
  • 如果两个条件都不是True(即num = 1为False, num = 2为False),则执行将跳转到下面的代码其他的声明。

你可以有很多ElseIf语句,但如果您有很多语句,那么如果您使用选择……情况下而是条件语句。

选择……情况

你使用选择……情况当您想要根据所查询的变量的值执行不同的代码段时。这是你应该如何写关于如果……声明使用选择……情况

Dim num As Integer = 1
选择大小写num
案例1
做点什么
案例2
做点别的事
其他情况下
“什么也别做
最终选择

的逻辑工作与如果……示例—如果Num = 1,然后是下面的代码案例1执行,等等。你也可以将案例分组,例如:

案例3 ~ 6
情形7 11 13

循环
Visual Basic . net提供了几种创建循环的方法。每个方法都有一些微妙之处,使您可以对循环的执行方式进行很多控制。我们建议您查看每个类型的完整语法msdn.microsoft.com.点击下面的子标题可以直接链接到MSDN文档。

…未来

为每个…下一个的一种特殊情况…未来循环,当需要遍历集合或数组中的每个元素时使用。的…未来循环接受一个循环变量(指数在下面的例子中),并在循环的每次迭代中递增它,直到它不再位于为循环定义的上界和下界之间(= 0到10表示从索引= 0开始,到索引>结束。可选一步关键字指定每次迭代要添加到循环变量的值。例如,这个循环执行index = 0、2、4、6、8和10的包含代码:

For index As Integer = 0 ~ 10步骤2
...
下一个

如果步骤2则循环中的代码将执行index = 0、1、2、3、4、5、6、7、8、9和10。Step可以是负的(也就是说,你可以从一个高的数字向后迭代到一个低的数字。

方法也可以移动到下一个循环迭代持续关键字或退出循环使用退出.该循环跳过index = 5的循环迭代,并在index = 8时退出循环

Dim skipThis As Integer = 5
Dim exitThis As Integer = 8
For index As Integer = 0到10
...
如果index = skipThis,则继续For
如果index = exitThis,则退出For
...
下一个

为每个…下一个

这是您在插件代码中使用的循环类型。一个为每个…下一个循环就像…未来,但用于遍历数组和其他类似于“集合”的类中的对象。语法与…未来,但实际上并没有一步选择。

概括一下,下面是如何在插件代码中使用attRefColl AttributeCollection变量For Each…Next:

对于attRefColl中的每个id As ObjectId
“用这个物体做点什么
下一个

循环做…

循环做…使用直到关键字在同一段上循环,直到满足逻辑条件为止。这段代码循环直到变量count的值为10(即直到计数= 10是真的)

Dim count As Integer = 0
Count = Count + 1
循环直到count = 10

这段代码使用而不是直到

Count = Count + 1
循环While计数<= 10

在前面的两个示例中,循环做…将至少执行一次,因为逻辑测试位于循环的末尾。你也可以把虽然/直到时,如果逻辑条件不为True,则循环内的代码将永远不会执行语句执行。下面的代码将循环,直到设置一个指示这一点的条件{我想停止循环}

暗标志As布尔值= True
Do While标志
如果{我想停止循环}则flag = False
循环

扩展实体数据

Xdata
Xdata可以附加到任何DBObject。可以向每个对象添加总共16KB的Xdata。您应该始终假定您不是唯一一个向对象添加Xdata的人,因此您自己的Xdata的礼貌限制是大约2KB,以便为其他人留出空间。如果需要存储更多的数据,则应该使用Xrecords。

Xdata存储为ResultBuffers链。链中的第一个ResultBuffer存储了您注册的应用程序Id,这样您就知道它后面的数据(直到下一个注册的应用程序Id)是您的。如果使用Xdata对否决进行过滤,则对已注册的应用程序Id进行过滤。

Xrecords
每个Xrecord最多可以保存2GB的数据。您创建了所需的Xrecord,因此(与Xdata不同)Xrecord中的所有存储空间都属于您自己。

Xrecords存储在字典对象。你会发现字典物体在两个地方。

  • 的DWG数据库有一个中心命名对象字典.这是存储应用于整个绘图的全局数据的地方。
  • 每一个DBObject可以有扩展字典.(如果你想要,你可以创建它。)

你可以创建额外的字典并将它们存储在命名对象字典或扩展字典中。Dictionary中的任何条目都是通过名称引用的。可用于重写的另一种类型的扩展实体数据过滤是对存储在DBObject扩展字典中的对象的名称进行过滤——如果您将Xrecord直接添加到扩展字典中,则该名称是存储Xrecord的名称;如果您喜欢使用子字典,则该名称是添加的子字典的名称。

在本教程中您不会使用Xrecords,但是在AutoCAD . net培训实验室中使用了Xrecords。

Xrecord数据存储为ResultBuffers链——就像Xdata一样。

ResultBuffers
Xdata和Xrecords中使用的数据存储为ResultBuffer,这是一个列表TypedValue对象。每一个TypedValue在列表中存储单个数据项。

一个TypedValueTypeCode和一个价值.的TypeCode描述数据的格式(整数、字符串、双精度数等);Value(显然)存储数据的实际值(10,“Some Text”,3.14159265,等等)。

如果你熟悉的话DXF代码从LISP或DXF文件,那么你会立即明白这一点,因为TypeCode是简单的DXF代码,和价值是该DXF代码的值。.NET API提供DxfCode枚举(或枚举),让您轻松访问DXF代码,而不必记住每个DXF代码编号代表什么。

枚举只是一组预定义的名称,可以用来代替数字。例如,你可能决定一个方法应该接受一个整数作为参数,它用来知道它应该画一个弧、一个圆还是一个椭圆。但是很难记住“0”表示弧,“1”表示圆,“2”表示椭圆。相反,你可以定义一个Enum,并让方法接受它作为参数,就像这样:

公共Enum WhatToDraw
DrawArc
DrawCircle
DrawEllipse
结束枚举

             
Public Sub DrawIt(ByVal参数As WhatToDraw)
选择Case参数
WhatToDraw。DrawArc
画一条弧线
WhatToDraw。DrawCircle
画一个圆
WhatToDraw。DrawEllipse
画一个椭圆
最终选择
终止子

在阅读代码时,这比使用整数更容易理解。

你已经在这节课的代码中使用了两个DxfCode枚举:

  • DxfCode。ExtendedDataRegAppName-表示已注册的应用程序id。
  • DxfCode。ExtendedDataAsciiString-表示字符串(一些文本)。

有太多的DxfCode枚举值在这里列出。你可以在DxfCode中找到它们AutoCAD托管类参考.以下是一些比较常见的说法:

  • DxfCode。Int8DxfCode。Int16DxfCode。Int32DxfCode。Int64-不同大小的整数(Int8的值为255,Int16的值为65535,等等)。
  • DxfCode。HardPointerIdDxfCode。SoftPointerId-存储对象(“硬”和“软”之间的区别是当你复制对象时如何处理对象)。这些只能用于xrecord(不能用于Xdata)。
  • DxfCode。XCoordinateDxfCode。YCoordinateDxfCode。ZCoordinate-三维点的X, Y和Z值。
  • DxfCode。保龄球-一个布尔值(真或假)
  • DxfCode。真正的-实数(两倍)。

您可以添加尽可能多的新TypedValue对象ResultBuffer使用ResultBuffer.Add ()方法。

在Xdata、Xrecords、选择集过滤器以及创建自定义lisp可调用函数时,您将主要使用ResultBuffers。ResultBuffers和DxfCodes是AutoCAD特有的—如果您不打算将数据传递给AutoCAD,则不太可能使用它们在插件中存储数据。

我的第一个AutoCAD插件概述>>第一课>>教训2>>第三课>>4课>>5课>>第六课>>第七课>>8课

网站版本:2.132.0
Baidu
map