Контекстное меню ручек с использованием AcDbMultiModesGripPE
Это пример проекта, который реализует контекстное меню ручек для собственного примитива с использованием класса AcDbMultiModesGripPE. Он демонстрирует использование мультирежимных ручек, которые выполняют ввод в зависимости от собственного примитива.Чтобы было веселее, я создал собственный примитив, который напоминает дерево. Контекстное меню его ручек показывает два режима: "Spring" (весна) and "Winter" (зима). После того как собственный примитив дерева создан, контекстное меню появляется, когда курсор оказывается возле ручки (ручка становится «теплой»). Выбор "Spring" (весна) приводит к тому, что у дерева появляются листья, а при выборе "Winter" (зима) дерево сбрасывает листья.
В нашем случае, так как режимы не связаны с редактированием при помощи ручек и нам не нужно начинать редактирование перетаскиванием за ручку, тип днйствия будет установлен как команда. После выбора режима, вызывается команда AutoCAD. В командной реализации, мы гарантируем, что дерево обновится на основе режима, который был выбран. Мне бы хотелось, чтобы иметь галочку в контекстном меню рядом с текущим режимом, но в API нет способа это сделать в настоящее время и мы добавили это пожелание в wish-list для команды инженеров.
Вот соответствующий код, а полный проект примера можно скачать по ссылке ниже:
- // Файл заголовка
- // TreeMultiModesGripPE.h
- #pragma once
- #include "dbMultiModesGrip.h"
- class AdskTreeMultiModesGripPE : public AcDbMultiModesGripPE
- {
- private:
- static AcDbMultiModesGripPE::GripMode _currentGripMode;
- static AcDbObjectId _lastModifiedEntId;
- public:
- ACRX_DECLARE_MEMBERS(AdskTreeMultiModesGripPE);
- AdskTreeMultiModesGripPE();
- ~AdskTreeMultiModesGripPE();
- static AcDbObjectId getLastModifiedEntId();
- virtual bool getGripModes(AcDbEntity* pThis,
- AcDbGripData* pGripData,
- AcArray<GripMode>& modes,
- unsigned int& curMode) const;
- virtual unsigned int mode(AcDbEntity* pThis,
- AcDbGripData* pGripData) const;
- virtual AcDbMultiModesGripPE::GripMode modeEx(
- AcDbEntity* pThis,
- AcDbGripData* pGripData) const;
- virtual bool setMode(
- AcDbEntity* pThis,
- AcDbGripData* pGripData,
- unsigned int newMode);
- virtual AcDbMultiModesGripPE::GripType gripType(
- AcDbEntity* pThis, AcDbGripData* pGripData) const;
- virtual void reset(AcDbEntity* pThis);
- };
- // Файл реализации
- // TreeMultiModesGripPE.cpp
- #include "StdAfx.h"
- #include "dbMultiModesGrip.h"
- #include "TreeMultiModesGripPE.h"
- #include "AdskTree.h"
- ACRX_CONS_DEFINE_MEMBERS(AdskTreeMultiModesGripPE,
- AcDbMultiModesGripPE, 1);
- AcDbMultiModesGripPE::GripMode
- AdskTreeMultiModesGripPE::_currentGripMode;
- AcDbObjectId AdskTreeMultiModesGripPE::_lastModifiedEntId
- = AcDbObjectId::kNull;
- AdskTreeMultiModesGripPE::AdskTreeMultiModesGripPE()
- {
- // Режим ручки по-умолчанию
- _currentGripMode.Mode = 0;
- _currentGripMode.DisplayString = AcString("Spring");
- }
- AdskTreeMultiModesGripPE::~AdskTreeMultiModesGripPE()
- {
- }
- // Возвращаем возможные режимы ручки
- bool AdskTreeMultiModesGripPE::getGripModes(
- AcDbEntity* pThis,
- AcDbGripData* pGripData,
- AcArray<GripMode>& modes,
- unsigned int& curMode) const
- {
- GripMode gripMode1;
- gripMode1.Mode = 0;
- gripMode1.DisplayString = AcString("Spring");
- gripMode1.ActionType = GripActionType::kCommand;
- gripMode1.CommandString = AcString("ModeSwitchCmd ");
- modes.append(gripMode1);
- GripMode gripMode2;
- gripMode2.Mode = 1;
- gripMode2.DisplayString = AcString("Winter");
- gripMode2.ActionType = GripActionType::kCommand;
- gripMode2.CommandString = AcString("ModeSwitchCmd ");
- modes.append(gripMode2);
- curMode = 0;
- return true;
- }
- // Получаем идентификатор текущего режима.
- unsigned int AdskTreeMultiModesGripPE::mode(
- AcDbEntity* pThis,
- AcDbGripData* pGripData) const
- {
- return _currentGripMode.Mode;
- }
- // Возвращаем текущий режим.
- AcDbMultiModesGripPE::GripMode
- AdskTreeMultiModesGripPE::modeEx(
- AcDbEntity* pThis, AcDbGripData* pGripData) const
- {
- return _currentGripMode;
- }
- // Устанавливаем текущий режим.
- bool AdskTreeMultiModesGripPE::setMode(
- AcDbEntity* pThis,
- AcDbGripData* pGripData,
- unsigned int newMode)
- {
- _currentGripMode.Mode = newMode;
- AcDbObjectId entId = pThis->id();
- AdskTree *pTree = AdskTree::cast(pThis);
- switch(newMode)
- {
- case 0:
- acutPrintf(ACRX_T("\nВесна, листочки растут!"));
- _currentGripMode.DisplayString = AcString("Spring");
- pTree->setSeason(AcString("Spring"));
- // Для обновления графики
- _lastModifiedEntId = pTree->id();
- break;
- case 1:
- acutPrintf(ACRX_T("\nЗима, листочки опадают!"));
- _currentGripMode.DisplayString = AcString("Winter");
- pTree->setSeason(AcString("Winter"));
- // Для обновления графики
- _lastModifiedEntId = pTree->id();
- break;
- }
- return true;
- }
- // Получаем тип ручки для заданной ручки.
- AcDbMultiModesGripPE::GripType
- AdskTreeMultiModesGripPE::gripType(
- AcDbEntity* pThis, AcDbGripData* pGripData) const
- {
- return AcDbMultiModesGripPE::GripType::kPrimary;
- }
- // Получаем objectId примитива дерево для
- // обновления графики
- AcDbObjectId AdskTreeMultiModesGripPE::getLastModifiedEntId()
- {
- return _lastModifiedEntId;
- }
- // Сбрасываем текущий режим в значение по-умолчанию
- void AdskTreeMultiModesGripPE::reset(AcDbEntity* pThis)
- {
- _currentGripMode.Mode = 0;
- _currentGripMode.DisplayString = AcString("Spring");
- }
- // Файл заголовка собственного примитива
- // AsdkTree.h
- #pragma once
- #ifdef MULTIMODEGRIPSIMPLESAMPLE_MODULE
- #define DLLIMPEXP __declspec(dllexport)
- #else
- #define DLLIMPEXP
- #endif
- //-----------------------------------------------------------------------------
- #include "dbmain.h"
- //-----------------------------------------------------------------------------
- class DLLIMPEXP AdskTree : public AcDbEntity
- {
- public:
- ACRX_DECLARE_MEMBERS(AdskTree) ;
- protected:
- static Adesk::UInt32 kCurrentVersionNumber ;
- private:
- AcGePoint3d _basePoint;
- AcString _season;
- void BuildSubTree(
- AcGeLineSeg3d *pMainBranch,
- int level,
- AcGiWorldDraw *mode,
- Adesk::Boolean flower = Adesk::kFalse);
- public:
- AdskTree () ;
- virtual ~AdskTree () ;
- // Sets the season status
- void setSeason(AcString season);
- // Sets the insertion point
- void setBasePoint(AcGePoint3d basePoint);
- //----- AcDbObject protocols
- //- Dwg Filing protocol
- virtual Acad::ErrorStatus
- dwgOutFields (AcDbDwgFiler *pFiler) const ;
- virtual Acad::ErrorStatus
- dwgInFields (AcDbDwgFiler *pFiler) ;
- //----- AcDbEntity protocols
- //- Graphics protocol
- protected:
- virtual Adesk::Boolean subWorldDraw (AcGiWorldDraw *mode) ;
- virtual Acad::ErrorStatus
- subTransformBy(const AcGeMatrix3d& xform);
- //- Grip points protocol
- virtual Acad::ErrorStatus subGetGripPoints (
- AcDbGripDataPtrArray &grips,
- const double curViewUnitSize,
- const int gripSize,
- const AcGeVector3d &curViewDir,
- const int bitflags) const ;
- virtual Acad::ErrorStatus subMoveGripPointsAt (
- const AcDbVoidPtrArray &gripAppData,
- const AcGeVector3d &offset, const int bitflags) ;
- };
- #ifdef MULTIMODEGRIPSIMPLESAMPLE_MODULE
- ACDB_REGISTER_OBJECT_ENTRY_AUTO(AdskTree)
- #endif
- // Файл реализация собственного примитива
- // AdskTree.cpp
- #include "StdAfx.h"
- #include "AdskTree.h"
- Adesk::UInt32 AdskTree::kCurrentVersionNumber =1 ;
- ACRX_DXF_DEFINE_MEMBERS (
- AdskTree, AcDbEntity,
- AcDb::kDHL_CURRENT, AcDb::kMReleaseCurrent,
- AcDbProxyEntity::kNoOperation, ADSKTREE,
- ADSKMULTIMODEGRIPSIMPLESAMPLEAPP
- |Product Desc: A description for your object
- |Company: Your company name
- |WEB Address: Your company WEB site address
- )
- AdskTree::AdskTree () : AcDbEntity ()
- {
- _basePoint = AcGePoint3d::kOrigin;
- _season = AcString("Spring");
- }
- AdskTree::~AdskTree ()
- {
- }
- //----- AcDbObject protocols
- //- Dwg Filing protocol
- Acad::ErrorStatus AdskTree::dwgOutFields(AcDbDwgFiler *pFiler)
- const {
- assertReadEnabled () ;
- //----- Save parent class information first.
- Acad::ErrorStatus es =AcDbEntity::dwgOutFields (pFiler) ;
- if ( es != Acad::eOk )
- return (es) ;
- //----- Object version number needs to be saved first
- if ( (es =pFiler->writeUInt32
- (AdskTree::kCurrentVersionNumber)) != Acad::eOk )
- return (es) ;
- //----- Output params
- pFiler->writePoint3d(_basePoint);
- return (pFiler->filerStatus ()) ;
- }
- Acad::ErrorStatus AdskTree::dwgInFields(AcDbDwgFiler *pFiler)
- {
- assertWriteEnabled () ;
- //----- Read parent class information first.
- Acad::ErrorStatus es =AcDbEntity::dwgInFields (pFiler) ;
- if ( es != Acad::eOk )
- return (es) ;
- //----- Object version number needs to be read first
- Adesk::UInt32 version =0 ;
- if ( (es =pFiler->readUInt32 (&version)) != Acad::eOk )
- return (es) ;
- if ( version > AdskTree::kCurrentVersionNumber )
- return (Acad::eMakeMeProxy) ;
- //----- Read params
- pFiler->readPoint3d(&_basePoint);
- return (pFiler->filerStatus ()) ;
- }
- //----- AcDbEntity protocols
- Adesk::Boolean AdskTree::subWorldDraw (AcGiWorldDraw *mode)
- {
- assertReadEnabled () ;
- AcGeLineSeg3d mainBranch(
- _basePoint,
- AcGePoint3d(_basePoint.x,_basePoint.y+10.0,_basePoint.z));
- AcDbLine *pLine1 = new AcDbLine(
- mainBranch.startPoint(), mainBranch.endPoint());
- mode->geometry().draw(pLine1);
- delete pLine1;
- int level = 0;
- BuildSubTree(&mainBranch, level, mode);
- return (AcDbEntity::subWorldDraw (mode)) ;
- }
- void AdskTree::setBasePoint(AcGePoint3d basePoint)
- {
- _basePoint = basePoint;
- }
- void AdskTree::setSeason(AcString season)
- {
- _season = season;
- }
- void AdskTree::BuildSubTree(AcGeLineSeg3d *pMainBranch,
- int level,
- AcGiWorldDraw *mode,
- Adesk::Boolean flower)
- {
- if(mode->isDragging() && level >= 2)
- return; // Облегчаем для перетаскивания
- if(level >= 3)
- {
- if(_season == AcString("Spring"))
- {
- AcDbCircle *pLeaf = new AcDbCircle(
- pMainBranch->endPoint(),
- AcGeVector3d::kZAxis,
- pMainBranch->length() * 0.2);
- if(flower)
- pLeaf->setColorIndex(1);
- else
- pLeaf->setColorIndex(2);
- mode->geometry().draw(pLeaf);
- delete pLeaf;
- }
- return;
- }
- int subLevel = level + 1;
- AcGePoint3d sp = AcGePoint3d::kOrigin;
- AcGePoint3d ep = AcGePoint3d::kOrigin;
- AcGeInterval intrvl;
- pMainBranch->getInterval(intrvl, sp, ep);
- double len = pMainBranch->length();
- AcGePoint3dArray pts;
- pMainBranch->getSamplePoints(5, pts);
- const double PI = 3.1415926535897932385;
- int cnt = 1;
- if(level == 0)
- cnt = 2;
- for(;cnt < 5; cnt++)
- {
- AcGeVector3d dir = pMainBranch->direction().normalize();
- AcGePoint3d refPt1 = pts[cnt];
- if(cnt == 4)
- {
- AcGePoint3d refPt2 = refPt1 + (len * 0.5) * dir;
- AcGeLineSeg3d branch1(refPt1, refPt2);
- AcDbLine *pBranchLine1 = new AcDbLine(refPt1, refPt2);
- mode->geometry().draw(pBranchLine1);
- delete pBranchLine1;
- BuildSubTree(&branch1, subLevel, mode, Adesk::kTrue);
- }
- else
- {
- AcGePoint3d refPt2 = refPt1 +
- (len * 0.5) * dir.transformBy(
- AcGeMatrix3d::rotation( PI * 0.25,
- AcGeVector3d::kZAxis,
- refPt1
- ));
- AcGeLineSeg3d branch1(refPt1, refPt2);
- AcDbLine *pBranchLine1 = new AcDbLine(refPt1, refPt2);
- mode->geometry().draw(pBranchLine1);
- delete pBranchLine1;
- BuildSubTree(&branch1, subLevel, mode);
- dir = pMainBranch->direction().normalize();
- refPt2 = refPt1 + (len * 0.5) *
- dir.transformBy(AcGeMatrix3d::rotation(
- -PI * 0.25, AcGeVector3d::kZAxis, refPt1));
- AcGeLineSeg3d branch2(refPt1, refPt2);
- AcDbLine *pBranchLine2 = new AcDbLine(refPt1, refPt2);
- mode->geometry().draw(pBranchLine2);
- delete pBranchLine2;
- BuildSubTree(&branch2, subLevel, mode);
- }
- }
- }
- Acad::ErrorStatus AdskTree::subGetGripPoints (
- AcDbGripDataPtrArray &grips,
- const double curViewUnitSize,
- const int gripSize,
- const AcGeVector3d &curViewDir,
- const int bitflags ) const
- {
- assertReadEnabled () ;
- AcDbGripData *pGripData = new AcDbGripData();
- pGripData->setGripPoint(_basePoint);
- grips.append(pGripData);
- return Acad::eOk;
- }
- Acad::ErrorStatus AdskTree::subMoveGripPointsAt (
- const AcDbVoidPtrArray &gripAppData,
- const AcGeVector3d &offset,
- const int bitflags)
- {
- assertWriteEnabled () ;
- _basePoint += offset;
- return Acad::eOk;
- }
- Acad::ErrorStatus AdskTree::subTransformBy(
- const AcGeMatrix3d& xform)
- {
- assertWriteEnabled();
- _basePoint.transformBy(xform);
- return (AcDbEntity::subTransformBy(xform));
- }
- // Использование
- // acrxEntryPoint.cpp
- #include "resource.h"
- #include "AdskTree.h"
- #include "stdafx.h"
- #include "dbMultiModesGrip.h"
- #include "TreeMultiModesGripPE.h"
- static AdskTreeMultiModesGripPE *pMyMultiModeGrips = NULL;
- #define szRDS _RXST("Adsk")
- //----- ObjectARX EntryPoint
- class CMultiModeGripSimpleSampleApp : public AcRxArxApp {
- public:
- CMultiModeGripSimpleSampleApp () : AcRxArxApp () {}
- virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {
- // TODO: Load dependencies here
- // You *must* call On_kInitAppMsg here
- AcRx::AppRetCode retCode
- =AcRxArxApp::On_kInitAppMsg(pkt) ;
- AdskTreeMultiModesGripPE::rxInit();
- AdskTree::rxInit();
- acrxBuildClassHierarchy();
- // TODO: Add your initialization code here
- if(pMyMultiModeGrips == NULL)
- {
- pMyMultiModeGrips = new AdskTreeMultiModesGripPE();
- AdskTree::desc()->addX(
- AcDbMultiModesGripPE::desc(),
- pMyMultiModeGrips);
- }
- return (retCode) ;
- }
- virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt) {
- // TODO: Add your code here
- // You *must* call On_kUnloadAppMsg here
- AcRx::AppRetCode retCode
- = AcRxArxApp::On_kUnloadAppMsg (pkt) ;
- // TODO: Unload dependencies here
- if(pMyMultiModeGrips != NULL)
- {
- delete pMyMultiModeGrips;
- pMyMultiModeGrips = NULL;
- }
- return (retCode) ;
- }
- virtual void RegisterServerComponents () {
- }
- // "Tree" – команда для создания дерева
- static void AdskMultiModeGripSimpleSampleTREE(void)
- {
- ads_point pt;
- if (RTNORM != acedGetPoint(
- NULL, L"\nУкажите базовую точку для дерева: ", pt))
- return;
- AcGePoint3d insertionPt = asPnt3d( pt );
- AdskTree *pTree = new AdskTree();
- pTree->setDatabaseDefaults();
- pTree->setBasePoint(insertionPt);
- PostToDb(pTree);
- }
- // Добавление примитива к DB
- static Acad::ErrorStatus PostToDb(AcDbEntity* pEnt)
- {
- AcDbDatabase *pDb
- = acdbHostApplicationServices()->workingDatabase();
- AcDbObjectId objId;
- Acad::ErrorStatus es;
- AcDbBlockTable* pBlockTable;
- AcDbBlockTableRecord* pSpaceRecord;
- pDb->getBlockTable(pBlockTable, AcDb::kForRead);
- pBlockTable->getAt( ACDB_MODEL_SPACE,
- pSpaceRecord,
- AcDb::kForWrite);
- es = pSpaceRecord->appendAcDbEntity(objId, pEnt);
- es = pEnt->close();
- es = pSpaceRecord->close();
- es = pBlockTable->close();
- return es;
- }
- // Команда для обновления графики при изменении режима ручки
- // Она необходима для синхронизации графики с выбранным режимом
- static void AdskMultiModeGripSimpleSampleModeSwitchCmd(void)
- {
- AcDbObjectId entId
- = AdskTreeMultiModesGripPE::getLastModifiedEntId();
- AcApDocument *pActiveDoc
- = acDocManager->mdiActiveDocument();
- AcDbDatabase *pDb = pActiveDoc->database();
- if(entId.isNull())
- return;
- AcDbEntity* pEnt = NULL;
- acdbOpenAcDbEntity(pEnt, entId, AcDb::kForWrite);
- pEnt->recordGraphicsModified();
- pEnt->close();
- acedUpdateDisplay();
- }
- } ;
- //-----------------------------------------------------------------------------
- IMPLEMENT_ARX_ENTRYPOINT(CMultiModeGripSimpleSampleApp)
- ACED_ARXCOMMAND_ENTRY_AUTO(CMultiModeGripSimpleSampleApp,
- AdskMultiModeGripSimpleSample,
- TREE,
- TREE,
- ACRX_CMD_TRANSPARENT,
- NULL)
- ACED_ARXCOMMAND_ENTRY_AUTO(CMultiModeGripSimpleSampleApp,
- AdskMultiModeGripSimpleSample,
- ModeSwitchCmd,
- ModeSwitchCmd,
- ACRX_CMD_TRANSPARENT,
- NULL)
А вот и картинка собственного примитива «дерева» в двух режимах:
Источник: http://adndevblog.typepad.com/autocad/2013/12/grip-context-menu-using-acdbmultimodesgrippe.html
Обсуждение: http://adn-cis.org/forum/index.php?topic=453
Опубликовано 13.01.2014Отредактировано 13.01.2014 в 04:04:44