gdc666 发表于 2003-4-22 12:19:00

请教一个object arx的例子

我是初学者,对objectarx的运行机理不是很清楚,当我在学习下面这个例子时出现了一些不理解的地方,提出来希望各位老师帮帮我。下面的setlayer函数的目的是搜索是否有名叫gdc的block,如果有,就把这个block的layer设置为zxl层(zxl是一个已经存在的layer)
void setInsertLayer()
{
Acad::ErrorStatus es;
AcDbBlockTable* pBlockTbl;
AcDbBlockTableRecord* pMS;

if ((es = acdbCurDwg()->getBlockTable(pBlockTbl, AcDb::kForRead)) == Acad::eOk)
{
{if ((es = pBlockTbl->getAt(ACDB_MODEL_SPACE, pMS, AcDb::kForWrite))! =Acad::eOk) //    (一)
acrx_abort("\nCouldn't get Model Space! Drawing corrupt.\n");
}
   pBlockTbl->close();
}
AcDbBlockTableRecordIterator* pBtrIter; //(二)
if ((es = pMS->newIterator(pBtrIter)) != Acad::eOk)//(三)
{
acutPrintf("\nCouldn't create Model Space iterator: %s", acadErrorStatusText(es));
return;
}
char* blockName;
AcDbEntity* pEnt;
AcDbBlockTableRecord* pCurEntBlock;
AcDbObjectId blockId;
for (pBtrIter->start(); !pBtrIter->done(); pBtrIter->step())//(四)
{
if ((es = pBtrIter->getEntity(pEnt, AcDb::kForRead)) != Acad::eOk)
{
        acutPrintf("\nCouldn't open entity:%s", acadErrorStatusText(es));
        continue;
}
if (pEnt->isA() != AcDbBlockReference::desc())//(五)
{
        pEnt->close();
        continue;
}
blockId = (AcDbBlockReference::cast(pEnt))->blockTableRecord();//(六)
if (acdbOpenObject((AcDbObject*&)pCurEntBlock, blockId, AcDb::kForRead) == Acad::eOk)                                                   //(七)
{
pCurEntBlock->getName(blockName);
if (strcmp(blockName, "gdc") == 0)
{
        if (pEnt->upgradeOpen() == Acad::eOk)
                pEnt->setLayer("zxl");
}
pCurEntBlock->close();
}
delete pBtrIter;
pMS->close();
return;

}
/////////////////////////////////////
我不是很清楚的地方(一下标题对应代码中的标记)
(一)句是将ACDB_MODEL_SPACE模型空间的块表记录传递给块表指针pMS吧
(二)句对于AcDbBlockTableRecordIterator*指针我不理解它的作用
(三)句newIterator函数的作用不清楚
(四)句for (pBtrIter->start(); !pBtrIter->done(); pBtrIter->step())
   是在一个什么里面不断的找下一个记录??
(五)句pEnt->isA() 的作用是判断pEnt是否是一个实体?
      AcDbBlockReference::desc())是什么意思呢?
(六)句我非常不明白AcDbBlockReference::cast(pEnt)是什么意思
            blockTableRecord()函数又是什么作用?
      通过实体得到id?
(七)句AcDbObject*& ——*&好玄妙--就是不懂
      通过id得到块表记录pCurEntBlock?
   总之我对这断代码总体上把握不了,望斑竹和各位老师帮助啊!
   祝objectarx版越办越好!

gdc666 发表于 2003-4-22 14:21:00

差点忘了,还有一点

if ((es = acdbCurDwg()->getBlockTable(pBlockTbl, AcDb::kForRead)) == Acad::eOk) 这句意义何在,

goldenshin 发表于 2003-4-22 15:01:00

->

if ((es = pBlockTbl->getAt(ACDB_MODEL_SPACE, pMS, AcDb::kForWrite))! =Acad::eOk) //    (一)
AcDbBlockTableRecordIterator* pBtrIter; //(二)
if ((es = pMS->newIterator(pBtrIter)) != Acad::eOk)//(三)
for (pBtrIter->start(); !pBtrIter->done(); pBtrIter->step())//(四)
if (pEnt->isA() != AcDbBlockReference::desc())//(五)
blockId = (AcDbBlockReference::cast(pEnt))->blockTableRecord();//(六)
if (acdbOpenObject((AcDbObject*&)pCurEntBlock, blockId, AcDb::kForRead) == Acad::eOk)                                                   //(七)


/////////////////////////////////////
我不是很清楚的地方(一下标题对应代码中的标记)
(一)句是将ACDB_MODEL_SPACE模型空间的块表记录传递给块表指针pMS吧
    (-> YES)

