找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 761|回复: 9

[求助] saveAs()保存问题【已解决】

[复制链接]

已领礼包: 4个

财富等级: 恭喜发财

发表于 2020-7-30 15:36:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 rwss009 于 2020-8-28 11:25 编辑

我的程序流程是这样的:
1.创建自定义实体(就是一个多段线)
2.将该实体保存到另一个文件中(已将当前文档锁定)
2.1 新建数据库,使用readDwgFile函数获取其他文件的数据库
2.2 获取块表,块表记录,将实体加到块表记录上
2.3 关闭各内容后,使用saveAs()保存,参数就是该文件路径

之前绘制自定义实体不太多的时候是没有问题的,但现在在绘制一个自定义实体较多的图案时,看运行时文件的大小,是先增长然后突然变小,再增长,再变小没有规律(例如20k到35k然后变成16k,)。调试时发现文件变小是在执行saveAs()之后发生的。打开绘制的dwg果然只绘制了一点点内容,最诡异的是调试时使用ErrorStatus观察每一步的返回值都是eOk,请问这是怎么回事,有人遇到过吗?
//时隔一个月解决,不是保存的问题,终究还是自己写的自定义实体的函数有问题。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 145个

财富等级: 日进斗金

发表于 2020-7-31 09:43:03 | 显示全部楼层
有代码才好分析
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 4个

财富等级: 恭喜发财

 楼主| 发表于 2020-7-31 11:14:16 | 显示全部楼层
本帖最后由 rwss009 于 2020-8-4 14:40 编辑
XDSoft 发表于 2020-7-31 09:43
有代码才好分析

其实真的代码意义不大。。因为就是正常的操作,es调试也都是eOK,只是到了saveAs那里,该绘制的实体没绘制,反而把之前绘制的全部清空了。。我贴一下代码
[C++] 纯文本查看 复制代码
AcDbObjectId PostToModelSpace( AcDbEntity *pEnt, CString cstr)
{
        assert(pEnt);

        AcDbDatabase *pDb = new AcDbDatabase(false,true);
        // cstr为文件路径
        Acad::ErrorStatus es = pDb->readDwgFile(cstr, _SH_DENYRW);
                
        // 获得块表
        AcDbBlockTable *pBlkTbl = NULL;
        es = pDb->getSymbolTable(pBlkTbl,AcDb::kForRead);
                
        // 获得模型空间对应的块表记录
        AcDbBlockTableRecord *pBlkTblRcd = NULL;
        es = pBlkTbl->getAt(ACDB_MODEL_SPACE, pBlkTblRcd,AcDb::kForWrite);
        if(es != Acad::eOk)
        {
                pBlkTbl->close();
                delete pEnt;
                pEnt = NULL;
                return AcDbObjectId::kNull;
        }

        // 将实体添加到模型空间的块表记录
        AcDbObjectId entId = NULL;
        es = pBlkTblRcd->appendAcDbEntity(entId, pEnt);
        if (es != Acad::eOk)
        {
                pBlkTblRcd->close();
                delete pEnt;        // 添加失败时,要delete
                pEnt = NULL;
                return AcDbObjectId::kNull;
        }

        // 关闭模型空间块表记录和实体
        pBlkTbl->close();
        pBlkTblRcd->close();
        pEnt->close();

        // 关闭后才可保存
        es = pDb->saveAs(cstr); // 这里有时执行完文件变小

        delete pDb;
        return entId;
}


调用该函数时的操作
[C++] 纯文本查看 复制代码
custEnt *pCustEnt = new custEnt(); //此处新建了一个自定义实体
// 锁定文档acDocManager->lockDocument(acDocManager->curDocument());

PostToModelSpace(pCustEnt ,cstr_file); //传入该实体和路径

// 解锁文档
acDocManager->unlockDocument(acDocManager->curDocument());



如图所示,现在发现绘制前12个自定义实体是没有出错了,等到绘制第13个的时候,本该在图1的基础上再绘制图2所示内容(就那个“电”字左上方的方块),但实际没有绘制反而把图1绘制的东西全清除掉了。
通过调试,准备绘制第13个实体时,我遍历了readDwgFile获取到的cad数据库,里面存在的实体数量是正确的。一直在saveAs()前,es都是eOk,甚至saveAs()也是返回eOk的。。这里到底是因为什么导致了之前绘制的都被清除掉了。







图1

图1

图2

图2
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 145个

财富等级: 日进斗金

发表于 2020-7-31 15:56:58 | 显示全部楼层
没弹出报错窗口什么的吗?


AcDbDatabase *pDb = new AcDbDatabase(false,true);

把上面的改

AcDbDatabase *pDb = new AcDbDatabase(true);

试试
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 4个

