Fork me on GitHub

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;
        }
    }
}
View Code

 

最后我需要做的就是,选择要选择的实体,把实体的ObjectId传入到func函数里,在func函数里进行旋转操作,我发现,必须在func函数里每滑动依次鼠标,就需要对实体进行依次开闭操作,如果,只是在处理函数里只旋转,而不关闭实体,cad里的实体是不会旋转的,到最后你什么时候关闭这个打开的实体,这个实体才会旋转到最后一次的操作上来。
下面是我在命令类的全局参数和定义的操作命令:

#define PI 3.14159265358979323846

BOOL func(MSG *msg);

AcDbObjectId oId;
AcGeMatrix3d matx1;
AcGeMatrix3d matx2;
RegMsg * reg = NULL;
View Code

 

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();
            }
        }

    }
View Code

 

static void ECDMyGroupMyUnRegMsg() {

        acDocManager->unlockDocument(acDocManager->curDocument());

        if (reg != NULL) {

            reg->unReg();

            reg = NULL;

            delete reg;
        }
    }
View Code
posted @ 2020-01-07 11:47  HelloLLLLL  阅读(1303)  评论(0编辑  收藏  举报