(二)句对于AcDbBlockTableRecordIterator*指针我不理解它的作用
    (-> 遍历指针,在本例中,指向PMs的所有的记录)

(三)句newIterator函数的作用不清楚
    (-> 创建遍历器指针)

(四)句for (pBtrIter->start(); !pBtrIter->done(); pBtrIter->step())
         是在一个什么里面不断的找下一个记录??
    (-> 在遍历指针里一个一个的指向具体记录)

(五)句pEnt->isA() 的作用是判断pEnt是否是一个实体?
      AcDbBlockReference::desc())是什么意思呢?
    (->isA()返回类标识,AcDbBlockReference::desc()返回 AcDbBlockReference 这个类的类标识)

(六)句我非常不明白AcDbBlockReference::cast(pEnt)是什么意思
    (强制类型转换)
      blockTableRecord()函数又是什么作用?
      通过实体得到id? (yes)
(七)句AcDbObject*& ——*&好玄妙--就是不懂
      通过id得到块表记录pCurEntBlock?(yes)
      (AcDbObject*表示将要打开的实体的类别,&是告诉你这个函数会给你分配内存,用完后要尽早close掉,)
============================================
===========================================
建议:(1)你对于C或C++还有些陌生,有空的时候(比如坐车时或睡觉前)多看一俩本C\C++的书
(2)Arx的东西在其在线帮助中都有说明,自己去看

leeyeafu 发表于 2003-4-22 15:54:00

好家伙,一下子七个问题

本帖最后由 leeyeafu 于 2003-4-22 15:54:06 编辑

在正式回答你的七个问题之前,先说一说另外两个问题,在这两个问题上,你还有些模糊。
一、C++函数调用机制,尤其是用指针和地址引用作函数的参数传递机制时,你的理解可能不太准确。我们知道,C++函数调用的返回只能是一个精确的数据类型,仅仅通过返回机制是不可能在一个函数中修改或设置两个以上的数据。这个问题的解决方案就是使用C++指针(即*运算符)或地址引用(即&运算符)实现对函数输入参数的修改或设置。在ARX中,许多函数都只是返回一个错误号,用来表示函数执行过程是否有错误,而函数的真正功能是通过指针或引用来返回。
二、ACAD及ARX图形数据库结构。我不知道你是否熟悉普通关系型数据库的结构,在这我要重点说明的是:ARX图形数据库的结构与普通的关系型数据库的结构有很大的不同,这一点经常造成初学者对ARX图形数据库结构的理解出现偏差。ARX数据库是一种完全面向对象的数据库结构,也就是说,它的各条记录的各个字段值不仅可以是各种类型的数据,也可以是指针或地址引用,甚至还可以是一个对象,比如说是另外一条记录或另外一张表。当然,也可使用指针(或引用)来指向(或引用)另外的记录或表。例如,ACDB块表记录的某个字段值就可能指向另一个表记录。在ACAD中,一个有实际意义的ACDB图形数据库的块表中必须包括至少一条表示模型空间(ACAD R14以上版本还要有表示图纸空间)的块表记录。换句话说,也就任何有实际意义的ACAD图形至少应包括一个名为模型空间的图块。(这个说法对于ACAD的操作员来说好象有点不可置信,但这对于ACDB数据库结构的理解是有帮助的。)在ACDB数据库的块表中中,名为模型空间的那条记录有一个字段值为一个类似列表的数据类型的对象,该对象包括一系列指针,分别指向图形中所有的ACDB实体。当ACAD图形的模型空间中包含有ACDB图块(或向图形中添加ACDB图块)实体时,不仅ACDB数据库的块表中要有(或添加)这些(或个)块的记录内容,名为模型空间的那条块表记录的某个字段值中也应有(或添加)块的记录。说起来象是绕口令一样,但这些确实是ARX图形数据库编程的基础,我不知道是否说清楚了,若有不明白,欢迎继续提问。
以下回答你的七个问题:
第一个问题:你的理解基本是正确的,仅仅是有点不准确。getAt()函数的作用是使pMS指针指向当前图形的模型空间的块表记录。
第二、三、四个问题:我们已经知道,图形中的ACDB实体只是模型空间块表记录中某个字段的内容,由于该字段值是一个对象无法直接得到这些实体的记录,要通过一个叫块表记录浏览器的类来查询(或者说遍历)模型空间的块表记录。AcDbBlockTableRecordIterator*就是指向这样一个块表记录浏览器的指针。同时可通过该浏览器类的成员函数(如start()函数)实现浏览功能。第四个问题中的那个for循环就是在模型空间的块表记录的那一个字段值(注意:它是一个对象)中循环。
第五个问题:pEnt对象是AcDbEntity实体类型(注意:ACDB模型空间的块表记录中可能有各种各样类型的实体,它们都派生自AcDbEntity类),AcDbEntity类的成员函数isA()返回实体的具体类型,各派生类的desc()成员函数返回本身的ACDB子类名。如此,这句的意思就是判断pEnt指向的实体对象是否为图块参考类型。
第六个问题:正如上个问题,pEnt为AcDbEntity类型,它无法使用其派生类AcDbBlockReference的成员函数和成员对象,AcDbObject类(它是AcDbEntity类的基类)的cast()函数返回一个类对象,AcDbBlockReference::cast(pEnt)返回一个表示pEnt指向的实体的AcDbBlockReference类指针(注意:AcDbBlockReference同样是AcDbObject类的派生类。)这样就可以使用AcDbBlockReference类的成员函数和成员对象了。
第七个问题的回答涉及acdbOpenObject()函数的具体应用,*&表示一个指向地址引用的指针。其余的你自己先理解一下试试。

