ObjectArx 使用消息钩子实现鼠标滚轮旋转实体
测试结果:
实现方法:主要是程序注册一个消息函数:func,拦截鼠标滚轮触发的消息,需要注意的是,以写的方式处理实体时需要锁定文档。注册func的主要方法是:
BOOL acedRegisterFilterWinMsg(
const AcedFilterWinMsgFn pfn
);
AcedFilterWinMsgFn 这个类型 是一个函数指针,其实他是这样的:
typedef BOOL (* AcedFilterWinMsgFn)(MSG*);接受一个MSG *的参数,返回BOOL类型的函数。
这个MSG是个struct,参数内部是这样的:
typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; #ifdef _MAC DWORD lPrivate; #endif } MSG
我们主要使用到的是message成员,和wParam成员。使用message成员过滤出鼠标滚轮滑动的消息,wParam的值来区分滚轮上和下的运动,然后我们就把实体的旋转写在这个里面。详细见代码:、
BOOL func(MSG *msg) { int zdFx = 0; if (msg->message == WM_MOUSEWHEEL) { zdFx = (short)HIWORD(msg->wParam); acutPrintf(L"\n%d", zdFx); if (zdFx == 120) { AcDbEntity * pEnt = NULL; ErrorStatus es = acdbOpenObject(pEnt, oId, AcDb::kForWrite); if (es == Acad::eOk) { pEnt->transformBy(matx1); pEnt->close(); } } else if (zdFx == -120) { AcDbEntity * pEnt = NULL; ErrorStatus es = acdbOpenObject(pEnt, oId, AcDb::kForWrite); if (es == Acad::eOk) { pEnt->transformBy(matx2); pEnt->close(); } } return TRUE; } return FALSE; }
这个func是个全局函数,这样方便我在注册func的类里面调用。因为注册了这个消息,cad默认的滚轮放大缩小的功能就会被屏蔽掉,需要使用解除注册的方法来取消对这个消息的监视。这个方法是:
BOOL acedRemoveFilterWinMsg(
const AcedFilterWinMsgFn pfn
);
我把注册和取消的方法封装到一个类里面,并且定义了一个BOOL类型的全局变量来避免重复注册和重复取消,见代码:
#include "stdafx.h" #include "RegMsg.h" static bool isReged = FALSE; extern BOOL func(MSG *msg); RegMsg::RegMsg() { } RegMsg::~RegMsg() { } void RegMsg::reg() { if (!isReged) { acutPrintf(L"\n reging...\n"); if (!acedRegisterFilterWinMsg(func)) { acutPrintf(L"\n reg failed\n"); } else{ acutPrintf(L"\n reg success\n"); isReged = TRUE; } } } void RegMsg::unReg() { if (isReged) { if (!acedRemoveFilterWinMsg(func)) { acutPrintf(L"\n unreg failed\n"); } else { acutPrintf(L"\n unreg success\n"); isReged = FALSE; } } }
最后我需要做的就是,选择要选择的实体,把实体的ObjectId传入到func函数里,在func函数里进行旋转操作,我发现,必须在func函数里每滑动依次鼠标,就需要对实体进行依次开闭操作,如果,只是在处理函数里只旋转,而不关闭实体,cad里的实体是不会旋转的,到最后你什么时候关闭这个打开的实体,这个实体才会旋转到最后一次的操作上来。
下面是我在命令类的全局参数和定义的操作命令:
#define PI 3.14159265358979323846 BOOL func(MSG *msg); AcDbObjectId oId; AcGeMatrix3d matx1; AcGeMatrix3d matx2; RegMsg * reg = NULL;
static void ECDMyGroupMyRegMsg() { acDocManager->lockDocument(acDocManager->curDocument()); if (reg == NULL) { reg = new RegMsg(); AcRxClass *cls = AcDbEntity::desc(); AcDbEntity * pEnt = NULL; AcGePoint3d pickPoint; if (CSelectUtil::PromptSelectEntity(L"选择实体:", cls, pEnt, pickPoint, true)) { oId = pEnt->objectId(); pEnt->close(); matx1 = AcGeMatrix3d::rotation(1.0 / 18 * PI, AcGeVector3d::kZAxis, pickPoint); matx2 = AcGeMatrix3d::rotation(-1.0 / 18 * PI, AcGeVector3d::kZAxis, pickPoint); reg->reg(); } } }
static void ECDMyGroupMyUnRegMsg() { acDocManager->unlockDocument(acDocManager->curDocument()); if (reg != NULL) { reg->unReg(); reg = NULL; delete reg; } }