当前位置:文档之家› 第8章 自定义对象

第8章 自定义对象

第8章  自定义对象
第8章  自定义对象

第8章
本章简介 8
自定义对象
?自定义对象的概念。 ?从 AcDbObject 派生对象。 ?从 AcDbEntity 派生自定义实体。
学习要点
? 了解自定义对象的概念及其的应用。 ? 掌握从 AcDbObject 派生对象。 ? 掌握自定义实体的创建方法。
我们在前面介绍了通过扩充数据方式来存储扩充数据,虽然能满足一定的工程需求,但 是由于最终的扩展数据通过结果缓冲链表的方式存储,缺少面向对象特性,在处理的时候比 较繁琐, 我们完成可以定义自己的类来封装数据, 此种情况下我们需要通 AcDbObject 派生数 据库对象;另外,AutoCAD 是一个通用的 CAD 平台,提供如点、线等通用的对象类型,我 们可以针对行业特征派生自己的实体,如定义螺栓类、管道类等,这些派生的实体除了具有 自己的几何形体外,还包含自己所有的一些数据,如管道的管径、材质等属性。本章我们介 绍一下自定义数据库对象的概念和方法,用户可以根据自己的实际需求派生一套面向行业的 对象类型。
8.1
自定义对象
在介绍自定义对象之前, 我们需要对 AutoCAD 中数据库对象的层次关系有所了解了 解,这有助于我们理解后面的实际应操作,AutoCAD 中数据库对象的层次关系如图 8-1 所示。
1
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

图 8-1AutoCAD 中数据库对象的层次关系 从图 8-1 我们看出所有的数据库对象类都派生自 AcRxObject,该类是所有数据库对 象的基类,它主要实现对象运行时类型识别机制,提供一些用于类型识别的重要函数,它 提供的函数主要有一下几个: n desc() : 静态成员函数,返回指定类的类描述符对象。 n cast(): 返回指定类型的对象。 n isKindOf(): 用于判断对象是否属于指定类或者派生类。 n isA() :返回未知类对象的类描述符对象。 我们在介绍实体操作的时候讲过如何使用这些函数, 这里我们需要在这里介绍这些函 数的实现机制,从 AcRxObject 派生的类都包含一个相应的类描述符对象,用 AcRxClass 类表示, 它包含了运行使类型的识别信息,AcRxObject 的派生类包含一个指向 AcRxClass 对象的指针(gpDesc),可以通过 AcRxObject::desc()获取这个 AcRxClass 对象指针,而 AcRxClass 对象包含一个指向其父对象 AcRxClass 的指针, 这样构成了类的运行时类层次 表,如图 8-2,我们可以调用 AcRxObject::isKindOf()来判断对象是否是从某个类派生 出来。
图 8-2 行时类层次表 在派生自定义类中要实现运行类的识别信息, 也就是要重载上面提到的 desc()、 isKindOf()
2
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