gdc666 发表于 2003-4-22 17:40:00

感谢两位版主的解答

我认真看了五遍,感觉很有收获,还有一些疑惑如下:
(1)模型空间就是一个block,它的记录存放在ACDB数据库的块表中,模型空间这个block的记录本身有很多项,其中有一项(以下简称A)是专用来存放所有模型空间中实体记录的;其他项用于存放模型空间中其他的block(这样理解对吗?)
(2)“当ACAD图形的模型空间中包含有ACDB图块(或向图形中添加ACDB图块)实体时名为模型空间的那条块表记录的某个字段值中也应有(或添加)块的记录。”---是否可以这样理解:A中既有block的记录又有单个单个实体的记录,而每个block中又有单个单个实体的记录?因此在那个for循环中,既要遍历每个block中的实体,还要遍历A中每个单个的实体
(3)if ((es = pBtrIter->getEntity(pEnt, AcDb::kForRead)) != Acad::eOk) …..中的返回值pEnt,是一个AcDbEntity*类型,在if (pEnt->isA() != AcDbBlockReference::desc())判断它所指向的具体实体是否是AcDbBlockReference类型。这句也就是说,对于A中单个单个的实体就不再进行操作吧?
(4)blockId = (AcDbBlockReference::cast(pEnt))->blockTableRecord();的作用就是通过cast()把pEnt强制转换为AcDbBlockReference类的指针,然后通过该指针调用blockTableRecord()得到pEnt的id――送给blockId;然后通过blockId调用acdbOpenObject()函数,打开对象?把blockId对应的pCurEntBlock找到?
然后通过pCurEntBlock用getname()来得到遍历block的名字?(好复杂,id是什么?为什么一定要通过pCurEntBlock来得到name of the block);
(5)最后一点,acdbCurDwg()->getBlockTable(pBlockTbl, AcDb::kForRead))是从ACDB数据库的块表中得到当前图形中所对应的块表记录吧?

leeyeafu 发表于 2003-4-24 09:58:00

看来我确实没能说清楚

昨天没时间回贴,SRY。
(1)“A”用于存放所有模型空间中实体记录,没错。但其他项用于存放模型空间的其他信息。模型空间内的其他图块内容是另外的块表记录。下表是一个可能的DWG图形数据库的块表结构:
块表记录                   字段(或项目)“A”
模型空间         {直线1,图块1,圆1,直线2,弧1,图块2......}
   图块1            {多段线1-1,弧1-1,直线1-1......}
   图块2               {直线2-1,圆2-1......}
(2)你给出的源程序仅仅遍历了模型空间的“A”字段,从中找到图块1和图块2,没有对图块内部进行遍历操作。
(3)理解正确。
(4)cast()函数的实现与C++的强制类型转换有很大的不同,但他们的作用有些相似。通过遍历操作我们得到指向图块的AcDbEntiy类型的指针,它仅仅只是指示图块实体数据在内存中的位置,要进一步访问该图块实体,可以通过cast()函数进行“类型转换”。首先,->blockTableRecord()得到图块的块表记录ID。ID直译的意思是“身份标志号码”,对于每一个ACAD对象,都有一个ID号进行唯一标志。得到ID号后,我们才可能访问图块内部的数据,例如图块名称。方法是acdbOpenObject()。只有这样,pCurEntBlock指针才是指向图块本身的。
(5)类似问题(一)。

gdc666 发表于 2003-4-24 10:28:00

感谢leeyeafu

我每天都来这里,不过,你好像不常来啊,能不能留个e_mail给我啊?
   我作毕业设计,要用objectarx,自己现学,老师又不管,对于vc_mfc 到是了解一些,但还远远不够啊

wangdaobin 发表于 2014-6-1 19:47:31

非常好!!!!!!!!!!!
页: [1]
查看完整版本: 请教一个object arx的例子