Тема: Обработать клик по элементу чертежа
Необходимо определить, что пользователь кликнул по элементу Multiline Text.
Подскажите, пожалуйста, какой reactor или функция отвечают за обработку клика/двойного клика на некотором типе объектов.
Спасибо
Информационный портал для профессионалов в области САПР
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Форумы CADUser → Программирование → ObjectARX → Обработать клик по элементу чертежа
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Необходимо определить, что пользователь кликнул по элементу Multiline Text.
Подскажите, пожалуйста, какой reactor или функция отвечают за обработку клика/двойного клика на некотором типе объектов.
Спасибо
Одиночный клик обычно не обрабатывают, а для двойного: AcEditorReactor::beginDoubleClick или https://www.caduser.ru/forum/topic37026.html или используй acedRegisterFilterWinMsg()
> Александр Ривилис
Александр, на сколько понял из ваших комментариев в теме https://www.caduser.ru/forum/topic37026.html, в sdk 2000 нет встроенного обработчика двойного клика.
В таком случае придется регистрировать его через acedRegisterFilterWinMsg()?
Как с таким решением получить элемент, на котором сделан клик?
Если это требует значительных затрат или невозможно, то хотелось бы знать, имеется ли возомжность встроить свой пункт в контекстное меню элемента.
Спасибо
Когда-то писал что-то такое, но не тестировал:
BOOL DoubleClickFilter(MSG *pMsg) { BOOL MyBlock = FALSE; // Обрабатываем только если DBLCLK и это окно DwgView if (pMsg->message == WM_LBUTTONDBLCLK && acedGetAcadDwgView()->GetSafeHwnd() == pMsg->hwnd) { acedDwgPoint dcsPt,ucsPt; CPoint winPt(LOWORD(pMsg->lParam), HIWORD(pMsg->lParam)); // Преобразуем координаты курсора в DCS acedCoordFromPixelToWorld(winPt, dcsPt); struct resbuf dcs, ucs; dcs.restype = RTSHORT; dcs.resval.rint = 2; // DCS ucs.restype = RTSHORT; ucs.resval.rint = 1; // UCS // Преобразуем координаты курсора в UCS для acedSSGet acedTrans(dcsPt, &dcs, &ucs, FALSE, ucsPt); ads_name ss,en; // Находим примитив под курсором: if (acedSSGet(":E", ucsPt, NULL, NULL, ss) == RTNORM) { // Нужно обязательно включить блокировку!!! if (acDocManager->lockDocument(curDoc()) == Acad::eOk) { AcDbObjectId eid; acedSSName(ss,0,en); if (acdbGetObjectId(eid,en) == Acad::eOk) { AcDbObjectPointer<AcDbBlockReference> pBlk(eid,AcDb::kForRead); if (pBlk.openStatus() == Acad::eOk) { AcDbObjectPointer<AcDbBlockTableRecord> pBtr(pBlk->blockTableRecord(),AcDb::kForRead); if (pBtr.openStatus() == Acad::eOk) { char *pName = NULL; if (pBtr->getName(pName) == Acad::eOk) { // Если указан блок и его имя "Myblock" - обработаем его // Если нет - пусть с ним мучается AutoCAD if (!stricmp(pName,"MyBlock")) { pBtr->close(); acedAlert("Это наш блок - попробуем его редактировать."); // Снимаем ручки acedSSSetFirst(NULL,NULL); // Увеличим масштаб блока в 1.2 раза AcGeScale3d sc = pBlk->scaleFactors(); sc.setToProduct(sc,1.2); Acad::ErrorStatus es; if ((es = pBlk->upgradeOpen()) == Acad::eOk) { pBlk->setScaleFactors(sc); pBlk->downgradeOpen(); } else { char buf[256]; sprintf(buf,"Ошибка при попытке открыть блок на запись: %s",acadErrorStatusText(es)); acedAlert(buf); } // Сообщаем AutoCAD, что ему уже не нужно // обрабатывать DBLCLK MyBlock = TRUE; } free(pName); } } } acDocManager->unlockDocument(curDoc()); } } } } return MyBlock; }
Думаю что нужно будет этот код хорошо причесывать.
В контекстное меню элемента можно встроить свой пункт (пункты). При помощи acedAddObjectContextMenu(). Пример смотри в samples\editor\mfcsamps\contextmenu
Спасибо, Александр.
Ваш пример запустил. Попробую реализовать свою задачу.
> Александр Ривилис
Используя Ваш пример, определил двойной клик на элементе AcDbMText.
Теперь у меня есть AcDbObjectId и AcDbObjectPointer этого элемента.
Подскажите, пожалуйста, как я могу извлечь текст из AcDbMText.
Хотелось бы ещё узнать, можно ли подвеситься на событие перехода по гиперссылке при клике с зажатым Ctrl по некоторому entity и добавить свою логику для кастомных протоколов, ссылки которых AutoCAD не рискует отдавать системе.
Спасибо.
Первого вопроса не понял. Если у тебя есть AcDbObjectId, то открываешь AcDbMtext и используя его метод contents или text получаешь текст.
> Александр Ривилис
Ответ на первый вопрос понял. Метода text() правда, у AcDbMText не нашел. А contents() возвращает текст с параметрами форматирования. Придется его разбирать самому, если нет другой возможности у SDK. Подскажите, пожалуйста.
Первого вопроса не понял.
Мм.. наверное все же речь шла о втором вопросе.. поэтому поясню примером. Добавляете элемент, например, MText. В его свойстве Hyperlink указываете гиперссылку "https://www.caduser.ru/". Теперь, если подвести курсор к данному элементу чертежа, нажать Ctrl и кликнуть, то "https://www.caduser.ru/" откроется в браузере.
Теперь предположим, что у меня есть другой протокол, не http, о котором знает система. Например, test: "test://mylink". Т.е., если я вставлю такой гиперлинк в MS Word и кликну по нему - то, например, откроется приложение, ассоциированное с протоколом и в нем откроется данный линк. Если же я вставлю этот гиперлинк в свойство Hyperlink элемента MText и кликну - то получу сообщение "The system cannot find the path specified."
Я хотел бы сам определить логику работы AutoCAD, когда в свойстве элемента Hyperlink гиперлинк с определенным префиксом протокола.
> equilibrium
По первому вопросу воспользуйся методом explodeFragments. Метод text появился в версии 2008.
По второму вопросу - тоже фильтр, но на CTRL-click
> Александр Ривилис
Обработал CRTL+click, однако есть проблема с достачей гиперлинка из свойств.
Использую метод getField(), однако есть сомнения в том, что это тот метод, что мне нужен.
Нашел пример, https://www.caduser.ru/forum/topic35873.html, так как по propName "Hyperlink" метод не достал мне field.
Однако и "TEXT" из MText он не достал.
А при чем здесь field?
Command: (entget(car(entsel))'("*")) Select object: ((-1 . <Entity name: -45158c98>) (0 . "LINE") (330 . <Entity name: -4515a308>) (5 . "1AD") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbLine") (10 955.741 847.074 0.0) (11 1441.9 1319.76 0.0) (210 0.0 0.0 1.0) (-3 ("PE_URL" (1000 . "test://mylink") (1002 . "{") (1000 . "aaa") (1002 . "{") (1071 . 0) (1002 . "}") (1002 . "}"))))
Так что можно или проанализировать расширенные данные или:
static void HyperlinkHypTest(void) { ads_name en; ads_point p; if (acedEntSel(_T("\nВыберите примитив: "),en,p) == RTNORM) { AcDbObjectId eId; acdbGetObjectId(eId,en); AcDbObjectPointer<AcDbEntity> pEnt(eId,AcDb::kForRead); if (pEnt.openStatus() == Acad::eOk) { AcDbHyperlinkCollection *pcHCL = NULL; ACRX_X_CALL(pEnt.object(), AcDbEntityHyperlinkPE)->getHyperlinkCollection(pEnt, pcHCL, false, true); if (pcHCL && pcHCL->count() != 0) { AcDbHyperlink * pcHO; for (int i = 0; i < pcHCL->count(); i++) { pcHO = pcHCL->item(i); acutPrintf(_T("\nHyperlink name: %s"), pcHO->name()); acutPrintf(_T("\nHyperlink location: %s"), pcHO->subLocation()); acutPrintf(_T("\nHyperlink description: %s"), pcHO->description()); } } } } }
> Александр Ривилис
То, что нужно, Александр.
Спасибо.
Вот правда перенес код из тестового проекта в рабочий. Теперь вызов
acedSSGet(_ADT(":E"), ucsPt, NULL, NULL, ss)
возвращает код -5001 - RTERROR.
Повторю за Вами.. но приведу код функции-фильтра целиком:
BOOL OpenHyperlinkFilter(MSG *pMsg) { BOOL halt = FALSE; // if CTRL + LB Click if (pMsg->message == WM_LBUTTONUP && pMsg->wParam == MK_CONTROL) { // if window is DwgView if (acedGetAcadDwgView()->GetSafeHwnd() == pMsg->hwnd) { acedDwgPoint dcsPt, ucsPt; CPoint winPt(LOWORD(pMsg->lParam)); // Convert cursor coordinates to DCS acedCoordFromPixelToWorld(winPt, dcsPt); struct resbuf dcs, ucs; dcs.restype = RTSHORT; dcs.resval.rint = 2; // DCS ucs.restype = RTSHORT; ucs.resval.rint = 1; // UCS // Convert cursor coordinates to UCS (for acedSSGet) acedTrans(dcsPt, &dcs, &ucs, FALSE, ucsPt); ads_name ss, en; // Get entity under cursor [b]if (acedSSGet(_ADT(":E"), ucsPt, NULL, NULL, ss) == RTNORM)[/b] { // Set lock is required if (acDocManager->lockDocument(curDoc()) == Acad::eOk) { AcDbObjectId eid; acedSSName(ss, 0, en); if (acdbGetObjectId(eid, en) == Acad::eOk) { AcDbObjectPointer<AcDbEntity> entity(eid, AcDb::kForRead); if (entity.openStatus() == Acad::eOk) { AcDbHyperlinkCollection *pcHCL = NULL; ACRX_X_CALL(entity.object(), AcDbEntityHyperlinkPE)-> getHyperlinkCollection(entity.object(), pcHCL, false, true); if (pcHCL && pcHCL->count() != 0) { AcDbHyperlink * pcHO; for (int i = 0; i < pcHCL->count(); i++) { pcHO = pcHCL->item(i); acutPrintf(_ADT("\nHyperlink name: %s"), pcHO->name()); acutPrintf(_ADT("\nHyperlink location: %s"), pcHO->subLocation()); acutPrintf(_ADT("\nHyperlink description: %s"), pcHO->description()); } } acDocManager->unlockDocument(curDoc()); } } } } } } return halt; }
> equilibrium
А в тестовом примере все работало? Если да, то разбирайся в чем разница.
Кстати, система координат у тебя установлена WCS? И вид в плане? Если нет, то нужно преобразаовывать координаты.
> Александр Ривилис
Александр, я все же нашел отличие, код работает.
Я бы ещё добавил сюда проверку на класс объекта
if (entity->isKindOf(ВашКласс::desc())){
}
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Форумы CADUser → Программирование → ObjectARX → Обработать клик по элементу чертежа
Форум работает на PunBB, при поддержке Informer Technologies, Inc