等 函 数 , 这 可 以 通 过 ObjectARX 提 供 的 宏 来 实 现 , 通 过 使 用 类 声 明 宏 ACRX_DECLARE_MEMBERS(CLASS_NAME)可以声明 desc(), cast(), isA()函数,代码如 下: class CMyClass : public AcRxObject { public: ACRX_DECLARE_MEMBERS(CMyClass); …. } 该宏经过编译预处理后被扩展成一下代码: virtual AcRxClass* isA() const; static AcRxClass* gpDesc; static AcRxClass* desc(); static CMyClass * cast(const AcRxObject* inPtr) { return ((inPtr == 0) || !inPtr->isKindOf(CMyClass::desc())) ? 0 : (CMyClass *)inPtr; }; static void rxInit(); 自定义类的静态成员函数 rxInit()用于实现以下初始化操作: n 注册自定义类。 n 创建类的描述对象。 n 将类描述对象添加到类的描述词典中。 在应用程序的初始化函数中必须调用自定义类的静态成员函数 rxInit()来实现自定义类的 初始化,然后调用全局函数 acrxBuildClassHierarchy 把该类添加到 ACRX 运行类层次表中。 另外在应用程序的卸载时需要调用 deleteAcRxClass()把该类从 ACRX 运行类层次表中删 除,应用程序的初始化代码如下: extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt) { switch (msg) { case AcRx::kInitAppMsg: acrxDynamicLinker->unlockApplication(pkt); // 自定义类的初始化 CMyClass::rxInit(); // 把该类添加到 ACRX 运行类层次表中 acrxBuildClassHierarchy(); break; case AcRx::kUnloadAppMsg: // 该类从 ACRX 运行类层次表中删除 deleteAcRxClass(CMyClass::desc()); } return AcRx::kRetOK;
3
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

} 所有永久或者临时的图形对象都实现可绘制接口,封装该接口的对象可以通过火绘制 API 完成绘制, 可显示的对象派生自 AcGiDrawable 类, 该类实现图形系统 (GS) 绘制协议。 AcDbObject 类执行文件操作协议, 从该类派生的对象通过重载文件操作函数可以被保存 为 DWG 或 DXF 文件,或者从 DWG 或 DXF 文件读入。 AcDbEntity 类是实体类,派生自 AcDbObject 类,从该类派生的对象除了可以支持文件 操作外,还可以通过重载绘制函数来按照开发者的要求绘制图形。
8.2 从 AcDbObject 派生
从 AcDbObject 类派生的子类可以支持文件操作,即对象可以从 DWG 或者 DXF 文件中 读写, 也就是可以保存到 DWG 或者 DXF 文件中, 要实现文件读写操作派生类必须重载以下 四个函数: Acad::ErrorStatus dwgInFields(AcDbDwgFiler *filer); Acad::ErrorStatus dwgOutFieds(AcDbDwgFiler *filer); Acad::ErrorStatus dxfInFieds(AcDbDxfFiler *filer); Acad::ErrorStatus dxfOutFieds(AcDbDxfFiler *filer); 以上函数的参数是文件操作类 AcDbDwgFiler 或 AcDbDxfFiler 指针,文件操作类是一个 工具类,用于数据库对象的读写读写, ObjectARX 通过枚举类型 AcDb::FilerType 来检查文件 操方式和类型。 例如当调用 AutoCAD 的 SAVE 命令保存文件时,会调用数据库对象的 dwgOutFieds 函 数, 此时使用 kFileFiler 枚举类型; 而当使用 WBLOCK 命令时, 同样调用 dwgOutFieds 函数, 但使用的枚举类型为 kWblockCloneFiler 和 kIdXlateFiler, 如果调用 UNDO 命令取消操作时候, 会调用数据库对象的 dwgInFields 函数,使用的枚举类型是 kUndoFiler。 向文件操作类对象写入数据的过程中,不需要执行错误检查,文件操作类都有一个成员 函数 getFilerStatus()用于返回类的状态,有时候开发者需要检查文件操作类对象的状态。 在 自 定 义 类 中 重 载 文 件 操 作 函 数 时 , 必 须 首 次 调 用 assertReadEnabled() 或 assertWriteEnabled()函数来检查对象处于正确的打开状态, 然后调用自定义类父类的同名函数 来提供对父类数据的重载。 对于 DWG 文件操作函数 dwgInFields 和 dwgOutFieds,必须按照相同的顺序进行数据的 读写操作,否则派生类数据可能发生混乱。 文件操作类对象可以调用成员函数 readItem()和 writeItem()来读写数据,实际上这 两个函数会被所有支持的数据类型重载,另外还可以调用一些指定了数据类型的读写函数, 如 writeInt32 ) 这些函数在被调用时会自动转换参数的数据类型而忽略数据的实际类型, ( 等, 例如自定义类中包含整型数据,则可以调用 readInt32()和 writeInt32()进行相应的读写操 作。 Acad::ErrorStatus CPipeAttribute::dwgOutFields (AcDbDwgFiler *pFiler) const { // assertReadEnabled () ; //----- Save parent class information first. Acad::ErrorStatus es =AcDbObject::dwgOutFields (pFiler) ; if ( es != Acad::eOk ) return (es) ;
4
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

//----- Object version number needs to be saved first if ( (es =pFiler->writeUInt32 (CPipeAttribute::kCurrentVersionNumber)) != Acad::eOk ) return (es) ; ///写入数据开始 pFiler->writeItem(m_dRadius); pFiler->writeItem(m_dThickness); pFiler->writeItem(m_dDeep); pFiler->writeString(m_cMaterial); //写入数据结束 return (pFiler->filerStatus ()) ; }
Acad::ErrorStatus CPipeAttribute::dwgInFields (AcDbDwgFiler *pFiler) { assertWriteEnabled () ; //----- Read parent class information first. Acad::ErrorStatus es =AcDbObject::dwgInFields (pFiler) ; if ( es != Acad::eOk ) return (es) ; //----- Object version number needs to be read first Adesk::UInt32 version =0 ; if ( (es =pFiler->readUInt32 (&version)) != Acad::eOk ) return (es) ; if ( version > CPipeAttribute::kCurrentVersionNumber ) return (Acad::eMakeMeProxy) ; //读取数据开始 pFiler->readItem(&m_dRadius); pFiler->readItem(&m_dThickness); pFiler->readItem(&m_dDeep); TCHAR *pString=NULL; pFiler->readString(&pString); _tcscpy(m_cMaterial,pString); // 读取数据结束 return (pFiler->filerStatus ()) ; } 对象可以用 DXF 格式来表示,DXF 格式由成对的 DXF 组码和数据构成,组码对应一种 指定的数据类型, 当定义自定义类对象的 DXF 格式时, 函数读写的的一组数据必须是派生类 的数据标记,这个数据标记的 DXF 组码是 100(AcDb::kDxfSubclass),然后是类名的字符串。 对于 DXF 文件操作函数 dxfInFieds 和 dxfOutFieds 也通过文件操作类对象 AcDbDxfFiler 的成员函数 readItem()和 writeItem()来读写数据,用户可以决定数据组是按照一定的顺 序读写还是无顺序读写。如果程序中允许无顺序读写,则在重载函数中必须使用 switch 语句 来选择于 DXF 组码相应的操作, 无顺序读写通常用于那些包含不变的数据域的对象, 而另外 包含可变长度的数组和结构的对象往往采用顺序读写。
5
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

Acad::ErrorStatus CPipeAttribute::dxfOutFields (AcDbDxfFiler *pFiler) const { // 检查对象处于正确的打开状态 assertReadEnabled () ; //父类数据的重载 Acad::ErrorStatus es =AcDbObject::dxfOutFields (pFiler) ; if ( es != Acad::eOk ) return (es) ; es =pFiler->writeItem (AcDb::kDxfSubclass, _RXST("CPipeAttribute")) ; if ( es != Acad::eOk ) return (es) ; //----- Object version number needs to be saved first if ( (es =pFiler->writeUInt32 (kDxfInt32, CPipeAttribute::kCurrentVersionNumber)) != Acad::eOk ) return (es) ; ////写入数据开始 pFiler->writeItem(AcDb::kDxfReal , m_dRadius); pFiler->writeItem(AcDb::kDxfReal+1 , m_dThickness); pFiler->writeItem(AcDb::kDxfReal+2 , m_dDeep); pFiler->writeItem(AcDb::kDxfText ,m_cMaterial); ////写入数据结束 return (pFiler->filerStatus ()) ; } Acad::ErrorStatus CPipeAttribute::dxfInFields (AcDbDxfFiler *pFiler) { assertWriteEnabled () ; //----- Read parent class information first. Acad::ErrorStatus es =AcDbObject::dxfInFields (pFiler) ; if ( es != Acad::eOk || !pFiler->atSubclassData (_RXST("CPipeAttribute")) ) return (pFiler->filerStatus ()) ; //----- Object version number needs to be read first struct resbuf rb ; pFiler->readItem (&rb) ; if ( rb.restype != AcDb::kDxfInt32 ) { pFiler->pushBackItem () ; pFiler->setError (Acad::eInvalidDxfCode, _RXST("\nError: expected group code %d (version #)"), AcDb::kDxfInt32) ; return (pFiler->filerStatus ()) ; } Adesk::UInt32 version =(Adesk::UInt32)rb.resval.rlong ; if ( version > CPipeAttribute::kCurrentVersionNumber ) return (Acad::eMakeMeProxy) ; while ( es == Acad::eOk && (es =pFiler->readResBuf (&rb)) == Acad::eOk ) {
6
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

switch ( rb.restype ) { // 从 DXF 中读取数据 case AcDb::kDxfReal: m_dRadius =rb.resval.rreal ; break ; case AcDb::kDxfReal+1: m_dThickness =rb.resval.rreal ; break ; case AcDb::kDxfReal+2: m_dDeep =rb.resval.rreal ; break ; case AcDb::kDxfText: _tcscpy(m_cMaterial,rb.resval.rstring); break ; default: pFiler->pushBackItem () ; es =Acad::eEndOfFile ; break ; } } if ( es != Acad::eEndOfFile ) return (Acad::eInvalidResBuf) ; return (pFiler->filerStatus ()) ; }
AutoCAD 为撤销操作(UNDO)提供了两中基本的方法,一种是系统默认的自动撤销操 作机制,另外一种是部分撤销操作机制。其中前者通过系统调用函数 dwgOutFields(采用 kUndoFiler 为参数)来复制对象的全部状态来实现,而部分操作机制需要程序对特殊的修改 来读写指定的信息,自动撤销操作通过 assertWriteEnabled()函数来实现。 自定义类中任何修改函数都必须调用函数 assertWriteEnabled , () 用于检查对象是否是用 写的模式打开,当该函数被调用时,首先检查参数 recordModified,如果 recordModified 的值 为 Adesk::kFalse,则不执行任何撤销操作,如果 recordModified 的值为 Adesk::kTrue,则检查 autoUndo 参数,如果参数 autoUndo 为 Adesk::kTrue,则 AutoCAD 将记录对象的状态以便执 行撤销操作,当对象的修改操作完成并关闭对象,操作对象的全部状态将被保存到一个撤销 操作文件中,如果这时的用 UNDO 命令,AutoCAD 调用对象的 dwgInFields()函数把这个 撤销操作文件的内容读入到数据库中。 如果想记录对象的部分状态,自定义类中修改函数都必须在调用函数 assertWriteEnabled ()时将参数 autoUndo 设为 Adesk::kFalse,然后调用 undoFiler::writeItem()(或其他的 undoFiler::writeXXX()函数)把相关的信息保存到撤销操作文件中,如果这时执行 UNDO 操 作,AutoCAD 会调用 applyPartialUndo()读入撤销操作文件中保存的信息。 执行撤销操作时,系统记录当前的状态为重做(REDO)操作做准备,重做操作使用和
7
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

撤销做作相同的文件机制, 即调用 dwgOutFields()函数来记录对象的状态, 不需要编写额外的 代码,如果自定义对象的修改函数实现了部分撤销操作,那么在执行撤销操作的同时为重做 操作做记录,这个过程通常调用相应的 set()函数来事项,它会调用 assertWriteEnabled()来 记录数据。 下面我们结合工程实际说明如何从 AcDbObject 派生自己的类并在程序中使用这个派生 的类。在该例子中我们将为管道定义一个属性类,用于存储管道的属性信息,所定义的属性 类包含以下数据: 表 8-1 管道的属性信息 属性 管径 壁厚 埋深 材质 数据类型 double double double TCHAR
创建一个新的工程 CH081,通过 ObjectARX 工具条的按钮 (第二个) 启动 Autodesk class , Explorer,选择工程 CH081,右键单击,在弹出的右键菜单中选择 Add an ObjectDBX Custom Object…,如图 8-3 所示。
图 8-3 添加自定义类 在弹出的对话框中,从 AcDbObject 派生管道的属性类 CPipeAttribute,如图 8-4.
图 8-4 管道的属性类 在协议页(Protocols) ,选中 DXF Protocol,如图 8-5,其他采用缺省设置。
8
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

图 8-5 重载 DXF 协议 在类定义中添加成员变量: //管径 double m_dRidus; //壁厚 double m_dThickness; //埋深 double m_dDeep; //材质 TCHAR m_cMaterial[128]; 在 CPipeAttribute 类的构造函数中完成数据的初始化,代码如下: CPipeAttribute::CPipeAttribute () : AcDbObject () { m_dRidus = 120.0; m_dThickness = 10.0; m_dDeep = 2.4; _tcscpy(m_cMaterial,_T("水泥管")); } CPipeAttribute 类实现文件读写操作的四个重载函数已经在前面列出,ObjectARX 向导 已经给出了缺省函数的代码,我们只需要添加用户自定义部分的数据。 CPipeAttribute 完成以后, 需要定义一个命令来使用这个属性类, 在工程中添加命令, 将 CPipeAttribute 对象实例作为扩展数据存储到实体的扩展字典中,代码如下: static void CSCH081AddAttribute(void) { AcDbObjectId dictObjId,eId, attId; AcDbDictionary* pDict; //选择管道(多义线) ads_name en; ads_point pt;
9
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

if ( {
acedEntSel(_T("\n 选择管道(多义线): "), en, pt)!= RTNORM) acutPrintf(_T("\n 选择失败,退出: ")); return ;
} // 打开对象 acdbGetObjectId(eId, en); AcDbEntity * pEnt; acdbOpenObject(pEnt, eId, AcDb::kForWrite); if(!pEnt->isKindOf (AcDbPolyline::desc ())) { acutPrintf(_T("\n 选择的不是管道(多义线) ,退出: " )); return ; } // 判断实体的扩展词典是否创建,如果没有则创建 dictObjId = pEnt->extensionDictionary(); if( dictObjId == AcDbObjectId::kNull ) { pEnt->createExtensionDictionary(); } // 获取实体的扩展词典 dictObjId = pEnt->extensionDictionary(); pEnt->close(); // 判断词典中的属性是否创建 CPipeAttribute* pAttribute; acdbOpenObject(pDict, dictObjId, AcDb::kForWrite); pDict->getAt (_T("属性"),attId); if(attId!= AcDbObjectId::kNull )//如果已经创建则输出数据 { acdbOpenObject(pAttribute, attId, AcDb::kForRead); acutPrintf(_T("\n 管径:%4.2f " ),pAttribute->m_dRadius); acutPrintf(_T("\n 壁厚:%4.2f " ),pAttribute->m_dThickness ); acutPrintf(_T("\n 埋深:%4.2f " ),pAttribute->m_dDeep ); acutPrintf(_T("\n 材质:%s " ),pAttribute->m_cMaterial ); } else { //没有则创建属性 pAttribute = new CPipeAttribute(); pDict->setAt(_T("属性"), pAttribute, attId); }
10
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

//关闭对象 pDict->close(); pAttribute->close(); } 将工程编译、运行可以看到 CPipeAttribute 能够将属性数据保存在多义线的扩展字典 中。
8.3 从 AcDbEntity 派生
AcDbEntity 是从 AcDbObject 派生而来, 因此 AcDbEntity 的派生类必须重载 AcDbObject 类所有必须重载的函数, 如文件操作函数, 然后根据需要重载 AcDbObject 类的其他虚函数和 AcDbEntity 类的函数。 AutoCAD 利用 worldDraw()和 viewportDraw()函数来显示实体,对任何由 AcDbEntity 派 生的类必须重载 worldDraw()函数,而对于 viewportDraw()函数来说,则是可选的,下面是函 数原型: Virtual Adesk::Boolean AcDbEntity::worldDraw(AcGiWorldDraw *pWd); Virtual void AcDbEntity::viewportDraw(AcGiViewportDraw *pVd); 当 AutoCAD 需要重新生成图形以显示实体时,会用以下方式调用 worldDraw()和 viewportDraw()函数: if(!entity->worldDraw(pWd)) for(每一个相关视口) entity->viewportDraw(void); 函数 worldDraw()用于绘制实体的图形表达部分, 与指定的模型空间和图纸空间的视口内 容无关,然后调用函数 viewportDraw()绘制于视口相关的部分,如果实体的所有图形表示都 与视图相关, 那么函数 worldDraw()必须返回 kFalse,而且必须重载 viewportDraw()函数。 相反, 如果实体没有与视图相关的图形,则 worldDraw()函数返回 kTrue,而且不需要重载 viewportDraw()函数。 在函数 AcDbEntity::worldDraw(AcGiWorldDraw *pWd)中, 有一个指向 AcGiWorldDrawde 指针对象,它是一个 AcGi 几何对象和特征对象的容器类。另外,AcGeWorldDraw 包含其他 两个对象:AcGIiWorldGeometry 和 AcGiSubEntityTraits。 可以通过 AcGiWorldDraw::geometry()获取 AcGIiWorldGeometry 对象,该对象能够通 过制实体图形的基本绘制命令即图形原型将几何对象写到 AutoCAD 的图形缓存中,世界坐 标系中绘制图形原型的函数主要有 Circle、Circular arc、 Polyline、Polygon、Mesh,Shell、 Text、 Xline 和 Ray。 通过 AcGiWorldDraw::subEntityTraits()函数可以返回 AcGiSubEntityTraits 对象,该对 象能够通过特性函数设置图形的属性值,如 Color,Layer,LineType 等。 在 函 数 void AcDbEntity::viewportDraw(AcGiViewportDraw *pVd) 中 , 有 一 个 指 向 AcGiViewportDraw 指针的对象,它也是一个容器对象,它包含 AcGeViewportGeometry, AcGiSubEntityTraits 和 AcGiViewport 等对象。其中,AcGeViewportGeometry 对象提供了与 AcGeWorldGeometry 相同的图形原型列表,同时增加了 polylineEye() , polygonEye(), polylineDc(),PolygonDc()等函数原型,新添的图形原型使用视觉坐标和显示空间坐标来绘制 多段线。AcGiSubEntityTraints 对象的使用方法与 AcGiWorldDraw 相同,AcGiViewport 对象
11
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

提供了用于查找适口变换矩阵和观察参数的函数。
图 8-6 图形的绘制过程 从上面可以看出图形的绘制过程如下: 1、AutoCAD 创建 AcGiWorldDraw 对象。 2、AutoCAD 创建 AcGiViewportDraw 对象。 3、AutoCAD 将 AcGiWorldDraw 对象传给图形对象。 4、图形对象绘制图形(和视口无关) 。 5、AutoCAD 将 AcGiViewportDraw 传给图形对象。 6、图形对象根据视口绘制图形。 n 实现对象捕捉功能 如果自定义实体支持对象捕捉功能, 则需要重载 getOsnapPoints()函数, 打开捕捉方式后, AutoCAD 会调用该函数获取当前捕捉方式下的相应的捕捉点,在实际的开发过程中,开发者 开发的自定义实体如果不需要支持全部捕捉方式,这个时候在重载的 getOsnapPoints()函数中 只需要对支持的捕捉方式进行处理,对其它不支持的捕捉方式返回 eOk,如果用户激活了多 种捕捉方式,AutoCAD 就会为每种捕捉方式调用一次 getOsnapPoints 函数。 Acad::ErrorStatus CSPolyline::getOsnapPoints( AcDb::OsnapMode osnapMode, int gsSelectionMark, const AcGePoint3d& pickPoint, const AcGePoint3d& lastPoint, const AcGeMatrix3d& viewXform, AcGePoint3dArray& snapPoints, AcDbIntArray& /*geomIds*/) const { assertReadEnabled(); Acad::ErrorStatus es = Acad::eOk; if (gsSelectionMark == 0) return Acad::eOk; if ( osnapMode != AcDb::kOsModeEnd && osnapMode != AcDb::kOsModeMid && osnapMode != AcDb::kOsModeNear && osnapMode != AcDb::kOsModePerp
12
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

&& osnapMode != AcDb::kOsModeCen && osnapMode != AcDb::kOsModeIns) { return Acad::eOk; } AcGePoint3d center; getCenter(center); if (gsSelectionMark == (mNumSides + 1)) { if (osnapMode == AcDb::kOsModeIns) snapPoints.append(center); else if (osnapMode == AcDb::kOsModeCen) snapPoints.append(center); return es; } int startIndex = gsSelectionMark - 1; AcGePoint3dArray vertexArray; if ((es = getVertices3d(vertexArray)) != Acad::eOk) { return es; } AcGeLineSeg3d lnsg(vertexArray[startIndex], vertexArray[startIndex + 1]); AcGePoint3d pt; AcGeLine3d line, perpLine; AcGeVector3d vect; AcGeVector3d viewDir(viewXform(Z, 0), viewXform(Z, 1), viewXform(Z, 2)); switch (osnapMode) { case AcDb::kOsModeEnd: snapPoints.append(vertexArray[startIndex]); snapPoints.append(vertexArray[startIndex + 1]); break; case AcDb::kOsModeMid: pt.set( ((vertexArray[startIndex])[X] + (vertexArray[startIndex + 1])[X]) * 0.5, ((vertexArray[startIndex])[Y]
13
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

+ (vertexArray[startIndex + 1])[Y]) * 0.5, ((vertexArray[startIndex])[Z] + (vertexArray[startIndex + 1])[Z]) * 0.5); snapPoints.append(pt); break; case AcDb::kOsModeNear: pt = lnsg.projClosestPointTo(pickPoint, viewDir); snapPoints.append(pt); break; case AcDb::kOsModePerp: vect = vertexArray[startIndex + 1] - vertexArray[startIndex]; vect.normalize(); line.set(vertexArray[startIndex], vect); pt = line.closestPointTo(lastPoint); snapPoints.append(pt); break; case AcDb::kOsModeCen: snapPoints.append(center); break; default: return Acad::eOk; } return es; } 需要说明的对象的交点捕捉方式通过调用 intersectWith() 函数进行处理,而不是 getOsnapPoints 函数。 n 自定义实体的夹点 当使用鼠标选择了一个 AutoCAD 的实体时,AutoCAD 会显示出实体的夹点。如果要求 自 定 义 实 体 支 持 夹 点 编 辑 功 能 , 则 需 要 重 载 getGripPoints() 和 moveGripPointsAt() 函 数,getGripPoints()函数的实例如下: Acad::ErrorStatus CSPolyline::getGripPoints( AcGePoint3dArray& gripPoints, AcDbIntArray& osnapModes, AcDbIntArray& geomIds) const {
14
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

assertReadEnabled(); Acad::ErrorStatus es; if ((es = getVertices3d(gripPoints)) != Acad::eOk) { return es; } gripPoints.removeAt(gripPoints.length() - 1); AcGePoint3d center; getCenter(center); gripPoints.append(center); return es; } 夹点编辑的拉伸功能允许用户通过把选择的夹点移动到新位置来拉伸实体对象, AutoCAD 通过的用 moveGripPointsAt()函数实现夹点的拉伸功能,但对一些特定的实体移 动一些夹点时移动对象而不是拉伸对象,如圆的圆心,在这种情况下 moveGripPointsAt() 函数调用 transformBy()函数来移动对象。 Acad::ErrorStatus CSPolyline::moveGripPointsAt( const AcDbIntArray& indices, const AcGeVector3d& offset) { if (indices.length()== 0 || offset.isZeroLength()) return Acad::eOk; //that's easy :-) if (mDragDataFlags & kCloneMeForDraggingCalled) { mDragDataFlags |= kUseDragCache; } else assertWriteEnabled(); if (indices.length()>1 || indices[0] == mNumSides) return transformBy(AcGeMatrix3d::translation(offset)); AcGeVector3d off(offset); double rotateBy = 2.0 * 3.14159265358979323846 / mNumSides * indices[0]; AcGePoint3d cent; getCenter(cent); off.transformBy(AcGeMatrix3d::rotation(-rotateBy,normal(),cent)); acdbWcs2Ecs(asDblArray(off),asDblArray(off),asDblArray(normal()),Adesk::kTrue); if (mDragDataFlags & kUseDragCache){ mDragCenter = mCenter; mDragPlaneNormal = mPlaneNormal; mDragStartPoint = mStartPoint + AcGeVector2d(off.x,off.y); mDragElevation = mElevation + off.z;
15
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

}else{ mStartPoint = mStartPoint + AcGeVector2d(off.x,off.y); mElevation = mElevation + off.z; } return Acad::eOk; } 当用户调用夹点编辑中的移动、旋转、缩放和镜像操作时,AutoCAD 调用 transformBy() 函数来实现相应的操作。 n 自定义实体的拉伸点 实体的拉伸点集合实际是实体的夹点集合的一个子集,当用户调用 STRETCH 命令时, AutoCAD 调用实体的 getStretchPoints()函数返回其拉伸点,对于大多数实体来说夹点的编辑 模式和拉神点的变价模式是一致的,函数 getStretchPoints()和 moveStretchPointsAt ()只是调用 了重载的 getGripPoints()和 moveGripPointsAt()函数在程序中可以不重载函数 getStretchPoints() 和 moveStretchPointsAt (),他们默认调用 getGripPoints()和 transformBy()。 Acad::ErrorStatus CSPolyline::getStretchPoints( AcGePoint3dArray& stretchPoints) const { assertReadEnabled(); Acad::ErrorStatus es; if ((es = getVertices3d(stretchPoints)) != Acad::eOk) { return es; } stretchPoints.removeAt(stretchPoints.length() - 1); return es; } n 自定义实体的几何变换 AcDbEntity 类提供了两个变换函数,其中,transformBy()函数对实体进行指定的矩阵操 作变换,另外一个为 getTransformedCopy()函数,它首先复制自身,然后再进行指定的矩阵变 换并返回变换后的复制实体。 Acad::ErrorStatus CSPolyline::transformBy(const AcGeMatrix3d& xform) { if (mDragDataFlags & kCloneMeForDraggingCalled) { mDragDataFlags |= kUseDragCache; mDragPlaneNormal = mPlaneNormal; mDragElevation = mElevation; AcGeMatrix2d xform2d(xform.convertToLocal(mDragPlaneNormal,mDragElevation)); mDragCenter = mCenter; mDragCenter.transformBy(xform2d); mDragStartPoint = mStartPoint;
16
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

mDragStartPoint.transformBy(xform2d); mDragPlaneNormal.normalize(); } else { assertWriteEnabled(); AcGeMatrix2d xform2d(xform.convertToLocal(mPlaneNormal,mElevation)); mCenter.transformBy(xform2d); mStartPoint.transformBy(xform2d); mPlaneNormal.normalize(); } return Acad::eOk; } n 自定义实体的相交函数 实体的相交函数主要有两中形式: virtual Acad::ErrorStatus intersectWith( const AcDbEntity* pEnt, AcDb::Intersect intType, AcGePoint3dArray& points, int thisGsMarker = 0, int otherGsMarker = 0) const; virtual Acad::ErrorStatus intersectWith( const AcDbEntity* pEnt, AcDb::Intersect intType, const AcGePlane& projPlane, AcGePoint3dArray& points, int thisGsMarker = 0, int otherGsMarker = 0) const; 第一种形式对两个实体的简单点进行测试,第二种形式在一个投影面上计算交点,这两 种形式都返回在实体自身上的交点。重载 intersectWith 函数应该遵循一下原则: 1. 每个自定义实体都应该能够处理与 AutoCAD 中定义实体如 AcDbLine 等的求交操作 2. 如果自定义实体的intersectWith函数被调用时的实体参数不是AutoCAD 中缺省定义的 实体,应用程序需要把该自定义实体分解为一系列可以识别的 AutoCAD 中缺省实体,然后 对这些分解所得的实体逐一调用 intersectWith 函数。 Acad::ErrorStatus CSPolyline::intersectWith( const AcDbEntity* ent, AcDb::Intersect intType, const AcGePlane& projPlane, AcGePoint3dArray& points, int /*thisGsMarker*/, int /*otherGsMarker*/) const {
17
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

assertReadEnabled(); Acad::ErrorStatus es = Acad::eOk; if (ent == NULL) return Acad::eNullEntityPointer; if (ent->isKindOf(AcDbLine::desc())) { if ((es = intLine(this, AcDbLine::cast(ent), intType, &projPlane, points)) != Acad::eOk) { return es; } } else if (ent->isKindOf(AcDbArc::desc())) { if ((es = intArc(this, AcDbArc::cast(ent), intType, &projPlane, points)) != Acad::eOk) { return es; } } else if (ent->isKindOf(AcDbCircle::desc())) { if ((es = intCircle(this, AcDbCircle::cast(ent), intType, &projPlane, points)) != Acad::eOk) { return es; } } else if (ent->isKindOf(AcDb2dPolyline::desc())) { if ((es = intPline(this, AcDb2dPolyline::cast(ent), intType, &projPlane, points)) != Acad::eOk) { return es; } } else if (ent->isKindOf(AcDb3dPolyline::desc())) { if ((es = intPline(this, AcDb3dPolyline::cast(ent), intType, &projPlane, points)) != Acad::eOk) { return es; } } else { AcGePoint3dArray vertexArray; if ((es = getVertices3d(vertexArray)) != Acad::eOk) { return es; } if (intType == AcDb::kExtendArg || intType == AcDb::kExtendBoth) {
18
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

intType = AcDb::kExtendThis; } AcDbLine *pAcadLine; int i; for (i = 0; i < vertexArray.length() - 1; i++) { pAcadLine = new AcDbLine(); pAcadLine->setStartPoint(vertexArray[i]); pAcadLine->setEndPoint(vertexArray[i + 1]); pAcadLine->setNormal(normal()); if ((es = ent->intersectWith(pAcadLine, intType, projPlane, points)) != Acad::eOk) { delete pAcadLine; return es; } delete pAcadLine; } n 自定义实体的分解 要使AutoCAD 的 BHATCH 和EXPLODE 命令对自定义实体起作用, 则必须重载explode() 函数。自定义的 explode()函数应该能为实体分解为复杂程度小的实体。如果分解以后的实体 不是固有的实体,则函数返回 explodeAgain。这将导致 BHATCH 对所返回的实体递归调用 explode,直到他们分解为 AutoCAD 缺省定义的实体为止。 Acad::ErrorStatus CSPolyline::explode(AcDbVoidPtrArray& entitySet) const { assertReadEnabled(); Acad::ErrorStatus es = Acad::eOk; AcGePoint3dArray vertexArray; if ((es = getVertices3d(vertexArray)) != Acad::eOk) { return es; } AcDbLine* line; for (int i = 0; i < vertexArray.length() - 1; i++) { line = new AcDbLine(); line->setStartPoint(vertexArray[i]); line->setEndPoint(vertexArray[i + 1]); line->setNormal(normal()); entitySet.append(line); } AcDbText *text ;
19
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

if ((mpName != NULL) && (mpName[0] != _T('\0'))) { AcGePoint3d center,startPoint; getCenter(center); getStartPoint(startPoint); AcGeVector3d direction = startPoint - center; if (mTextStyle != AcDbObjectId::kNull) text =new AcDbText (center, mpName, mTextStyle, 0, direction.angleTo (AcGeVector3d (1, 0, 0))) ; else text =new AcDbText (center, mpName, mTextStyle, direction.length() / 20, direction.angleTo (AcGeVector3d (1, 0, 0))) ; entitySet.append (text) ; } return es; } 下面我们通过实例来说明自定义实体的创建,通常我们把自定义实体创建为一个 DBX 工程, 在通过 ObjectARX 向导创建工程的时候可以设置工程的类型, 如图 8-7 所示, 这样工程编译后生成扩展名为 DBX 的文件。
图 8-7 创建 DBX 工程 前面我们从 AcDbObject 类派生了一个管道属性类, 当使用属性类的时候, 需要把属性类 实例保存在实体的扩展词典中,现在我们创建自定义实体,将管道属性数据直接保存为自定 义实体的自身数据,选择从 AcDbPolyline 类派生,而不是直接从 AcDbEntity 类派生,这样可 以已有对象的特性,避免重复性的工作。使用 ObjectARX 向导创建自定义实体类的过程和 AcDbObject 类派生了一个管道属性类一样,我们创建自定义实体类 CPipeLine,如图 8-8。
20
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

用户定义数据类型与自定义函数

数据库系统原理实验报告 实验名称:__用户定义数据类型与自定义函数_ 指导教师:_叶晓鸣刘国芳_____ 专业:_计算机科学与技术_ 班级:__2010级计科班_ 姓名:_文科_____学号: 100510107 完成日期:_2012年11月10日_成绩: ___ ___一、实验目的: (1)学习和掌握用户定义数据类型的概念、创建及使用方法。 (2)学习和掌握用户定义函数的概念、创建及使用方法。 二、实验内容及要求: 实验 11.1 创建和使用用户自定义数据类型 内容: (1)用SQL语句创建一个用户定义的数据类型Idnum。 (2)交互式创建一个用户定义的数据类型Nameperson。 要求: (1)掌握创建用户定义数据类型的方法。 (2)掌握用户定义数据类型的使用。 实验 11.2 删除用户定义数据类型 内容: (1)使用系统存储过程删除用户定义的数据类型Namperson。 (2)交互式删除用户定义的数据类型Idnum。 要求: (1)掌握使用系统存储过程删除用户定义的数据类型。 (2)掌握交互式删除用户定义的数据类型。 实验 11.3 创建和使用用户自定义的函数 内容: (1)创建一个标量函数Score_FUN,根据学生姓名和课程名查询成绩。 (2)创建一个内嵌表值函数S_Score_FUN,根据学生姓名查询该生所有选课的成绩。 (3)创建一个多语句表值函数ALL_Score_FUN,根据课程名查询所有选择该课程学生的成绩信息。

要求: (1)掌握创建标量值函数的方法。 (2)掌握创建内嵌表值函数的方法。 (3)掌握创建多语句表值函数的方法。 实验 11.4 修改用户定义的函数 内容: (1)交互式修改函数Score_FUN,将成绩转换为等级输出。 (2)用SQL修改函数S_Score_FUN,要求增加一输出列定义的成绩的等级。要求: (1)掌握交互式修改用户定义函数的方法。 (2)掌握使用SQL修改用户定义函数的方法。 实验 11.5 输出用户定义的函数 内容: (1)交互式删除函数Score_FUN。 (2)用SQL删除函数S_Score_FUN。 要求: (1)掌握交互式删除用户定义函数的方法。 (2)掌握使用SQL删除用户定义函数的方法。

vb用户自定义的数据类型

用户自定义的数据类型------记录 保存多个相同或不同类型数值的结构称为记录(record)。 在VISUAL BASIC 中定义记录,用Type语句,其语法如下: Type varType Variable1 As varType Variable2 As varType … Variablen As varType End Type 例如定义一个名为CheckRecord的记录: Type CheckRecord CheckNumber as Integer CheckDate as Date CheckAmount as Single End Type CheckRecord结构可以像普通变量类型一样使用。要定义这个类型的变量,使用如下语句: Dim check1 As CheckRecord 要对结构的各个字段访问,可使用如下语句: check1. CheckNumber=123 check1. CheckDate=#08/14/1996# check1. CheckAmount=240.00 例: 简单例(自定义类型1.frm) 数组自定义类型1.FRM 用一维数组存放学生年龄。并可通过学生姓名输入或显示该学生的年龄。 Private Type StudentInformation StudentAge As Integer StudentName As String End Type Dim N As Boolean Dim Information(1 To 4) As StudentInformation Dim infIndex As Integer Dim stuName As String Private Sub cmdInputname_Click() For i = 1 To 4 Information(i).StudentName = InputBox("PL input name") Next i End Sub Private Sub cmdInput_Click() infIndex = 1 N = False

SQL_用户自定义的数据类型、规则、默认

用户自定义的数据类型、默认值、规则 一、用户自定义的数据类型 用户自定义数据类型可看做是系统数据类型的别名。 在多表操作的情况下,当多个表中的列要存储相同类型的数据时,往往要确保这些列具有完全相同的数据类型、长度和为空性(数据类型是否允许为空)。例如,对于student数据库中表student、grade和course三张表的xh,kh两个列必须具有相同的数据类型。 创建用户自定义数据类型时首先应考虑如下三个属性: (1)数据类型名称 (2)新数据类型所依据的系统数据类型(又称为基类型) (3)为空性 如果为空性未明确定义,系统将依据数据库或连接的ANSI NULL 默认设置进行指派。 1、创建用户自定义数据类型的方法如下: (1)利用企业管理器定义 (2)利用SQL命令定义数据类型 在SQL Server中,通过系统存储过程实现用户数据类型的定义。 语法格式如下: sp_addtype [@typename=] type, /*自定义类型名称*/ [@phystype=] system_data_type /*基类型*/ [,[@nulltype=] null_type /*为空性*/

[,[@owner=] owner_name] /*创建者或所有者*/ 其中: type:用户自定义数据类型的名称。 System_data_type:用户自定义数据类型所依据的基类型。如果参数中嵌入有空格或标点符号,则必须用引号将该参数引起来。 null_type:指明用户自定义数据类型处理空值的方式。取值可为’NULL’、’NOT NULL’、’NONULL’三者之一(注意:必须用单引号引起来)。如果没有用sp_addtype显式定义null_type,则将其设置为当前默认值,系统默认值一般为’NULL’。 例:定义学号字段的数据类型 sp_addtype ’student_xh’,’char(4)’,’not null’ 2、删除用户自定义数据类型 (1)利用企业管理器 (2)利用SQL语句 语法格式如下: sp_droptype [@typename=] type 其中type为用户自定义数据类型的名称,应用单引号括起来。 例:删除student_xh用户自定义数据类型 sp_droptype ’student_xh’ 说明: (1)如果在表定义内使用某个用户定义的数据类型,或者将

AB PLC编程软件RSLOGIX5000入门7——UDT用户自定义数据类型

AB PLC编程软件RSLOGIX5000入门7——UDT用户自定义数据类型 在本章中,我们将介绍如何通过用户自定义数据类型和数据范围划定来规划标签数据库。这里将学到 § 了解使用 UDT 的优势 § 学习如何优化 UDT 规划 § 使用数据范围划定帮助简化并加快开发工作 我们现在将重点关注 Logix 控制器中的数据规划。 打开现有控制器文件 1. 在计算机桌面上,双击 Lab Files 文件夹。 2. 双击名为 Conveyor_Program_S 3.ACD 的现有项目。 这样将在 RSLogix 5000 中启动该项目。 为传送带创建用户自定义数据类型 您已重新组织了程序规划以更好地利用 Logix,现在已准备好开始对数据规划进行重新组织。可注意到,工程师规划数据的方式仍像使用带有整数、实数和定时器数据表的传统 PLC 一样。问题是,当与设备关联的数据分布到控制器内存中的各处时便很难进行跟踪。您已再次决定充分利用 Logix,使用用户自定义数据类型。 用户自定义数据类型 用户自定义数据类型也称为 UDT 或结构,借此按逻辑方式对数据进行组织或分组,以便所有与设备关联的数据都可组合在一起。 例如,每个传送带都有 8 个整数值、3 个实数值、2 个定时器和 11 个与其关联的布尔值。在传统PLC 中,可能需要 4 个不同的数据表。然后,当您具有多条传送带时,您可能需要详细地将传送带映射到各个数据表中。这样就会变得很难管理。 通过 UDT 能够实现的是将不同的数据类型(整数、实数、定时器、布尔等)组合到一起,共同作为用户自定义数据类型。然后便可创建该 UDT 类型的数组。这可使得编程工作、代码的记录和数据的跟踪都更加轻松。 1. 在控制器项目管理器中,双击"控制器标签"(Controller Tags)。

第8章 自定义对象

第8章
本章简介 8
自定义对象
?自定义对象的概念。 ?从 AcDbObject 派生对象。 ?从 AcDbEntity 派生自定义实体。
学习要点
? 了解自定义对象的概念及其的应用。 ? 掌握从 AcDbObject 派生对象。 ? 掌握自定义实体的创建方法。
我们在前面介绍了通过扩充数据方式来存储扩充数据,虽然能满足一定的工程需求,但 是由于最终的扩展数据通过结果缓冲链表的方式存储,缺少面向对象特性,在处理的时候比 较繁琐, 我们完成可以定义自己的类来封装数据, 此种情况下我们需要通 AcDbObject 派生数 据库对象;另外,AutoCAD 是一个通用的 CAD 平台,提供如点、线等通用的对象类型,我 们可以针对行业特征派生自己的实体,如定义螺栓类、管道类等,这些派生的实体除了具有 自己的几何形体外,还包含自己所有的一些数据,如管道的管径、材质等属性。本章我们介 绍一下自定义数据库对象的概念和方法,用户可以根据自己的实际需求派生一套面向行业的 对象类型。
8.1
自定义对象
在介绍自定义对象之前, 我们需要对 AutoCAD 中数据库对象的层次关系有所了解了 解,这有助于我们理解后面的实际应操作,AutoCAD 中数据库对象的层次关系如图 8-1 所示。
1
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

图 8-1AutoCAD 中数据库对象的层次关系 从图 8-1 我们看出所有的数据库对象类都派生自 AcRxObject,该类是所有数据库对 象的基类,它主要实现对象运行时类型识别机制,提供一些用于类型识别的重要函数,它 提供的函数主要有一下几个: n desc() : 静态成员函数,返回指定类的类描述符对象。 n cast(): 返回指定类型的对象。 n isKindOf(): 用于判断对象是否属于指定类或者派生类。 n isA() :返回未知类对象的类描述符对象。 我们在介绍实体操作的时候讲过如何使用这些函数, 这里我们需要在这里介绍这些函 数的实现机制,从 AcRxObject 派生的类都包含一个相应的类描述符对象,用 AcRxClass 类表示, 它包含了运行使类型的识别信息,AcRxObject 的派生类包含一个指向 AcRxClass 对象的指针(gpDesc),可以通过 AcRxObject::desc()获取这个 AcRxClass 对象指针,而 AcRxClass 对象包含一个指向其父对象 AcRxClass 的指针, 这样构成了类的运行时类层次 表,如图 8-2,我们可以调用 AcRxObject::isKindOf()来判断对象是否是从某个类派生 出来。
图 8-2 行时类层次表 在派生自定义类中要实现运行类的识别信息, 也就是要重载上面提到的 desc()、 isKindOf()
2
PDF 文件使用 "pdfFactory Pro" 试用版本创建 https://www.doczj.com/doc/432003239.html,

SAP自定义权限对象创建步骤

创建自定义权限对象 步骤1:事务代码SU21(Maintain Authorization Objects),单击创建。 选择“Object class”(如果已经有的Object Class能满足需要则不要此步,直接做步骤三) 步骤2:填入Object class和Text名称,然后保存。

步骤3:单击创建,选择“Authorization Object”。

步骤4:填入Object,Text,class名称,在Authorization fields的fields name中加入需要控制的字段名,然后保存,完成自定义权限对象的创建。(如果已经存在的字段没有满足需要的,则需要点击“Fields maintenance”按钮做步骤五)

步骤5:单击创建

步骤6:单击创建填入所需Fields Name, Data element, Table Name名称,保存。返回步骤四,填入刚刚建好的字段名称,保存。完成全线对象的创建。 步骤7:用事务代码PFCG,手工分配自定义的权限对象。 步骤8:在程序控制写入代码控制自定义权限对象。

Function module:EXIT_SAPLMGMU_001 INCLUDE ZXMG0U02. *&---------------------------------------------------------------------* *& Include ZXMG0U02 *&---------------------------------------------------------------------* TABLES: MAKT. IF sy-tcode = 'MM01' OR sy-tcode = 'MM02'. AUTHORITY-CHECK OBJECT 'ZMATNR' ID 'ACTIVITY' FIELD '01'. IF sy-subrc NE 0. SELECT SINGLE * FROM MAKT WHERE MATNR = WMARA-MATNR AND SPRAS = SY-LANGU. READ TABLE STEXT WITH KEY SPRAS = SY-LANGU. IF SY-SUBRC = 0. IF STEXT-MAKTX <> MAKT-MAKTX. MESSAGE 'You have not the authority change material text' TYPE 'E'. ENDIF. ELSE. MESSAGE 'You have not the authority change material text' TYPE 'E'. ENDIF. ENDIF. ENDIF. 注意:Object name, Object field name及Object field值可根据实际情况修改。 上面示例程序定义为,Object field ‘ACTIVITY’= 01时为可修改物料描述 当‘ACTIVITY’等于其他值时则未不可修改。

abplc7用户自定义数据类型

UDT----用户自定义数据类型(看不懂也要坚持一下,理解了这部分就不是新手了) 在本章中,我们将介绍如何通过用户自定义数据类型和数据范围划定来规划标签数据库。这里将学到 § 了解使用 UDT 的优势 § 学习如何优化 UDT 规划 § 使用数据范围划定帮助简化并加快开发工作 我们现在将重点关注 Logix 控制器中的数据规划。 打开现有控制器文件 1. 在计算机桌面上,双击Lab Files文件夹。 2. 双击名为Conveyor_Program_S 3.ACD的现有项目。 这样将在 RSLogix 5000 中启动该项目。 为传送带创建用户自定义数据类型 您已重新组织了程序规划以更好地利用 Logix,现在已准备好开始对数据规划进行重新组织。可注意到,工程师规划数据的方式仍像使用带有整数、实数和定时器数据表的传统 PLC 一样。问题是,当与设备关联的数据分布到控制器内存中的各处时便很难进行跟踪。您已再次决定充分利用 Logix,使用用户自定义数据类型。 用户自定义数据类型 用户自定义数据类型也称为 UDT 或结构,借此按逻辑方式对数据进行组织或分组,以便所有与设备关联的数据都可组合在一起。 例如,每个传送带都有 8 个整数值、3 个实数值、2 个定时器和 11 个与其关联的布尔值。在传统PLC 中,可能需要 4 个不同的数据表。然后,当您具有多条传送带时,您可能需要详细地将传送带映射到各个数据表中。这样就会变得很难管理。 通过 UDT 能够实现的是将不同的数据类型(整数、实数、定时器、布尔等)组合到一起,共同作为用户自定义数据类型。然后便可创建该 UDT 类型的数组。这可使得编程工作、代码的记录和数据的跟踪都更加轻松。 1. 在控制器项目管理器中,双击"控制器标签"(Controller Tags)。

SAP自定义权限对象之SU20

自定义权限对象 若标准权限对象在不同的角色中给与不同的权限,且都分配同一用户,这样用户的权限就会受到影响。例如:MY-ZLS-MM-6000-0001 某工厂物料主数据会计视图维护里面有标准的权限对象M_MATE_WRK控制只运行6000工厂,MY-ZLS-MM-0002-01 某集团物料主数据查询-有价格里面有标准的权限对象M_MATE_WRK控制允许所有工厂查询,若将MY-ZLS-MM-6000-0001和MY-ZLS-MM-0002-01同事赋给同一用户,那该用户就能创建所有工厂物料主数据。这样就需要手工增加权限对象控制工厂,并将权限对象手工加在MY-ZLS-MM-6000-0001中控制6000工厂。 1.su20 创建权限对象中控制的字段 创建自定义权限对象中需要控制的字段,一般在标准AUTHX表中都有需要控制的字段如公司代码、工厂等。 1.1.查询需要控制的字段名称 PFCG 1.2.SU20中查看有没有该字段 一般情况下,在AUTHX表中都有标准字段,若是特殊字段在该表中没有,可以通过SU20创建 2.su21 创建权限对象 选择需要创建权限对象的组,创建的权限对象保存在TOBCT表中

3.程序中书写,将权限对象加到程序中 在程序中加上类似代码: authority-check object 'V_VBKA_VKO' id 'VKORG' p_vkorg id 'ACTVT' '03'. 4.pfcg为角色分配权限 这是属于BASIS的部分,但是开发人员需要了解。选择需要修改的权限角色,第二栏为权限,可以添加事务码,之后在更改用户权限里面,点击授权对象,这时,前面为CM标记的权限对象会出现,标记为C的不会出现,需要手动分配。

JS中自定义类和对象

5 自定义类和对象 5.1 工厂方法 在ECMAScript中创建工厂方法,返回一个特定类型的对象,以此实现代码的简洁适用。 function createFruit() { var tempFruit = new Object; https://www.doczj.com/doc/432003239.html, = "apple"; tempFruit.number = 5; tempFruit.showName = function() { alert(https://www.doczj.com/doc/432003239.html,); }; return tempFruit; } var Fruit1 = creatFruit(); var Fruit2 = creatFruit(); 在createFruit()中可以加入形参来传入参数的值。随着ECMAScript不断被规范化,这种创建对象的方法已不再流行,一部分原因是语法上的,一部分原因是功能上的,如每个对象的实例都拥有属于自己的showName方法,给内存管理带来一定的开销。 5.2 构造函数 选择一个类名,第一个字母大写,该类名即是构造函数的名称。创建一个构造函数和工厂方法比较类似,不同的是需要使用关键字new来创建对象的引用。使用构造函数的方式来创建对象和使用工厂方法有着相同的弊端。

function Fruit(name, number) { https://www.doczj.com/doc/432003239.html, = name; this.number = number; this.showName = function() { alert(https://www.doczj.com/doc/432003239.html,); }; } var Fruit1 = new Fruit("apple", 5); var Fruit2 = new Fruit("pear", 3); 5.3 使用Prototype 使用prototype属性可以用来创建新的对象,首先需要一个空的构造函数建立类的名称,然后所有的属性和方法都直接分配到prototype属性中。 function Fruit() { } https://www.doczj.com/doc/432003239.html, = "apple"; Fruit.prototype.number = 5; Fruit.prototype.showName = function() { alert(https://www.doczj.com/doc/432003239.html,); }; var fruit1 = new Fruit(); var fruit2 = new Fruit(); 但是,这样同样存在一些缺点。首先,构造函数中没有参数,给初始化带来一些麻烦,其次,当一个属性指向的是一个对象而非方法时,该对象会被所有的实例所共享,任何一点改动都会影响到其他对象引用的使用。

相关主题
文本预览
相关文档 最新文档