Тема: Обработать клик по элементу чертежа

Необходимо определить, что пользователь кликнул по элементу Multiline Text.
Подскажите, пожалуйста, какой reactor или функция отвечают за обработку клика/двойного клика на некотором типе объектов.
Спасибо

Re: Обработать клик по элементу чертежа

Одиночный клик обычно не обрабатывают, а для двойного: AcEditorReactor::beginDoubleClick или https://www.caduser.ru/forum/topic37026.html или используй acedRegisterFilterWinMsg()

Re: Обработать клик по элементу чертежа

> Александр Ривилис
Александр, на сколько понял из ваших комментариев в теме https://www.caduser.ru/forum/topic37026.html, в sdk 2000 нет встроенного обработчика двойного клика.
В таком случае придется регистрировать его через acedRegisterFilterWinMsg()?
Как с таким решением получить элемент, на котором сделан клик?
Если это требует значительных затрат или невозможно, то хотелось бы знать, имеется ли возомжность встроить свой пункт в контекстное меню элемента.
Спасибо

Re: Обработать клик по элементу чертежа

Когда-то писал что-то такое, но не тестировал:

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

Re: Обработать клик по элементу чертежа

Спасибо, Александр.
Ваш пример запустил. Попробую реализовать свою задачу.

Re: Обработать клик по элементу чертежа

> Александр Ривилис
Используя Ваш пример, определил двойной клик на элементе AcDbMText.
Теперь у меня есть AcDbObjectId и AcDbObjectPointer этого элемента.
Подскажите, пожалуйста, как я могу извлечь текст из AcDbMText.
Хотелось бы ещё узнать, можно ли подвеситься на событие перехода по гиперссылке при клике с зажатым Ctrl по некоторому entity и добавить свою логику для кастомных протоколов, ссылки которых AutoCAD не рискует отдавать системе.
Спасибо.

Re: Обработать клик по элементу чертежа

Первого вопроса не понял. Если у тебя есть AcDbObjectId, то открываешь AcDbMtext и используя его метод contents или text получаешь текст.

Re: Обработать клик по элементу чертежа

> Александр Ривилис
Ответ на первый вопрос понял. Метода 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 гиперлинк с определенным префиксом протокола.

Re: Обработать клик по элементу чертежа

> equilibrium
По первому вопросу воспользуйся методом explodeFragments. Метод text появился в версии 2008.
По второму вопросу - тоже фильтр, но на CTRL-click

Re: Обработать клик по элементу чертежа

> Александр Ривилис
Обработал CRTL+click, однако есть проблема с достачей гиперлинка из свойств.
Использую метод getField(), однако есть сомнения в том, что это тот метод, что мне нужен.
Нашел пример, https://www.caduser.ru/forum/topic35873.html, так как по propName "Hyperlink" метод не достал мне field.
Однако и "TEXT" из MText он не достал.

Re: Обработать клик по элементу чертежа

А при чем здесь 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());
           }
         }
       }
     }
  }

Re: Обработать клик по элементу чертежа

> Александр Ривилис
То, что нужно, Александр.
Спасибо.
Вот правда перенес код из тестового проекта в рабочий. Теперь вызов

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

Re: Обработать клик по элементу чертежа

> equilibrium
А в тестовом примере все работало? Если да, то разбирайся в чем разница.

Re: Обработать клик по элементу чертежа

Кстати, система координат у тебя установлена WCS? И вид в плане? Если нет, то нужно преобразаовывать координаты.

Re: Обработать клик по элементу чертежа

> Александр Ривилис
Александр, я все же нашел отличие, код работает.

(изменено: DIVON DIVON, 30 сентября 2009г. 20:36:59)

Re: Обработать клик по элементу чертежа

Я бы ещё добавил сюда проверку на класс объекта

if (entity->isKindOf(ВашКласс::desc())){

}