设为首页收藏本站

晓东CAD家园-论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 3120|回复: 5

[每日一码] AutoCAD中实现双击编辑

[复制链接]

已领礼包: 1个

财富等级: 恭喜发财

发表于 2016-10-5 16:01:14 | 显示全部楼层 |阅读模式

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

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

x
转帖一篇网上的文章

AutoCAD中arx编程实现双击编辑有两种方法,其一是基于类AcDbDoubleClickEdit的双击事件,另一方法是使用反应器机制实现。

(一) 基于类AcDbDoubleClickEdit的双击事件实现双击编辑

(1)AutoCAD2002-AutoCAD2009版本

AutoCAD2002-AutoCAD2009中有ObjectARX API专门用来处理实体的双击事件,此API基于AcDbDoubleClickEdit类。在AutoCAD中双击实体时,默认的行为是调用相应的实体定义编辑器或对象属性管理器。如果多个实体同时被选中,在选择集中双击实体会弹出对象属性管理器。对于自定义实体,可以重载AcDbDoubleClickEdit类的双击事件,改变默认行为,为此需要从AcDbDoubleClickEdit为每个要处理双击事件的实体派生类。为了接受通告消息,在这个类中必需声明两个方法:一个是startEdit(),另一个是finishEdit()。当应用程序被加载的时候,AcDbDoubleClickEdit类要对要处理的数据库对象增加协议扩展,例如在InitApplication()初始化过程中增加如下的代码:

pPlineEdit = new AcDbDoubleClickEditPline;

AcDbPline::desc()->addX(AcDbDoubleClickEdit::desc(),pPlineEdit);

同样地,在卸载应用程序的时候去除数据库对象的协议扩展,方法如下:

AcDbPline::desc()->delX(AcDbDoubleClickEdit::desc());

要使程序能够被编译,还必需连接AcDblClkEditPE.lib库,可使用#pragma comment (lib ,"AcDblClkEditPE.lib")。并且在InitApplication()中增加如下的代码:

acrxDynamicLinker->loadModule(/*MSG0*/"ACDBLCLKEDITPE.ARX",Adesk::kFalse);



例子:

双击实体弹出对话框(重载AcDbDoubleClickEdit)ARX

// DoubleClickEdit.h: interface for the CDoubleClickEdit class.

//By freejsutin 2005-08-17

#include "AcDblClkEdit.h" //for dinfine AcDbDoubleClickEdit

#pragma comment (lib ,"AcDblClkEditPE.lib")

#include "actrans.h" //for dinfine actrTransactionManager

class CDoubleClickEdit : public AcDbDoubleClickEdit

{

public:

CDoubleClickEdit();

virtual ~CDoubleClickEdit();

void finishEdit(void);

void CDoubleClickEdit::startEdit(AcDbEntity *pEnt, AcGePoint3d clickpt);

private:

bool upgradeOpen(AcDbObject *pEnt);

};

// DoubleClickEdit.cpp: implementation of the CDoubleClickE//dit class.

///////////////////////////////////////////////////////////

#include "stdafx.h"

#include "autodrawing.h"

#include "DoubleClickEdit.h"

#include "DeviceAttribute.h"

void CDoubleClickEdit::finishEdit()

{



}

// 主要是这个函数在起作用,在这个函数里实现你想要的功能

void CDoubleClickEdit::startEdit(AcDbEntity *pEnt, AcGePoint3d clickpt)

{

// 由于要对实体进行编辑,先锁定文档

AcApDocument *pDoc = acDocManager->curDocument();

acDocManager->lockDocument(pDoc, AcAp::kWrite);



// 判断如果传进来的实体是我的自定义实体,便进行修改操作

if (pEnt->isKindOf(cascoCDeviceDrawing::desc()))
{
   cascoCDeviceDrawing* pMyClass = cascoCDeviceDrawing::cast(pEnt);
   // 将打开级别升级到可写方式,防止对象以只读模式打开
   if( !upgradeOpen(pMyClass) )
   {
            acDocManager->unlockDocument(pDoc);
    return;
   }
   // 创建这个对象,以便切换CAD资源
   CAcModuleResourceOverride thisResource;

   CDeviceAttribute Diatest(CWnd::FromHandle(adsw_acadMainWnd()));
   Diatest.DoModal();
   pMyClass->close();
}
// 所有修改完成,解锁文档
acDocManager->unlockDocument(pDoc);
// 刷新显示
actrTransactionManager->flushGraphics();
}
bool CDoubleClickEdit::upgradeOpen(AcDbObject *pEnt)
{
if(pEnt->upgradeOpen()!=Acad::eOk)
{
   acutPrintf("错误:不能打开%s实体!", pEnt->isA()->name());
   return FALSE;
}
return TRUE;
}