财富等级: 恭喜发财

 楼主| 发表于 2020-8-3 10:47:43 | 显示全部楼层
XDSoft 发表于 2020-7-31 15:56
没弹出报错窗口什么的吗?

一直没弹出任何报错窗口。。
按照你的办法,改了之后出现下面的情况:
运行时自动打开的那个cad那里,一拖动界面那个坐标轴会一直重复出现,拖的多了,就在saveAs的定义那里出现了异常。
14t.png
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 4个

财富等级: 恭喜发财

 楼主| 发表于 2020-8-3 10:53:22 | 显示全部楼层
XDSoft 发表于 2020-7-31 15:56
没弹出报错窗口什么的吗?

如果不乱动那个界面的话,是不会报异常的,但最终绘制完后,打开那个文件里面也还是不完整的。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 4个

财富等级: 恭喜发财

 楼主| 发表于 2020-8-3 15:35:08 | 显示全部楼层
XDSoft 发表于 2020-7-31 15:56
没弹出报错窗口什么的吗?

大佬有个发现,就是如果我不新建数据库然后readDwgFile的话,是可以完全绘制在当前数据库中的。但读取文件后绘制再保存就不行了。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 112个

财富等级: 日进斗金

发表于 2020-8-23 19:09:22 | 显示全部楼层
上传完整的demo可让高手共同诊断下
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 4个

财富等级: 恭喜发财

 楼主| 发表于 2020-8-28 11:22:01 | 显示全部楼层
时隔一个月终于破案了,因为我学会了如何使用附加到进程去调试,最终发现还是自定义实体的dwgOutFields和dwgOutFields这两函数出现了错误,我的自定义实体,是一个传入AcGePoint3dArray类型参数,根据这些点绘制一个闭合的多段线,但我完全按照张帆书上的三角形自定义实体写的这两函数,导致存文件还暂时没事,但读文件时无法获取到点集合的长度,上代码说明:
  1. Acad::ErrorStatus nmdsNameLine::dwgOutFields (AcDbDwgFiler *pFiler) const {
  2.         assertReadEnabled () ;
  3.         //----- Save parent class information first.
  4.         Acad::ErrorStatus es =AcDbEntity::dwgOutFields (pFiler) ;
  5.         if ( es != Acad::eOk )
  6.                 return (es) ;
  7.         //----- Object version number needs to be saved first
  8.         if ( (es =pFiler->writeUInt32 (nmdsNameLine::kCurrentVersionNumber)) != Acad::eOk )
  9.                 return (es) ;
  10.         //----- Output params
  11.        
  12.         for (int i = 0; i < name_points.length(); i++)
  13.         {
  14.                 pFiler->writeItem(name_points[i]);//该函数在保存时执行,此处只写入了点坐标
  15.         }

  16.         return (pFiler->filerStatus ()) ;
  17. }
复制代码
  1. Acad::ErrorStatus nmdsNameLine::dwgInFields (AcDbDwgFiler *pFiler) {
  2.         assertWriteEnabled () ;
  3.         //----- Read parent class information first.
  4.         Acad::ErrorStatus es =AcDbEntity::dwgInFields (pFiler) ;
  5.         if ( es != Acad::eOk )
  6.                 return (es) ;
  7.         //----- Object version number needs to be read first
  8.         Adesk::UInt32 version =0 ;
  9.         if ( (es =pFiler->readUInt32 (&version)) != Acad::eOk )
  10.                 return (es) ;
  11.         if ( version > nmdsNameLine::kCurrentVersionNumber )
  12.                 return (Acad::eMakeMeProxy) ;
  13.         //- Uncomment the 2 following lines if your current object implementation cannot
  14.         //- support previous version of that object.
  15.         //if ( version < nmdsNameLine::kCurrentVersionNumber )
  16.         //        return (Acad::eMakeMeProxy) ;
  17.         //----- Read params
  18.         for (int i = 0; i < name_points.length(); i++)
  19.         {
  20.                 pFiler->readItem(&name_points[i]);//此函数打开包含自定义实体的dwg时执行,但在此处其实是无法获取到name_points.length(),因为name_points就是一个空值,所以打开文件时其实是无法绘制的,所以后来在cad中打开dwg时会出现无效实体然后提示修复,修复就是帮你删除掉这些实体
  21.         }

  22.         return (pFiler->filerStatus ()) ;
  23. }
复制代码

