数据库是控件最重要的部分, 所有图形信息都储存在数据库中 ,因此掌握数据库是控件开发的基础。数据库对象包括 实体、块表记、符号表记录和字典 ,数据库对象组成了数据库。数据库的结构如下图:
数据库概述
控件数据库中存储了构成图形的对象和实体。图形是存储在数据库中对象的集合,基本的数据库对象包括实体、符号表和字典。
实体是一种指定类型的数据库对象,它在控件屏幕上有图形表示,实体的例子有 直线、圆、圆弧、文字、曲线和椭圆 等。用户在屏幕上可以看见实体并且可以对它进行操作。
符号表和字典是用来 存储数据库对象的容器对象 ,这两种对象都可以将一个符号名映射到一个数据库对象。控件数据库包括固定数目的符号表,每一个符号表包含了一种特定类的实例作为符号表记录。符号表的例子如层表(McDbLayerTable,包含层表记录)和块表(McDbBlockTable,包含块表记录),所有实体都属于块表记录。
字典提供了一个比符号表更加通用的容器对象来存储对象,一个字典可以 包含任何McDbObject类或其他子类的对象 。
在一个使用控件过程中,可以装入多个数据库,其中每一个对象都有自己的句柄和对象ID。这个唯一的句柄用来在一个特定的数据库中识别对象,而唯一的对象ID用来在同一时间装入的数据库中识别对象。
对象ID只存在于编辑过程中,而句柄可以保存在图形中。与对象ID相比,当在一个编辑过程中装入多个数据库时,句柄不一定是唯一的。
通过对象ID,用户可以获得一个实际数据库对象的指针,这样用户就可以对对象执行操作。用户可以通过下面的方法获得对象ID:
1. 建一个对象并将它添加到数据库中。数据库会赋予对象一个对象ID并且返回给用户。
2. 使用一个遍历器来遍历一组对象。McDb库提供了一些遍历器来浏览不同类型的容器对象(McDbDictionaryIterator和McDbObjectIterator)。
3. 查询一个选择集。当选择了一个对象后,用户可以询问选择集来获得所选择对象的实体名列表,然后将这些实体名转换成对象ID。
4. 由实体名柄得到实体ID
5. 由实体名得到实体ID
控件数据库中包含了以下元素:
符号表和对应类如下:
名称 | 类型 |
---|---|
块表 | McDbBlockTable |
层表 | McDbLayerTable |
线型表 | McDbLinetypeTable |
文本样式表 | McDbTextStyleTable |
一些符号表中已经包含了一个或多个记录。如层表中有一个记录0层,块表中有个*MODEL_SPACE记录,而线型表中包含一个记录:CONTINUOUS。
命名对象字典:
用户可以使用 new命令创建 一个数据库,使用 delete命令删除 一个数据库。 可以使用下面的函数读取一个图形文件:
Mcad::ErrorStatus McDbDatabase::readDwgFile(LPCTSTR filename);
注意:一定不要删除由Mx::mcdbHostApplicationServices()->workingDatabase()函数返回的数据库,因为它返回的是当前工作的数据库。
要保存一个数据库,可以使用 McDbDatabase::saveAs() 函数。
saveAs function
作用:保存一个数据库。
接口:Mcad::ErrorStatus saveAs(
LPCTSTR pszFileName,
const void* pSecParams = 0,
LPCTSTR wszPassword = NULL,
McDb::McDbDwgVersion version = McDb::kDHL_1015,
McDb::SaveType type = McDb::kDwg,
byte** ppRetData =NULL,
long* pRetDataLength = NULL
参数:
名称 | 说明 |
---|---|
pszFileName | DWG文件路径 |
pSecParams | 暂没使用 |
wszPassword | 暂没使用 |
version | DWG文件版本 |
type | 文件类型,可以是DWG或DXF |
ppRetData | 把数据保存到内存中,返回的数据需要free函数释放 |
pRetDataLength | 返回数据的长度 |
返回值:如果成功返回Mcad::eOk,如果传递的数据非法则返回Mcad::eInvalidInput。
参考例程:
McDbDatabase * pDatabase1 = new McDbDatabase; auto dsa = pDatabase1->readDwgFile(L"D:\\MxDraw\\Tech\\database\\测试.mxg"); pDatabase1->saveAs( L"D:\\MxDraw\\Tech\\database", nullptr, nullptr, McDb::kDHL_1015, McDb::kDxf);
要保存一个数据库,可以使用 McDbDatabase::saveAs() 函数。
如果两个数据库合并时发生冲突(例如两个数据库有相同的线型名),则在控件中使用目标数据库的数据。
下面的函数与标准的图形插入命令等价:
Mcad::ErrorStatus McDbDatabase::insert(McDbObjectId& blockId, LPCTSTR pBlockName, McDbDatabase* pDb);
Insert function
作用:将一个数据库复制到调用这个成员函数的数据库中。
接口:Mcad::ErrorStatus insert(
McDbObjectId & blockId,
LPCTSTR pszBlockName,
McDbDatabase* pDb,
bool preserveSourceDatabase = true,
bool isUpdataSameNameBlock = true);
参数:
名称 | 说明 |
---|---|
blockId | 返回新插入的图块表记录id |
pszBlockName | 新插入的图块表记录名,图块为空时,就把文件中所有图块都引进到当前图纸中 |
pDb | 插入的数据库指针 |
preserveSourceDatabase | 暂没使用 |
isUpdataSameNameBlock | 如果插入的数据库的图块名与当前数据库的图块名同名,需要不需要重新更新该图块 |
返回值:如果成功返回Mcad::eOk,如果传递的数据非法则返回Mcad::eInvalidInput。
参考例程:
AcDbDatabase db(Mdesk::kFalse ); if( db.readDwgFile( sBlkFileName ) != Acad::eOk ) { return FALSE; } if ( pDatabase->insert( blkRecId, sBlkName, &db ) != Acad::eOk ) { return FALSE; }
这个函数将实体从输入数据库的模型空间复制到指定的块表记录中,同时返回新块表记录的ID。
如果用户 没有指定一个实体的属性 (例如颜色和线型),则 实体的属性使用数据库的当前属性 。下面我们将对数据库的属性作一个详细介绍。
数据库颜色值
如果实体的颜色没有指定,则实体的颜色将使用存储在CECOLOR系统变量中的数据库当前颜色值。下面的函数可以用来设置和获得数据库当前的颜色值:
Mcad::ErrorStatus McDbDatabase::setCecolor(const McCmColor& color); McCmColor McDbDatabase::cecolor() const;
数据库线型值
下面的函数可以用来设置和获得数据库当前的线型值:
Mcad::ErrorStatus McDbDatabase::setCeltype(McDbObjectId); McDbObjectId McDbDatabase::celtype() const;
数据库线型比例值
在数据库中有2个线型比例设置:
1. 当前实体的线型比例,保存在CELTSCALE系统变量中
2. 当前图形的线型比例,保存在LTSCALE系统变量中
全局的LTSCALE设置在图形重新生成时使用,可以使用下面的函数来设置或获取这些值:
设置 LTSCALE 中的比例 Mcad::ErrorStatus McDbDatabase::setLtscale(double);
读取 LTSCALE 中的比例double McDbDatabase::ltScale() const;
设置 默认线型缩放比例 中的比例 Mcad::ErrorStatus McDbDatabase::setCeltscale(double);
读取 默认线型缩放比例 中的比例double McDbDatabase::celtscale() const;
数据库层值
下面的函数可以用来设置和获取数据库当前的层值:
Mcad::ErrorStatus McDbDatabase::setClayer(McDbObjectId); McDbObjectId McDbDatabase::clayer() const;
每一个数据库对象都可以通过下面3种方式来获得:
通过对象句柄
通过对象ID
通过C++实例指针
当控件没有运行时,图形保存在文件系统中,而包含在DWG文件中的对象是通过它的句柄来识别的。
当图形打开后,图形信息可以通过McDbDatabase对象来访问。在数据库中每一个对象都有一个对象ID,这个对象ID保存在当前编辑过程中,从McDbDatabase的创建直到删除,对象ID一直存在。对象打开函数将对象ID作为参数,返回一个McDbObject对象指针。这个指针在对象被删除前一直有效。
可以使用Mx::mcdbOpenObject()函数来打开对象,该函数的原型如下:
Mcad::ErrorStatus mcdbOpenMcDbObject ( McDbObject*& obj, McDbObjectId id, McDb::OpenMode mode, Mdesk::Boolean openErasedObject = Mdesk::kFalse); Mcad::ErrorStatus mcdbOpenObject(T_OBJECT*& pObj, McDbObjectId id, McDb::OpenMode mode, bool openErased = false);
可以使用下面的函数通过句柄获取对象ID,函数原型如下:
Mcad::ErrorStatus McDbDatabase::getAcDbObjectId(McDbObjectId& retId,Mdesk::Boolean createIfNotFound, const McDbHandle& objHandle, Mdesk::UInt32 xRefId=0);
可以使用McDbObjectPointer模板类打开:
McDbObjectPointer(McDbObjectId objId, McDb::OpenMode mode, bool openErased = false);
当然,也可以打开一个对象,然后获得此对象的句柄:
pObject->getMcDbHandle(handle);
mds_name与对象ID作用是相同的,在McDb库中提供了两个单独的函数在mds_name和McDbObjectId之间转换,函数原型如下:
mcdbGetAdsName(mds_name& objName, McDbObjectId objId); mcdbGetObjectId(McDbObjectId& objId, mds_name objName);
可以使用如下方式打开对象:
kForRead:读方式。如果对象没有被以写方式打开,它可以被最多256个使用者以读方式打开。
kForWrite:写方式。如果一个对象没有被打开,则它可以被以写方式打开,否则打开对象的操作将失败。
可以使用 McDbObject::new() 函数来创建一个McDbObject对象的实例并将它添加到数据库中。当对象刚被创建还没有添加到数据库中时,用户可以删除它,但是,一旦 对象被添加到了数据库 ,用户就 不能删除 该对象,而由控件来管理数据库对象的删除工作。
数据库中的任何对象都可以使用下面的函数删除:
Mcad::ErrorStatus McDbObject::erase(Mdesk::Boolen Erasing = Mdesk::kTrue);
对数据库对象和实体来说,使用erase()函数将会有不同的结果。当数据库对象被擦除时,该对象的相关信息都被从字典中删除,如果使用erase(kFalse)恢复对象,相关信息 不能自动恢复 ,必须使用 setAt() 函数将想关信息重新添加到字典中。当用户擦除一个实体时,它仅仅在块表记录中作了一个被擦除的标记,可以使用erase(kFalse)恢复对象。
使用Mx::mcdbOpenObject和Mx::mcdbOpenMcDbObject打开后删除不可恢复。
使用McDbObjectPointer智能指针打开后,删除可以恢复。
用户可以在自己的应用程序中使用2种机制来添加对象指定数据,这2种机制如下:
扩展数据(xdata)
扩展记录
扩展数据
扩展数据是一个结果缓冲区链表,应用程序可以访问这个链表。数据是通过从 1000~1071 的DXF组码相关联的。这种机制可以节省空间,并且使得向对象添加数据变得很容易。但是扩展数据大小必须限制在 16K以内 ,而且必须是属于DXF组码的数据类型。
可以使用McDbObject::xData()函数获得在对象中复制扩展数据的链表,该函数的原型如下:
virtual resbuf* McDbObject::xData(const char* regappname = NULL) const;
也可以使用McDbObject::setXData()函数来设置对象的扩展数据,该函数的原型如下:
virtual Mcad::ErrorStatus McDbObject::setXData(const resbuf* xdata);
setXData function
接口:virtual Mcad::ErrorStatus setXData(const struct resbuf* xdata);
参数:
名称 | 说明 |
---|---|
xdata | 扩展数据链表指针,在不使用时调用Mx::mcutRelRb释放链表 |
返回值:如果成功返回Mcad::eOk。
参考例程:
void CTestCommands::TestDataWrite() { MrxDbgSelSet mSelset; mSelset.userSelect(); McDbObjectIdArray vId; mSelset.asArray(vId); ID = vId[0]; McDbObjectPointer<McDbText> spText(ID, McDb::kForWrite); CString sAppName = _T("TestExData"); int iValue = 999; acdbRegApp(sAppName); struct resbuf* pExDataRb = acutBuildList(1001, sAppName, AcDb::kDxfXdInteger16, iValue, 0); spText->setXData(pExDataRb); }
xData function
接口:virtual struct resbuf* xData (LPCTSTR pszRegappName = NULL) const;
参数:
名称 | 说明 |
---|---|
pszRegappName | 扩展数据应用名,如果为空返回所有扩展数据 |
返回值:返回扩展数据链表,不需要是调用 Mx::mcutNewRb释放内链表。
参考例程:
void CTestCommands::TestDataRead() { McDbObjectPointer<McDbText> spText(ID, McDb::kForWrite); struct resbuf* pExDataRb = spText->xData(_T("")); if (pExDataRb == NULL) { acutPrintf(_T("\n 没有扩展数据")); } else { CTestCommands::printResbufChain(pExDataRb); } }
扩展字典
每个对象都可以有一个扩展字典,它包含一个任意的 McDbObject 对象序列。
对象打开后,当操作完成时,不在使用对象时,控件要求必须关闭对象,关闭对象调用 McDbObject::close() 函数,像这样调用: pObject->close();
因为有这样的要求,便常常在使用控件过程中,很容易忘记关闭对象,建议使用智能指针的方式打开对象,而对象的关闭会在智能指针释放的时候自动调用。
智能针指的使用例如:
打开一个实体:
McDbObjectPointer<McDbEntity> spEnt(id,McDb::kForRead); if(spEnt.openStatus() != Mcad::eOk) continue;
打开当前数据库中的模型空间:
McDbBlockTableRecordPointer spBlkTabRec(MCDB_MODEL_SPACE, McDbCurDwg(),McDb::kForRead); if(spBlkTabRec.openStatus() != Mcad::eOk) { return retId; }
实体简介
实体是具有 图形表示 的数据库对象,实体的例子有直线、圆、圆弧、文本、曲线和椭圆等。
实体组成了控件图形,用户在控件中的操作都是对实体进行的,可见实体具有非常重要的地位。在控件中绝大部分实体都是从 McDbEntity 中派生出来的,而McDbEntity是从 McDbObject 中派生出来的。
实体的共同属性
所有实体都有一些共同的属性,这些属性可以通过相同的成员函数来获得或修改,当然,这些属性也可以被用户命令修改。实体的共同属性如下:
颜色
线型
线型比例
可见性
层
线宽
当用户添加一个实体到块表记录中时,控件会自动将用户没有指定的实体属性设为缺省值。
颜色
实体的颜色可以通过0~256的数字值来指定和读取,也可以通过 McCmColor 类的实例来指定和读取,McCmColor类可以用来扩展颜色模型。McCmColor类可以用来表示真彩色中的任何一种色彩。
颜色值1~7代表的标准颜色如下:
颜色值 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
颜色 | 红 | 黄 | 绿 | 青 | 蓝 | 紫红 | 白或黑 |
颜色值7对应的颜色与控件背景颜色有关。如果背景是黑,则7对应的颜色是白,反之则对应的颜色是黑。
还有一些颜色值代表了一些特殊的含义:
0:指定实体的颜色为 BYBLOCK 。即实体继承当前块表记录中块参照的颜色值,如果实体直接处于模型空间或图纸空间块表记录中,则实体的颜色就是黑或白。
256:指定实体的颜色为 BYLAYER 。实体使用其所在层的颜色。
257:实体 无颜色 。这种情况仅在实体刚刚实例化,在被赋予0~256之间颜色值或被添加到数据库并使用数据库的当前颜色值之前才会出现。
可以使用下面的函数来设置或查询实体的颜色:
通过索引设置颜色:
Mcad::ErrorStatus McDbEntity::setColorIndex(Mdesk::Uint16 color);
通过索引读取颜色:
Mdesk::Uint16 McDbEntity::colorIndex() const;
通过McCmColor类设置颜色:
Mcad::ErrorStatus McDbEntity::setColor(const McCmColor& color, Mdesk::BooleandoSubents = true);
通过McCmColor类读取颜色:
McCmColor McDbEntity::color() const;
线型
当一个实体被创建时,它的线型被设置为 NULL 。当实体被添加到数据库后,如果没有这个实体指定的线型,则该实体的线型将被设置成数据库的当前线型值。这个缺省的线型值存放在CELTYPE系统变量中。线型可以通过名称字符串或在实体所在数据库的 McDbLineTypeTableRecord 的对象ID来指定。
可以使用下面的函数用实体名或对象ID来指定实体的线型:
使用函数用实体名来指定实体的线型:
Mcad::ErrorStatus McDbEntity::setLinetype(const char* newVal);
使用对象ID来指定实体的线型:
Mcad::ErrorStatus McDbEntity::setLinetype(McDbObjectId newVal);
下面的函数返回实体的线型名:
LPCTSTR McDbEntity::linetype() const;
下面的函数返回线型符号表记录的对象ID:
McDbObjectId McDbEntity::linetypeId() const;
线型比例
当一个实体被创建时,它的线型比例被设置成一个无效值。当对象被添加到数据库中后,如果没有为这个实体指定线型比例,则该实体的线型比例将被设置成数据库的当前线型比例值。这个缺省的线型比例值存放在 CELTSCALE 系统变量中。
可以使用下面的函数来设置或查询一个实体的线型比例值:
可以使用下面的函数来设置一个实体的线型比例值:
Mcad::ErrorStatus McDbEntity::setLinetypeScale(double newVal);
可以使用下面的函数来查询一个实体的线型比例值:
Double McDbEntity::linetypeScale() const;
当实体被重新生成后,它的有效线型比例是实体自身线型比例和全局数据库线型比例的乘积。对于非图纸空间的实体,它的线型比例可按如下方法计算:
effltscale = ent->linetypeScale() * ent->database()->ltscale();
可见性
如果指定一个实体不可见,则不管数据库中其他设置如何,该实体都将不可见。其他因素也可能导致实体不可见,例如:如果实体所在层被关闭或冻结,则该实体不可见。实体可见或不可见可以用一个变量 McDb::Visibility 来表示,它的值可以是 kInvisible 或 kVisible 。
可以用下面的函数来设置或查询一个实体的可见性:
可以用下面的函数来设置一个实体的可见性:
Mcad::ErrorStatus McDbEntity::setVisibility(McDb::Visibility newVal);
可以用下面的函数来查询一个实体的可见性:
McDb::Visibility McDbEntity::visibility() const;
层
所有实体都在某一个层上。在数据库中,最少包含一个层(初始情况下是0层)。和线型一样,用户可以为一个实体指定所在的层。如果用户不为实体指定层,则系统将会把这个实体添加到缺省层上。
每一个层有自己相关的属性,这此属性包括冻结/解冻、打开/关闭、锁定/解锁、颜色、线型和视口。当一个实体的颜色或线型是BYLAYER时,实体上的相关属性将会使用层的属性。
可以使用下面的函数来设置或查询一个实体所在的层:
可以使用下面的函数来设置一个实体所在的层:
Mcad::ErrorStatus McDbEntity::setLayer(const char* newVal);
可以使用下面的函数来查询一个实体所在的层:
Mcad::ErrorStatus McDbEntity::setLayer(McDbObjectId newVal);
下面的函数返回当前实体所在层的名称:
LPCTSTR McDbEntity::layer() const;
下面的函数返回实体所在层的对象ID:
McDbObjectId McDbEntity::layerId() const;
容器对象在图形文件初始化时,就已经存在了。容器对象包括符号表、字典、组和扩展记录。下面介绍如何向符号表、字典和组中添加实体,怎样使用遍历来查询容器的内容,以及怎样创建和使用自己的字典和扩展记录来管理应用程序数据和对象。
符号表
符号表具有这样的功能:它可以包含数据库对象,这些数据库对象能够通过一个字符串关键字来搜索。用户可以向这些容器中添加实体,也可以使用遍历来浏览容器以查找所需的内容。
符号表和字典的异同
符号表和字典在本质上有相同的功能。字典为用户提供了和符号表类似的机制来保存和恢复带有相关关键字的对象。当创建一个新的图形时,它就创建了一个命名对象字典,这个字典可以看作是图形中实体对象的容器列表。用户可以创建任意数量的对象并将它们添加到命名对象字典中。
符号表和字典的一个重要区别是符号表记录不能由ObjectARX应用程序直接删除,而一个字典所包含的对象则可以直接被删除。
符号表介绍
在符号表记录和字典中使用的名称必须遵循以下规则:
1. 名称可以有任意长度,但是在控件中用户输入的符号名不能超过255个字符。
2. 保留了使用名称中的大小写的权力,但是并没有在比较中区分大小写。
3. 除了逗号、单引号、分号、和等号之外,名称可以由任何Windows NT文件名中可以使用的字符组成。数据库中包含以下符号表:
类型 | 类名 |
---|---|
块表 | McDbBlockTable; BLOCK |
层表 | McDbLayerTable: LAYER |
文本样式表 | McDbTextStyleTable; STYLE |
线型表 | McDbLinetypeTable: LTYPE |
每一个表都包含相应的 McDbSymbolTableRecord 类的子类。
每一个符号表都提供了一个getAt()函数来查找指定名称的记录。另外还有 has() 和 add() 函数,前者可以用来判断一个记录名是否已经包含在符号表中,后者用来向符号表中添加一个新记录。
块表
在数据库中的实体通常属于一个块表记录。缺省情况下,块表包含1个记录: *MODEL_SPACE 。
层表
在缺省情况下,层表中包含0层一个层。下面是一些常用的设置和查询层特性信息的函数:
冻结和解冻:当一个层被冻结时,该层的图形将不能重新生成。
void McDbLayerTableRecord::setIsFrozen(Mdesk::Boolean); Mdesk::Boolean McDbLayerTableRecord::isFrozen() const;
打开和关闭:当一个图层被关闭时,该层的图形将不再显示。
void McDbLayerTableRecord::setIsOff(Mdesk::Boolean); Mdesk::Boolean McDbLayerTableRecord::isOff() const;
锁定和解锁:在控件中,用户不能修改在一个锁定层上的实体,也不能在应用程序中以write()函数打开实体。
void McDbLayerTableRecord::setIsLocked(Mdesk::Boolean); Mdesk::Boolean McDbLayerTableRecord::isLocked() const;
颜色:当一个实体的颜色被设置成BYLAYER时,可以通过setColor()函数来设置实体的颜色。
void McDbLayerTableRecord::setColor(const AcCmColor &color); AcCmColor McDbLayerTableRecord::color() const;
线型:当一个实体的线型是BYLAYER时,可以通过setLinetypeObjedtId()函数来设置实体的线型。
void McDbLayerTableRecord::setLinetypeObjectId(McDbObjectId); McDbObjectId McDbLayerTableRecord::linetypeObjectId() const;
遍历器
每一个符号表都有一个相应的遍历器,用户可以使用 newIterator() 函数创建新的遍历器对象,用来浏览整个表内的所有对象。在使用完这个遍历器之后, 一定要删除它 。另外,块表中还有一个可以用来操作其实体的遍历器。
字典
要创建一个新的字典,用户需要创建一个 McDbDictionary 的实体,将这个实例添加到数据库中并在它的主对象中注册。可以使用McDbDictionary类的 setAt() 函数来将对象添加到字典和数据库中。
扩展记录允许用户添加应用程序指定的辅助数据。因为在定义用户自己的类时可以选择扩展数据。一个扩展记录是一个 McDbxrecord 类的实例,而McDbxrecord类是从 McDbObject 类派生的。扩展数据的声明是由一个结果缓冲区的形式定义的,它是一个数据列表,其中每一项包含了一个 DXF 组码和相应的数据。下面将会介绍DXF组码的含义。
对于用户保存在一个扩展记录中的数据的量原则上是没有限制的,扩展记录可以从属于任何其他对象,包括扩展字典的任何对象、命名对象字典、其他字典或其他扩展记录。
McDbxrecord类提供了两个函数用来设定和获取扩展记录:
设定扩展记录:
Mcad::ErrorStatus McDbXrecord::setFromRbChain(resbuf& pRb, McDbDatabase* auxDb = NULL);
获取扩展记录:
Mcad::ErrorStatus McDbXrecord::rbChain(resbuf** ppRb, McDbDatabase* auxDb = NULL) const;
所有对象都一个唯一的标识id和句柄,都是用来标识对象,知道对象的Id或句柄,就能找到对象并修改属性。id是只在当前内存中唯一,下次再打开id就会发生变化,句柄会随图纸保存,并会一直不变。
对象Id,指针,句柄三者之前的转换关系:
从 ID 到对象指针: 通过Mx::mcdbOpenObject 打开对象,或使用智能指针打开, McDbObjectPointer。
从对象指针到 ID: 所有的数据库对象都继承自McDbObject,调用McDbObject::objectId()返回对象的ID。
从句柄到 ID:使用McDbDatabase::getAcDbObjectId 函数。
从 ID 到句柄:使用McDbObjectId::handle 函数。
从指针到句柄:使用 McDbObject::getAcDbHandle 函数。
修改对象颜色
上一节中:函数McDbObjectId CreateLine1(McGePoint3d pt1,McGePoint3d pt2)会返回新绘制的对象id。
// ------------------------------------------------------------------------- // Summary: // 改变实体颜色 // Parameters: // id - 实体的id // color - 实体的新颜色 // Returns: // 成功返回true // ------------------------------------------------------------------------- bool ChangeColor(McDbObjectId id,const McCmColor& color) { // 用智能指针打开对象,写方式打开。智能指针会自动关闭对象. McDbObjectPointer spEnt(id,McDb::kForWrite); if(spEnt.openStatus() != Mcad::eOk) { // 如果对象,在其它地方打开,就会打开的失败. return false; } // 设置对象颜色 spEnt->setColor(color); return true; }
COM接口调用方式,如C#代码:
// ------------------------------------------------------------------------- // Summary: // 改变实体颜色 // Parameters: // id - 实体的id. // iR, iG,iB - 实体的颜色 // Returns: // 成功返回true // ------------------------------------------------------------------------- bool ChangeColor(Int64 id,int iR,int iG,int iB) { // 由id得到实体对象. MxDrawEntity ent = (MxDrawEntity)axMxDrawX1.ObjectIdToObject(id); if (ent == null) return false; MxDrawMcCmColor color = new MxDrawMcCmColor(); color.SetRGB(iR, iG, iB); // 设置实体颜色。 ent.TrueColor = color; return true; }
修改实体的其他特性
下面实现修改其它属性的函数,比如:
修改图层属性:
// ------------------------------------------------------------------------- // Summary: // 修改对象图层. // Parameters: // id - 实体的id. // pszLayerName - 层名,如果数据库,没有该层名,返回失败。 // Returns: // 成功返回true // ------------------------------------------------------------------------- bool ChangeLayer(McDbObjectId id,LPCTSTR pszLayerName) { // 用智能指针打开对象,写方式打开。智能指针会自动关闭对象. McDbObjectPointer spEnt(id,McDb::kForWrite); if(spEnt.openStatus() != Mcad::eOk) { // 如果对象,在其它地方打开,就会打开的失败. return false; } // 设置对象颜色 if(spEnt->setLayer(pszLayerName) != Mcad::eOk) return false; return true; }
比如修改线型属性:
// ------------------------------------------------------------------------- // Summary: // 修改对象线型. // Parameters: // id - 实体的id. // pszLinetypeName - 线型名,如果数据库,没有线型名,返回失败。 // Returns: // 成功返回true // ------------------------------------------------------------------------- bool ChangeLinetype(McDbObjectId id,LPCTSTR pszLinetypeName) { // 用智能指针打开对象,写方式打开。智能指针会自动关闭对象. McDbObjectPointer spEnt(id,McDb::kForWrite); if(spEnt.openStatus() != Mcad::eOk) { // 如果对象,在其它地方打开,就会打开的失败. return false; } // 设置对象颜色 if(spEnt->setLinetype(pszLinetypeName) != Mcad::eOk) return false; return true; }
说明
CAD控件提供的接口,可以把dwg文件转换成Bmp,Jpg文件,也可以把DWG文件中某个区域的图形绘制到CDC上或保存为Bmp文件。这些接口即能在VC中使用,也能在VB,C#,Delphi,网页中调用。
DwgToJpg
不需要使用CAD控件打开dwg文件,直接把dwg文件转成jpg文件。
VC接口:
BOOL MxDraw::DwgToJpg(IN LPCTSTR pszDwgFilePath,
OUT LPCTSTR pszJpgFilePath,
int iWidth = -1,
int iHeight = -1);
COM接口:
bool DwgToJpg(string pszDwgFileName, string pszJpgFileName, int lWidth, int lHeight)
MxDrawXLib.IMxDrawApplication 的成员
参数 | 说明 |
---|---|
pszDwgFilePath | 转入的DWG文件路径 |
pszJpgFilePath | 另存为的JPG文件路径 |
iWidth | 保存后的JPG文件的像素宽度 |
iHeight | 保存后的JPG文件的像素高度 |
VC调用参考例程:
void CTestDlg::OnBnClickedDwgtojpgButton() { // TODO: CPreviewFileDialog openDlg(TRUE,_T("dwg"),NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, //_T("dwg(*.dwg) | *.dwg||"), _T("DWG files (*.dwg)|*.dwg|DXF files (*.dxf)|*.dxf|Jpg files (*.jpg)|*.jpg|BMP files (*.bmp)|*.bmp||"), this); CString sDwgFileName; if(openDlg.DoModal() == IDOK) { sDwgFileName = openDlg.GetPathName(); } else { return; } // CString sJpgFilePath; CFileDialog openJpgDlg(FALSE,_T("jpg"),NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("jpg(*.jpg) | *.jpg||"), this); if(openJpgDlg.DoModal() == IDOK) { sJpgFilePath = openJpgDlg.GetPathName(); } else { return; } // 1000,1000是转成jpg的像素宽度和高度。 if(MxDraw::DwgToJpg(sDwgFileName,sJpgFilePath,1000,1000) ) { AfxMessageBox(_T("转换成功")); } else { AfxMessageBox(_T("转换失败")); } }
C#调用参考例程:
private void DwgToJpg_Click(object sender, EventArgs e) { // 创建一个应用对象 MxDrawApplication app = new MxDrawApplication(); OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "Dwg 文件(*.Dwg)|*.Dwg|Dxf files (*.Dxf)|*.dxf"; if (ofd.ShowDialog() != DialogResult.OK) { return; } SaveFileDialog sfd = new SaveFileDialog(); sfd.Filter = "jpg 文件(*.jpg)|*.jpg"; if (sfd.ShowDialog() != DialogResult.OK) { return; } // 1000,1000是转成jpg的像素宽度和高度。 if(app.DwgToJpg(ofd.FileName, sfd.FileName, 1000, 1000) ) { MessageBox.Show("转换成功"); } else { MessageBox.Show("转换失败"); } } }
WriteJpg
使用CAD控件打开dwg文件或经过了编辑后,调用该函数把它另存为Jpg文件。
VC接口:
BOOL MxDraw::WriteJpg(MXDRAWOCXHANDLE hOcx,LPCTSTR pszJpgFilePath,
int iWidth = -1,int iHeight = -1);
COM接口:
public virtual bool SaveJpgFile(string pszJpgFilePath, int lWidth, int lHeight)
AxMxDrawXLib.AxMxDrawX 的成员
参数 | 说明 |
---|---|
hOcx | 控件的标识句柄 |
pszJpgFilePath | 保存的Jpg文件路径 |
lWidth | 保存后的Jpg文件像素宽度,取默认值-1,程序就自动取4000 |
lHeight | 保存后的Jpg文件像素高度,取默认值-1,程序就自动取4000 |
WriteBmp
使用CAD控件打开dwg文件或经过了编辑后,调用该函数把它另存为Bmp文件。
VC接口:
BOOL MxDraw::WriteBmp(MXDRAWOCXHANDLE hOcx,LPCTSTR pszBmpFilePath,
int iWidth = -1,int iHeight = -1);
COM接口:
public virtual bool SaveBmpFile(string pszBmpFilePath, int lWidth, int lHeight)
AxMxDrawXLib.AxMxDrawX 的成员
参数 | 说明 |
---|---|
hOcx | 控件的标识句柄 |
pszJpgFilePath | 保存的Jpg文件路径 |
lWidth | 保存后的Jpg文件像素宽度,取默认值-1,程序就自动取4000 |
lHeight | 保存后的Jpg文件像素高度,取默认值-1,程序就自动取4000 |
VC调用参考例程:
void CTestDlg::OnBnClickedSavebmpButton() { // TODO: 在此添加控件通知处理程序代码 CFileDialog openDlg(FALSE,_T("bmp"),NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("bmp(*.bmp) | *.bmp||"),this); CString sFileName; if(openDlg.DoModal() == IDOK) { sFileName = openDlg.GetPathName(); } else { return; } if(!MxDraw::WriteBmp(m_hDrawOcx,sFileName) ) { CString sError; if(MxDraw::GetLastError().IsEmpty() ) sError = _T("保存位图文件失败!"); else sError.Format(_T("保存位图文件失败!原因为:%s"),MxDraw::GetLastError()); AfxMessageBox(sError); } else { AfxMessageBox(_T("保存成功")); } }
DrawToDc
绘制CAD控件当前图形中指定区域到CDC对象中。
VC接口:
BOOL MxDraw::DrawToDc(MXDRAWOCXHANDLE hOcx,
CDC* pDC,
int iDCx,int iDCy,int iDCWidth,int iDCHeight,
double dLbx,double dLby,double dRtx,double dRty );
AxMxDrawXLib.AxMxDrawX 的成员
参数 | 说明 |
---|---|
hOcx | 标识控件的句柄 |
pDC | 把指定区域的图形中的内容绘制到pDC上 |
iDCx, iDCy | 绘制pDC的左上角位置 |
iDCWidth,iDCHeight | 绘制到pDC上的宽度和高度 |
dLbx, dLby | 指定图形区域的左下角坐标 |
dRtx, dRty | 指定图形区域的右下角坐标 |
VC调用参考例程:
void CTestCommands::DrawToBmp() { // 选择让用从图上选择个存位图的区域。 acutPrintf(_T("\n 请点取存位图的区域:")); // 动态拖放输入,让用户确定要保存的区域 CRectSelJig getRect; // pt1,pt2是矩形框的两点 AcGePoint3d pt1,pt2; if(!getRect.DoIt(pt1,pt2) ) return; // 让用户选择保存的位图文件. CTestDlg* pDlg = (CTestDlg*)AfxGetApp()->GetMainWnd(); CFileDialog openDlg(FALSE,_T("bmp"),NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("bmp(*.bmp) | *.bmp||"), pDlg); CString sFileName; if(openDlg.DoModal() == IDOK) { sFileName = openDlg.GetPathName(); } else { return; } int iBmpWidth = 1000; int iBmpHeight = 500; // 开始保存文件. CDC dc; dc.Attach(::GetDC(NULL)); CBitmap bm; bm.CreateCompatibleBitmap(&dc,iBmpWidth,iBmpHeight); CDC tmpDc; tmpDc.CreateCompatibleDC(&dc); CBitmap*pOld = tmpDc.SelectObject(&bm); if(MxDraw::DrawToDc(MxDraw::GetCurOcxHandle(), &tmpDc,0,0,iBmpWidth,iBmpHeight, pt1.x,pt1.y,pt2.x,pt2.y ) ) { tmpDc.SelectObject(pOld); if(SaveBmp(&bm,&dc,sFileName) ) { AfxMessageBox(_T("保存成功")); } else { AfxMessageBox(_T("保存失败")); } } else { AfxMessageBox(_T("未知原因,保存失败")); tmpDc.SelectObject(pOld); } }
bool CTestCommands::SaveBmp(CBitmap* pBmp,CDC* pDc,const CString& sBmpFilePath) { if(sBmpFilePath.IsEmpty() ) { AfxMessageBox(_T("文件路径为空")); return false; } BITMAP btm; pBmp->GetBitmap(&btm); DWORD size = btm.bmWidthBytes * btm.bmHeight; LPSTR lpData = (LPSTR)GlobalAlloc(GPTR,size); ///////////////////////////////////////////// BITMAPINFOHEADER bih; bih.biBitCount=btm.bmBitsPixel; bih.biClrImportant=0; bih.biClrUsed=0; bih.biCompression=0; bih.biHeight=btm.bmHeight; bih.biPlanes=1; bih.biSize=sizeof(BITMAPINFOHEADER); bih.biSizeImage=size; bih.biWidth=btm.bmWidth; bih.biXPelsPerMeter=0; bih.biYPelsPerMeter=0; /////////////////////////////////// GetDIBits(pDc->GetSafeHdc(),*pBmp,0,bih.biHeight,lpData,(BITMAPINFO*)&bih,DIB_RGB_COLORS); BITMAPFILEHEADER bfh; bfh.bfReserved1=bfh.bfReserved2=0; bfh.bfType=((WORD)('M'<< 8)|'B'); bfh.bfSize=54+size; bfh.bfOffBits=54; bool isSuc = false; CFile bf; if(bf.Open(sBmpFilePath,CFile::modeCreate|CFile::modeWrite)) { bf.Write(&bfh,sizeof(BITMAPFILEHEADER)); bf.Write(&bih,sizeof(BITMAPINFOHEADER)); bf.Write(lpData,size); bf.Close(); isSuc = true; } else { AfxMessageBox(_T("创建文件失败")); } GlobalFree(lpData); return isSuc; }