(2)AutoCAD2010及以上版本

AutoCAD2010及以上版本没有AcDbDoubleClickEdit类,在AcDblClkEditPE.arx中的 AcDbDoubleClickEdit 功能已在  AcApp.arx 和 acad.lib中了。(AutoCAD2010及以上版本自定义实体的时worldDraw(AcGiWorldDraw *mode)等也改为subWorldDraw(AcGiWorldDraw *mode))


    为使 AutoCAD 2010及以上版本的双击扩展协议能起作用,必需:

    1、删除调用AcDblClkEditPE.arx 的 loadModule() 。

    2、删除 AcDbDoubleClickEdit::rxinit() ,这项工作已能自动完成。

    3、Include the AcDblClkEdit.h

    4、在你的.cpp模块之一中增加 ACRX_DEFINE_MEMBERS(AcDbDoubleClickEdit)

(二) 使用反应器机制实现双击编辑

Autodesk为开发者提供了反应器机制,它类似于MFC的消息处理,利用它我们可以响应输入事件、实体添加/编辑/删除等事件。常见的AutoCAD反应器有:编辑反应器(AcEditorReactor)、实体反应器(AcDbEntityReactor)、对象反应器(AcDbObjectReactor)、图形数据库反应器(AcDbDatabaseReactor)、文档管理反应器(AcApDocManagerReactor)等。我们在这里是利用编辑反应器来实现鼠标双击事件的响应的,下面是实现步骤。

第一步 派生一个编辑反应器类CMyEditReactor。并重载编辑反应器的如下方法:

      virtual void beginDoubleClick(const AcGePoint3d& clickPoint);  这里只返回了双击时鼠标所在的一点,并不像上面方法(一)双击事件还返回了该点所在的实体对象。在本方法中怎样由该点获得要编辑的实体是本方法的关键。

   第二步 声明一个全局CMyEditReactor对象,如下:

      static CMyEditReactor *gpDblClkTest;

   第三步 在应用程序初始化时创建反应器对象,将反应器对象增加到编辑反应器列表。

// Init this application. Register your

// commands, reactors...

void InitApplication()

{

// NOTE: DO NOT edit the following lines.

//{{AFX_ARX_INIT

............................................

//}}AFX_ARX_INIT

// TODO: add your initialization functions

gpDblClkTest = new CMyEditReactor(); // 创建编辑反应器对象

acedEditor->addReactor(gpDblClkTest );

}

第四步 在应用程序卸载时从内存中清除反应器对象,将反应器对象从编辑反应器列表中删除。

// Unload this application. Unregister all objects

// registered in InitApplication.

void UnloadApplication()

{

// NOTE: DO NOT edit the following lines.

//{{AFX_ARX_EXIT

.........................................................

//}}AFX_ARX_EXIT

// TODO: clean up your application

if(gpDblClkTest)

{

acedEditor->removeReactor(gpDblClkTest);

delete gpDblClkTest; // 清除编辑反应器对象

gpDblClkTest = NULL;

}

}

第五步 响应鼠标事件,编写响应代码。

void CMyEditReactor::beginDoubleClick(const AcGePoint3d & clickPoint)