这两函数写不对,自定义实体终究就是无效的。
所以我通过调试,重新实现了这两函数,并给自定义实体添加了一个新的成员,len,即点集合的长度。写入和读出时,对长度也进行操作,终于自定义实体被完善了。
新的代码:
  1. Acad::ErrorStatus nmdsNameLine::dwgOutFields (AcDbDwgFiler *pFiler) const {
  2.         assertReadEnabled () ;
  3.         //----- Save parent class information first.
  4.         Acad::ErrorStatus es = AcDbEntity::dwgOutFields (pFiler) ;

  5.         if (pFiler->filerType() == AcDb::kWblockCloneFiler)
  6.                 pFiler->writeHardPointerId((AcDbHardPointerId)ownerId());

  7.         if ( es != Acad::eOk )
  8.                 return (es) ;
  9.         //----- Object version number needs to be saved first
  10.         if ( (es =pFiler->writeUInt32 (nmdsNameLine::kCurrentVersionNumber)) != Acad::eOk )
  11.                 return (es) ;
  12.         //----- Output params
  13.         pFiler->writeInt32(len);
  14.         AcGePoint3d *Points = new AcGePoint3d[len];
  15.         for (Adesk::Int32 i = 0; i < len; i++)
  16.         {
  17.                 Points[i] = name_points[i];
  18.         }
  19.         // 矩阵变换,这里我的自定义实体需要缩小与位移,所以必须先处理再写入
  20.         Transform(xform_scale,Points);
  21.         Transform(xform_move,Points);
  22.         Transform(xform_rotate,Points);
  23.         for (Adesk::Int32 i = 0; i < len; i++)
  24.         {
  25.                 pFiler->writePoint3d(Points[i]);
  26.         }
  27.         return (pFiler->filerStatus ()) ;
  28. }
复制代码
  1. Acad::ErrorStatus nmdsNameLine::dwgOutFields (AcDbDwgFiler *pFiler) {
  2.         assertWriteEnabled () ;
  3.         //----- Read parent class information first.

  4.         Acad::ErrorStatus es = AcDbEntity::dwgInFields (pFiler) ;

  5.         if(pFiler->filerType() == AcDb::kWblockCloneFiler)
  6.         {
  7.                 AcDbHardPointerId Id;
  8.                 pFiler->readItem(&Id);
  9.         }

  10.         if ( es != Acad::eOk )
  11.                 return (es) ;
  12.         //----- Object version number needs to be read first
  13.         Adesk::UInt32 version =0 ;
  14.         if ( (es =pFiler->readUInt32 (&version)) != Acad::eOk )
  15.                 return (es) ;
  16.         if ( version > nmdsNameLine::kCurrentVersionNumber )
  17.                 return (Acad::eMakeMeProxy) ;
  18.         //- Uncomment the 2 following lines if your current object implementation cannot
  19.         //- support previous version of that object.
  20.         //if ( version < nmdsNameLine::kCurrentVersionNumber )
  21.         //        return (Acad::eMakeMeProxy) ;
  22.         //----- Read params

  23.         name_points.removeAll();
  24.         pFiler->readInt32(&len);//先读取一下长度

  25.         AcGePoint3d *Points = new AcGePoint3d[len];

  26.         for (Adesk::Int32 i = 0; i < len; i++)
  27.         {
  28.                 pFiler->readPoint3d(&Points[i]);//读取时需要AcGePoint3d*格式
  29.                 name_points.append(Points[i]);//最后存到name_points中供WorldDraw函数绘制
  30.         }

  31.         return (pFiler->filerStatus ()) ;
  32. }
复制代码


改了这俩函数后,自定义实体才没有了问题,之前的绘制不全无法删除等错误都得到了解决。
感谢晓东cad各位的支持,想要深入了解再回复我吧,先就写这么多了。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

发表于 2020-8-30 20:50:03 | 显示全部楼层
rwss009 发表于 2020-8-3 15:35
大佬有个发现,就是如果我不新建数据库然后readDwgFile的话,是可以完全绘制在当前数据库中的。但读取文 ...

    pCurDb=acdbHostApplicationServices()->workingDatabase();

        Acad::ErrorStatus es=pCurDb->saveAs(_T("e:\\b.dwg")); //  需设置当前数据库为别的DWG CAD 打开文件名变了

或下面也不会出错,但当前DWG的文件名变SAVEAS的文件名了
//        AcApDocument*curDocument = acDocManager->curDocument();
//        const ACHAR *p = curDocument->fileName();
//        acDocManager->setCurDocument(NULL);
//        acDocManager->unlockDocument(acDocManager->curDocument());//不锁CAD打开的DWG 非 PDB2读的DWG,就可saveas
//        es=pDb2->saveAs(_T("e:\\a.dwg")); //  需设置当前数据库为别的DWG CAD 打开文件名变了
//        acDocManager->lockDocument(acDocManager->curDocument());//锁CAD打开的DWG 非 PDB2读的DWG,就可saveas
//        acDocManager->setCurDocument(curDocument);
//        p = curDocument->fileName();//变为E:\a.dwg

论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-6-10 04:48 , Processed in 0.413369 second(s), 49 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表