{

    ads_name ssName;

    ads_name entName;

    ads_point pt;

    AcDbObjectId id;

    AcDbEntity *pEnt=NULL;

    long len;

    if(acedSSGet(NULL,asDblArray(clickPoint),NULL,NULL,ssName)!= RTNORM )  //获得双击的选择集

    {

        acedSSFree(ssName);  

        return;   

    }

    Acad::ErrorStatus es;

    acedSSLength(ssName,&len);

    if (len>1)                    //表示多个实体重叠情况

    {

        acedSSFree(ssName);

        return;

    }

    if (acedSSName(ssName, 0, entName) == RTNORM) //获得实体名

    {

        es = acdbGetObjectId(id,entName);  //获得实体id

        if(es!=Acad::eOk)

        {

            AfxMessageBox(_T("打开实体ID失败"));

            acedSSFree(ssName);

            return;

        }

        es=acdbOpenObject(pEnt,id,AcDb::kForWrite);  //获得要处理的实体对象

        if(es!=Acad::eOk)

        {

            AfxMessageBox(_T("acdbOpenObject(pEnt,pID,AcDb::kForWrite)失败!"));

            acedSSFree(ssName);

            return;

        }

        // 由于要对实体进行编辑,先锁定文档

        AcApDocument *pDoc=acDocManager->curDocument();

        acDocManager->lockDocument(pDoc,AcAp::kWrite);

        // 判断如果传进来的实体是我的自定义实体,便进行修改操作

        if(pEnt->isKindOf(AsdkMyClass::desc()) == Adesk::kTrue)

        {

            AsdkMyClass* pMyClass = AsdkMyClass::cast(pEnt);

            // 创建这个对象,以便切换CAD资源

            CAcModuleResourceOverride thisResource;   

            // 创建我的修改实体对话框

            CDlgModiEnt Dlg(CWnd::FromHandle(adsw_acadMainWnd()));

            // 设定初值

            Dlg.setValue(pMyClass->GetFloorNum(), pMyClass->GetBaseHeight());

            // 如果“OK”按钮被按下,对自定义实体进行修改

            if (Dlg.DoModal() == IDOK) {

                pMyClass->SetFloorNum(Dlg.m_num);

                pMyClass->SetBaseHeight(Dlg.m_height);

                pMyClass->ExtendedBaseIni();

            }

            pMyClass->close();

        }

        else

            pEnt->close();

        // 所有修改完成,解锁文档

        acDocManager->unlockDocument(pDoc);

        acedSSFree(ssName);

    }

(三) 基于类AcDbDoubleClickEdit及基于反应器机制的双击事件实现双击编辑的不同

   1、基于类AcDbDoubleClickEdit需要从AcDbDoubleClickEdit为每个要处理双击事件的实体派生类。当应用程序被加载的时候,AcDbDoubleClickEdit类要对要处理的数据库对象增加协议扩展,在卸载应用程序的时候去除数据库对象的协议扩展。

   2、基于编辑反应器机制的只需派生一个编辑反应器类CMyEditReactor。并重载编辑反应器的如下方法:

virtual void beginDoubleClick(const AcGePoint3d& clickPoint),只创建一个全局反应器对象,可对不同的对象选择编辑。

  3、使用编辑反应器机制的工作量要小,但编辑完成之后还是会弹出属性编辑对话框,不知怎样解决。(解决:再进行自定义实体双击编辑之前,改变系统变量DBLCLKEDIT为0,完成编辑之后再还原系统变量
  4、基于类AcDbDoubleClickEdit的方式编辑完成之后不会弹出属性编辑对话框,双击时存在多选实体时,只会弹出属性编辑对话框,不会弹出属性编辑对话框,与cad本身的编辑方式相同。

(四)存在问题

    当基于编辑反应器机制时,选用cad工具->选项->配置->可用配置的另一配置时,双击编辑会出现问题。(已解决:需单文档,多文档出错。将源码中锁定文档的语句再向前移动就能解决mdi文档出错的问题)


  对于使用编辑反应器机制编辑完成之后还是会弹出属性编辑对话框及选用cad工具->选项->配置->可用配置的另一配置时,双击编辑会出现问题的情况,不知怎样解决?



原码是根据网上代码增加、修改。

请点击此处下载

查看状态:需购买或无权限

您的用户组是:游客

文件名称:DBLCLKedit.zip 
下载次数:83  文件大小:136.52 KB 
下载权限: 不限 以上  [免费赚D豆]


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

已领礼包: 480个

财富等级: 日进斗金

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

使用道具 举报

已领礼包: 2个

财富等级: 恭喜发财

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

使用道具 举报

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

使用道具 举报

已领礼包: 6050个

财富等级: 富甲天下

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

使用道具 举报

已领礼包: 57个

财富等级: 招财进宝

发表于 2021-3-31 09:59:56 | 显示全部楼层
谢谢分享,刚学习了通过类实现双击事件,正好看看反应器。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2021-4-21 07:28 , Processed in 0.450930 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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