| Правила | Регистрация | Пользователи | Поиск | Сообщения за день | Все разделы прочитаны |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > LISP. Получение значения ID пользовательского атрибута динамического блока

LISP. Получение значения ID пользовательского атрибута динамического блока

Ответ
Поиск в этой теме
Непрочитано 22.07.2020, 15:17 #1
LISP. Получение значения ID пользовательского атрибута динамического блока
modest-bp
 
Регистрация: 15.04.2019
Сообщений: 58

Здравствуйте!
Подскажите, пожалуйста, каким образом получить значение ID атрибута у динамического блока.

Собственно, хочу сделать вот, что.
Сейчас при помощи
Код:
[Выделить все]
 
(setq obj (car (entsel))
... выбираю объект
далее при помощи функции (Get-ObjectID-x86-x64) от VVA
Код:
[Выделить все]
 
(setq ID (Get-ObjectID-x86-x64 obj)) 
... извлекаю ID выбранного объекта и отправляю его в переменную ID.

Вот вопрос в том, как при выборе вхождения динамического блока с пользовательским атрибутом, например, "ТИП", загнать ID этого атрибута в переменную, например, attrID? То есть чтобы одним кликом выбрать объект на чертеже, а извлечь при этом два индентификатора: ID объекта (вхождения блока) и ID нужного атрибута.

Изучил тему DwgRuLispLib: Получение указателей на атрибуты вхождения блока, но так и не понял, как мне склеить предложенные там решения с кодом своей команды. Откровенно говоря, вообще не разобрался, как там чего работает ((((

Спасибо за подсказку!
Просмотров: 8383
 
Непрочитано 22.07.2020, 15:48
#2
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


А зачем тебе ID, если уже указатель можешь получить?
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 22.07.2020, 17:40
1 | #3
kp+

идущий по граблям
 
Регистрация: 26.05.2005
Сообщений: 5,090


Цитата:
Сообщение от modest-bp Посмотреть сообщение
при выборе вхождения динамического блока с пользовательским атрибутом, например, "ТИП", загнать ID этого атрибута в переменную, например, attrID? То есть чтобы одним кликом выбрать объект на чертеже, а извлечь при этом два индентификатора: ID объекта (вхождения блока) и ID нужного атрибута
Тэг "нужного" атрибута заранее известен, или нужный атрибут определяется только визуально?
Если первое - то лучше _dwgru-block-get-attr-by-mask не придумаешь, а если второе - можно так:
Код:
[Выделить все]
 (setq at (car (nentsel "целься в атрибут:\n")))
(if (= (vla-get-ObjectName (vlax-ename->vla-object at)) "AcDbAttribute")
  (setq block_owner (cdaddr (entget at)))
  (princ "промах")
)
Сделано по-колхозному, но работает. Нагло эксплуатируется тот факт, что в DXF-описании атрибута в составе блока третья пара - указатель на экземпляр блока-"владельца".
Вторая строчка проверяет, что выбран именно атрибут, а не графический примитив блока, например.
Дальше можно получить "эффективное имя" дин. блока, перевести указатель в удобоваримую форму, ... соль, перец по вкусу

Последний раз редактировалось kp+, 22.07.2020 в 17:54.
kp+ вне форума  
 
Автор темы   Непрочитано 22.07.2020, 17:56
#4
modest-bp


 
Регистрация: 15.04.2019
Сообщений: 58


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
А зачем тебе ID, если уже указатель можешь получить?
Так потом я эти ID (объекта и атрибута) буду использовать при создании полей. А именно, применяя функцию от VVA copyToclipboard, сразу отправлю в буфер обмена поля с нужными мне значениями в нужном формате, чтобы потом просто Ctrl-V в таблицах, тексте или где только это может потребоваться.

Вот такого плана:
%<\AcObjProp.16.2 Object(%<\_ObjId [<ЗДЕСЬ ID ОБЪЕКТА>]>%).Parameter(56).UpdatedDistance \f "%lu2%ds44%zs8">%
%<\AcObjProp Object(%<\_ObjId [<ЗДЕСЬ ID АТРИБУТА>]>%).TextString>%


Грубо говоря, хочу тыком по объекту получать в буфере обмена строку с полями, которую потом просто вставлять куда может потребоваться. А для этого нужны как раз значения ID объекта и ID атрибута. И, если я правильно понимаю, в виде текста.

----- добавлено через ~14 мин. -----
Цитата:
Сообщение от kp+ Посмотреть сообщение
Тэг "нужного" атрибута заранее известен, или нужный атрибут определяется только визуально?
Тэг известен. А вот визуально он не определяется, поскольку он скрыт. Надо было сразу сказать, что он невидимый, да? Не догадался...


Цитата:
Сообщение от kp+ Посмотреть сообщение
Если первое - то лучше _dwgru-block-get-attr-by-mask
Так в том-то и дело, что не понимаю я, как увязать переменную obj, которую задаю через (setq obj (car (entsel)), с переменной block-ref, которая обрабатывается функцией _dwgru-block-get-attr-by-mask

Простите, я, наверное, очень непонятно объясняю, потому как неграмотно... Но, надеюсь, смысл донести, всё-таки, получилось)))
Проще говоря, я не понимаю, как склеить в рамках одной команды с одним только тыком по объекту две функции: извлечение ID объекта через Get-ObjectID-x86-x64 и извлечение ID скрытого атрибута с заранее известным тэгом через _dwgru-block-get-attr-by-mask.
Понимание того, как далее использовать эти две переменные чтобы составить поля и отправить их при помощи copyToclipboard в буфер обмена у меня, вроде как, уже есть. По крайней мере, поля с ID объекта уже сформировал. Остались только поля с ID скрытого атрибута.
modest-bp вне форума  
 
Непрочитано 22.07.2020, 19:34
#5
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


(copyToclipboard (get-objectid-x86-x64 (car (_dwgru-block-get-attr-by-mask (car (entsel)) "RequiredTag"))))
Примерно так. Без проверок.
P.S. Мог бы и сам сообразить, как соединять функции
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 23.07.2020, 02:15
#6
modest-bp


 
Регистрация: 15.04.2019
Сообщений: 58


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
(copyToclipboard (get-objectid-x86-x64 (car (_dwgru-block-get-attr-by-mask (car (entsel)) "RequiredTag"))))
Примерно так. Без проверок.
Спасибо большое за ответ!
Да только вот проверить работу кода не получается, т.к. в теме DwgRuLispLib: Получение указателей на атрибуты вхождения блока ссылка на функцию _dwgru-is-ent-block-reference оказалась битая ((((
То есть собрать _dwgru-block-get-attr-by-mask целиком не выйдет (((

Тем не менее, в надежде, что функцию _dwgru-is-ent-block-reference удастся таки найти, я покорпел над кодом (ну на сколько хватило интуиции) с учётом подсказки Алексея Кулика aka kpblc, и вот, что сейчас получается. Но, боюсь, я всё-таки накосячил с применением _dwgru-block-get-attr-by-mask при присвоении значения переменной attrID.
Код:
[Выделить все]
 (defun C:getIDs ( / obj objID attrID)
	(setq obj (car (entsel "\nУкажите объект:")))
	(if obj
		(progn
			(setq objID (Get-ObjectID-x86-x64 obj))
			(setq attrID (_dwgru-block-get-attr-by-mask obj "ТЭГ_АТРИБУТА"))
			(if objID
				(if attrID
					(princ (strcat "\nзначение objID \"" objID "\"" "\nзначение attrID \"" attrID "\""))
					(princ (strcat "\nзначение objID \"" objID "\", \nattrID НЕ ИЗВЛЕЧЁН!!!"))
				)
				(if attrID
					(princ (strcat "\nзначение objID НЕ ИЗВЛЕЧЕНО!!!" "\nзначение attrID \"" attrID "\""))
					(princ "значения objID и attrID НЕ ИЗВЛЕЧЕНЫ!!!")
				)
			)
		(princ)
		) ;end of If Obj Progn true
		(princ "\nОбъект не выбран.") ; If Obj false
	) ; end of if obj
)
(vl-load-com)
(defun Get-ObjectID-x86-x64 (obj / util)
	(setq util (vla-get-Utility (vla-get-activedocument (vlax-get-acad-object))))
	(if (= (type obj) 'ENAME)(setq obj (vlax-ename->vla-object obj)))
	(if (= (type obj) 'VLA-OBJECT)
		(if (> (vl-string-search "x64" (getvar "platform")) 0)
			(vlax-invoke-method util "GetObjectIdString" obj :vlax-False)
			(rtos (vla-get-objectid obj) 2 0)
		)
	)
)
(defun _dwgru-block-get-attr-by-mask (block-ref mask / res)
  (if (not mask)
    (setq mask "*")
    ) ;_ end of if
  (if (_dwgru-is-ent-block-reference block-ref)
    (vl-remove-if-not
      '(lambda (x)
         (or x
             (wcmatch (strcase (vla-get-tagstring x)) (strcase mask))
             ) ;_ end of or
         ) ;_ end of lambda
      (apply 'append
             (mapcar '_dwgru-conv-value-to-list
                     (list
                       (vla-getattributes
                         (setq block-ref (_dwgru-conv-ent-to-vla block-ref))
                         ) ;_ end of vla-GetAttributes
                       (vla-getconstantattributes block-ref)
                       ) ;_ end of append
                     ) ;_ end of mapcar
             ) ;_ end of apply
      ) ;_ end of vl-remove
    ) ;_ end of if
  ) ;_ end of defun
Ну и в конце остаётся вклеить функции:
_dwgru-conv-ent-to-vla
_dwgru-conv-value-to-list
_dwgru-is-ent-block-reference (подскажите, где её найти?)

И ещё, Алексей, такой вопрос. Судя по всему, переменные block-ref и mask используются далее в трёх следующих функциях _dwgru-conv-<...>, поэтому они и объявлены как глобальные, я правильно понял? Насколько это критично, что они забивают собой память после отработки всех процедур? Может, их можно как-то выгрузить после выполнения команды getIDs? Или "обернуть" всё это ещё одной функцией, в которой обозначить эти переменные как локальные (но тогда теряюсь, как же её вызывать)?

Последний раз редактировалось modest-bp, 23.07.2020 в 02:30.
modest-bp вне форума  
 
Непрочитано 23.07.2020, 16:31
1 | #7
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


Нет, неправильно. Это просто параметры вызова.
По поводу битой ссылки - я не понял, как такое произошло. ПРимерный код:
Код:
[Выделить все]
 (defun _dwgru-is-ent-block-reference (ent)
                                     ;|
*    Функция возвращает, является ли переданный указатель на примитив вхождением
* (а не описанием) блока
*    Параметры вызова:
  ent : vla- или ename-указатель на проверяемый примитив
*    Примеры вызова:
(_dwgru-is-ent-block-reference (car (entsel)))
|;
  (and (setq ent (_dwgru-conv-ent-to-vla ent))
       (= (vla-get-objectname ent) "AcDbBlockReference")
       (not (vlax-property-available-p ent 'path))
       ) ;_ end of and
  ) ;_ end of defun
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Автор темы   Непрочитано 23.07.2020, 17:07
#8
modest-bp


 
Регистрация: 15.04.2019
Сообщений: 58


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
Нет, неправильно. Это просто параметры вызова.
в смысле, вместо block-ref надо подставить переменную obj, а вместо mask - тэг атрибута, верно? А res - это что?
modest-bp вне форума  
 
Непрочитано 23.07.2020, 17:49
#9
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


modest-bp, ты про какие функции говоришь?
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 23.07.2020, 20:53
#10
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,003


Цитата:
Сообщение от modest-bp Посмотреть сообщение
Судя по всему, переменные block-ref и mask используются далее в трёх следующих функциях _dwgru-conv-<...>, поэтому они и объявлены как глобальные, я правильно понял?
все в кучу - локальные переменные, аргументы функции, глобальные переменные.
Сергей812 вне форума  
 
Автор темы   Непрочитано 23.07.2020, 22:19
#11
modest-bp


 
Регистрация: 15.04.2019
Сообщений: 58


Оффтоп.
Цитата:
Сообщение от Сергей812 Посмотреть сообщение
все в кучу - локальные переменные, аргументы функции, глобальные переменные.
Вот блин. Ну никому нельзя верить.
Вот тут пишут, цитирую:
Цитата:
defun c:line10 (/ pt)
(...)
Последним элементом в первой строке является выражение (/pt). pt - это переменная (от слова point). Так как перед именем переменной стоит слеш (прямая косая черта), то это локальная переменная. Она хранит какое-то значение, которое используется только в данной процедуре. Чтобы эта переменная была доступной и в других процедурах, надо сделать ее глобальной. Для этого нужно записать ее определение без слеша - (pt) .
То есть, как бы, делаю вывод, что у (defun func1 (xxx)) этот самый "ххх" - это глобальная переменная.
А в документации пишут, что в этом случае "ххх" будет уже аргументом.
И вот сейчас, почитав документацию и ещё раз перечитав следующую лекцию по первой ссылке, понимаю, что это - действительно аргумент, а ни фига не глобальная переменная.
То есть, выходит, до слеша - аргумент, после - локальная переменная, а вне функции - глобальная переменная.
Но тогда что ж за муть написана по ссылке, цитату из которой я привёл?
Но это оффтоп и отчаянье. Два дня уже из этих учебников не вылезаю из-за одной единственной кнопочки, которую я загорелся сделать, и пока без толку ((((

Последний раз редактировалось modest-bp, 24.07.2020 в 01:06.
modest-bp вне форума  
 
Непрочитано 23.07.2020, 22:46
#12
skkkk


 
Регистрация: 20.03.2008
Сообщений: 2,653


Цитата:
Сообщение от modest-bp Посмотреть сообщение
То есть, выходит, до слеша - аргумент, после - локальная переменная, а вне функции - глобальная переменная.
Проходили ж недавно.
Цитата:
Сообщение от skkkk Посмотреть сообщение
Код:
[Выделить все]
(defun C:ID2CLP ( / obj ID) ;;; объявляем новую команду автокад. 
	 ;;; Аргументов (до слэша) нет, а после слэша - объявление локальных переменных obj и ID .
	 ;;; Если переменные, задаваемые в коде функцией setq не сделать локальными, 
	 ;;; то они после завершения функции станут глобальными переменными Автокада и будут жить до конца сеанса, забивая память. 
	 ;;; Поскольку в данном случае этого не нужно, делаем их локальными - перечисляем после слэша.
....................................................
Цитата:
Сообщение от skkkk Посмотреть сообщение
Код:
[Выделить все]
(if obj ;;; если объект выбран, 
	        (setq ID (Get-ObjectID-x86-x64 obj)) ;;; то вызываем функцию определения его ID, аргумент - выбранный объект (obj)
............................................................
(defun Get-ObjectID-x86-x64 (obj / util)
............................................................
Наверное, корявенько я все-таки объяснил...
skkkk вне форума  
 
Непрочитано 23.07.2020, 23:05
#13
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,003


Цитата:
Сообщение от modest-bp Посмотреть сообщение
А в документации пишут, что в этом случае "ххх" будет уже аргументом.
правильно пишут - иначе как разделять глобальные переменные и аргументы функции. И вообще не стоит злоупотреблять глобальными переменными, тем более в лиспе - где вообще нет никакого механизма разделения видимостей переменных, и все держится на искусственно придуманной конкретным программистом (группой программистов) системе имен.

а глобальная переменная - это когда она (переменная) объявлена вне функции: либо в явном виде
Код:
[Выделить все]
 (setq *GlobalVars* 1000)
либо в неявном виде - когда появляется присваивание ей внутри тела функции какого то значения - но при этом она не заявлена как локальная после слеша в заголовке этой функции. Что кто-то написал это через одно место
Цитата:
Сообщение от modest-bp Посмотреть сообщение
надо сделать ее глобальной. Для этого нужно записать ее определение без слеша - (pt) .
это проблема не лиспа уже)
Сергей812 вне форума  
 
Автор темы   Непрочитано 24.07.2020, 01:04
#14
modest-bp


 
Регистрация: 15.04.2019
Сообщений: 58


Цитата:
Сообщение от skkkk Посмотреть сообщение
Проходили ж недавно.
(...)
Наверное, корявенько я все-таки объяснил...
Ненене))) Спасибо))) Корявенько в учебнике написали))) А то цитату-то я привёл, а ссылкой подкрепить забыл.

Но с объявлением функций при сращивании нескольких у меня всё ещё есть проблемы. Сейчас доковыряю - выложу (если не заработает). А и если заработает - тоже выложу!)

----- добавлено через ~43 мин. -----
Собрал пока команду для извлечения из вхождения дин. блока ID пользовательского атрибута (скрытого) с тэгом "ТИП"
Судя по тому, что в результате обработки получаю
Цитата:
#<VLA-OBJECT IAcadAttributeReference 000000005c747528>
... это явно не то, что задумывалось. Значит, я что-то не так собрал.

Код сейчас выглядит так:
Код:
[Выделить все]
 (defun C:getAttrID (/ obj)
	(setq obj (car (entsel "Укажите объект: ")))
	(_dwgru-block-get-attr-by-mask obj "ТИП")
)

(defun _dwgru-block-get-attr-by-mask (block-ref mask / res)
	(if (not mask)
		(setq mask "*")
	) ;_ end of if
	(if (_dwgru-is-ent-block-reference obj)
		(vl-remove-if-not
			'(lambda (x)
			(or x
			(wcmatch (strcase (vla-get-tagstring x)) (strcase mask))
			) ;_ end of or
			) ;_ end of lambda
			(apply 'append
				(mapcar '_dwgru-conv-value-vla-to-list ; ВОТ ЗДЕСЬ БЫЛО ОБРАЩЕНИЕ К _dwgru-conv-value-to-list (РЕШИЛ, ЧТО ОПЕРЧАТКА, ИСПРАВИЛ...)
					(list
						(vla-getattributes
						
							;; ВОТ ЗДЕСЬ ПРИСВАИВАЕТСЯ ЗНАЧЕНИЕ BLOCK-REF, и аргумент у вызываемой функции тот же. А как же переменная obj, которую задали ткнув на объект?
							
							(setq block-ref (_dwgru-conv-ent-to-vla block-ref)) 
						) ;_ end of vla-GetAttributes
						(vla-getconstantattributes block-ref) ; и снова обращение к block-ref...
					) ;_ end of append
				) ;_ end of mapcar
			) ;_ end of apply
		) ;_ end of vl-remove
	) ;_ end of if
) ;_ end of defun


 (defun _dwgru-is-ent-block-reference (ent)
                                     ;|
*    Функция возвращает, является ли переданный указатель на примитив вхождением
* (а не описанием) блока
*    Параметры вызова:
  ent : vla- или ename-указатель на проверяемый примитив
*    Примеры вызова:
(_dwgru-is-ent-block-reference (car (entsel)))
|;
  (and (setq ent (_dwgru-conv-ent-to-vla ent))
       (= (vla-get-objectname ent) "AcDbBlockReference")
       (not (vlax-property-available-p ent 'path))
       ) ;_ end of and
  ) ;_ end of defun


(defun _dwgru-conv-ent-to-vla (ent)
	(cond
		((= (type ent) 'vla-object) ent)
		((= (type ent) 'ename) (vlax-ename->vla-object ent))
		((= (type ent) 'str)
			(if (setq ent (handent ent))
				(vlax-ename->vla-object ent)
			) ;_ end of if
		)
		(t nil)
	) ;_ end of cond
) ;_ end of defun




(defun _dwgru-conv-value-vla-to-list (value)
                                     ;|
*    Преобразование vlax-variant и vlax-safearray в обычный список.
*    Примеры вызова:
;; #1:
(setq point (vla-addpoint (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object))) (vlax-3d-point (getpoint))))
(_dwgru-conv-value-vla-to-list (vla-get-Coordinates point))	; '(1232.24 544.835 0.0)

;; #2:
(setq ent1 (vlax-ename->vla-object (entmakex '(list (0 . "LINE") (10 574.761 426.116 0.0) (11 1054.08 878.378 0.0))))
 ent2 (vlax-ename->vla-object (entmakex '((0 . "LINE") (10 967.833 561.795 0.0) (11 779.78 335.664 0.0)))))
(_dwgru-conv-value-vla-to-list (vla-IntersectWith ent1 ent2 acExtendNone))	; nil
(_dwgru-conv-value-vla-to-list (vla-IntersectWith ent1 ent2 acExtendBoth))	; '(1876.15 1654.04 0.0)
|;
  (cond
    ((= (type value) 'variant)
     (_dwgru-conv-value-vla-to-list (vlax-variant-value value))
     )
    ((= (type value) 'safearray)
     (if (>= (vlax-safearray-get-u-bound value 1) 0)
       (vlax-safearray->list value)
       ) ;_ end of if
     )
    (t value)
    ) ;_ end of cond
  ) ;_ end of defun

Внутри _dwgru-block-get-attr-by-mask было обращение к отсутствующей функции _dwgru-conv-value-to-list. Я решил, что это опечатка, поэтому заменил её на существующую _dwgru-conv-value-vla-to-list. Не знаю, прав ли был...
Но так и не понимаю, как мне срастить эти функции, потому как в них повсюду применяются переменные/аргументы block-ref, в то время как мне нужно повсюду брать значение переменной obj, заданной выбором объекта в самом начале (я же дальше планирую ещё одну функцию прикрутить - собирающую ObjID вхождения блока, а там, как раз, всюду именно эта obj используется).
Помогите, пожалуйста, задымил уже)))
modest-bp вне форума  
 
Непрочитано 24.07.2020, 07:52
#15
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 39,787


Offtop: Че-т я начинаю подумывать об организации общего репа на гитхабе на предмет подобных функций... Заодно поэкспериментировать и поучиться можно
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 24.07.2020, 08:00
#16
Boxa

КЖ; C#
 
Регистрация: 03.11.2005
Санкт-Петербург
Сообщений: 2,588


Кулик Алексей aka kpblc, давно пора...
Boxa вне форума  
 
Непрочитано 24.07.2020, 08:51
1 | 1 #17
koMon


 
Блог
 
Регистрация: 26.09.2017
Сообщений: 1,665


Цитата:
Сообщение от modest-bp Посмотреть сообщение
Помогите, пожалуйста
не надо заниматься ерундой по сращиванию костей / наращиванию ногтей)
Код:
[Выделить все]
 
(defun get_block_given_attribute_id ( / picking_entity picked_entity attribute_found block_found)
	(setq picking_entity t
		  attribute_tag "NAME"
	)
	(while picking_entity
		(setq picked_entity (vl-catch-all-apply 'entsel (list "Выберите блок: ")))
		(cond
			(
				(null picked_entity)
			)
			(
				(vl-catch-all-error-p picked_entity)
					(setq picking_entity nil)
			)
			(
				(and
					(= "INSERT" (cdr (assoc 0 (entget (car picked_entity)))))
					(setq block_found (vlax-ename->vla-object (car picked_entity)))
					(= :vlax-true (vla-get-hasattributes block_found))
					(vl-some '(lambda (each_attribute)
					  				(= attribute_tag (vla-get-tagstring (setq attribute_tested each_attribute)))
							  )
							  (vlax-safearray->list (vlax-variant-value (vla-getattributes block_found)))
					)
					(setq attribute_found attribute_tested)
				)
					(setq picking_entity nil)
			)
			(
				t
					(if block_found
						(setq picking_entity nil)
						(alert "Не блок")
					)
			)
		)
	)
	(if block_found
		(progn
			(princ "\nBlock ID: ")
			(princ (itoa (vla-get-objectid block_found)))
			(if attribute_found
				(progn
					(princ "\nAttribute ID: ")
					(princ (itoa (vla-get-objectid attribute_found)))
				)
				(progn
					(princ "\nВ блоке нет атрибута \"")
					(princ attribute_tag)
					(princ "\"")
				)
			)
		)
	)
	(princ)
)
функция (get_block_given_attribute_id) выведет в консоль id выбранного блока и id атрибута с тэгом "NAME", если таковой в блоке обнаружится. составлять, копировать в буфер, я думаю уже сможешь сам. хотя мне не понятно зачем копировать в буфер, если можно сразу тыкать в ячейку и заливать в неё данные, можно даже на курсор подвесить поля для наглядности.

Последний раз редактировалось koMon, 24.07.2020 в 16:34.
koMon вне форума  
 
Непрочитано 24.07.2020, 12:01
1 | 1 #18
skkkk


 
Регистрация: 20.03.2008
Сообщений: 2,653


Цитата:
Сообщение от modest-bp Посмотреть сообщение
Судя по тому, что в результате обработки получаю
Цитата:
#<VLA-OBJECT IAcadAttributeReference 000000005c747528>
... это явно не то, что задумывалось. Значит, я что-то не так собрал.
Если коротко и по-простому, в лиспе под автокад есть два подвида: AutoLISP (более старый, вроде классики) и VisualLISP (поновее, его функции начинаются с префиксов vla- и vlax-). В первом используются так называемые Entity name (то, что возвращает конструкция (car (entsel))), а во втором - vla-object (#<VLA-OBJECT IAcadAttributeReference). Для преобразования первого во второй используется функция (vlax-ename->vla-object en-obj), а для обратного - (vlax-vla-object->ename vla-obj).

В функции _dwgru-is-ent-block-reference, к примеру, в комментарии указано:
Цитата:
Сообщение от modest-bp Посмотреть сообщение
ent : vla- или ename-указатель на проверяемый примитив
то есть, в коде этой функции происходит проверка на тип указателя (vla или ename) и приведение его к нужному типу, поэтому в качестве аргумента можно использовать и то и другое. Аналогично с _dwgru-block-get-attr-by-mask, хоть в комментариях явно это и не указано. Но возвращает она как раз vla-object.


Цитата:
Сообщение от modest-bp Посмотреть сообщение
Код:
[Выделить все]
10-я строка кода   (if (_dwgru-is-ent-block-reference obj)
- тут не нужно было менять аргумент на obj. В описании функции [(defun _dwgru-block-get-attr-by-mask (block-ref mask /......] block-ref - аргумент, и он имеет для удобства понятное название (вхождение блока - block-reference), потому что в роли этого вхождения у нас выступает ранее полученная переменная obj. Иными словами, переменная полученная при помощи другой функции, не важно - пользовательской или встроенной лисповской (в нашем случае - [(car (entsel))]) - необязательно должна совпадать своим названием с аргументом той функции, которой она скармливается (функции второго уровня) - главное, чтоб у нее был нужный, подходящий тип (если нужен vla-объект, то он, если, например, строка - то она, если число, то оно)

Цитата:
Сообщение от modest-bp Посмотреть сообщение
; ВОТ ЗДЕСЬ БЫЛО ОБРАЩЕНИЕ К _dwgru-conv-value-to-list (РЕШИЛ, ЧТО ОПЕРЧАТКА, ИСПРАВИЛ...)
Это не опечатка. Слишком опытные люди писали эту библиотеку, и многие уже проверили ее в своих кодах тысячекратно. Это как раз и есть одна из тех функций для приведения к общему виду в целях работы программы). Но об этом пока рано - чтоб кашу в голове не заварить. Библиотечные функции для того и нужны, чтоб их использовать как есть, просто подставляя свои аргументы. И хорошо сделанные библиотечные функции помимо прочего обычно принимают в качестве аргумента и ename и vla, просто внутри кода преобразуются к чему-то одному, что более удобно по ходу выполнения кода. А библиотека _dwgru-lisp-lib - хорошо сделанная библиотека - можно не сомневаться.

В общем, код должен выглядеть как-то так:
Код:
[Выделить все]
  (defun C:getAttrID (/ obj attr_vla_obj)
	(setq obj (car (entsel "Укажите объект: ")))
	(if obj
		(setq attr_vla_obj (_dwgru-block-get-attr-by-mask obj "ТИП")) ;;; заносим в переменную vla-объект атрибута
	)
	(if attr_vla_obj
		(setq attrID (Get-ObjectID-x86-x64 attr_vla_obj)) ;;; функция Get-ObjectID-x86-x64 принимает как vla, так и ename
	)
)
Однако, нам нужно далее собирать строки в формулу поля, и в этих строках будут использоваться эти полученные ID, и тут нам удобнее уже делать не команду, а функцию второго уровня (свою библиотечную функцию) для использования в команде-оболочке (первого уровня):
Код:
[Выделить все]
 (defun getAttrID (obj tag / attr_vla_obj)
	; ; ; убираем запрос объекта из функции и выводим его аргумент - до слэша 
;;;(setq obj (car (entsel "Укажите объект: ")))
	;;; также для универсальности уберем в аргумены тэг атрибута 
	(if obj
		(setq attr_vla_obj (_dwgru-block-get-attr-by-mask obj tag)) ;;; заносим в переменную vla-объект атрибута с тэгом tag
	)
	(if attr_vla_obj
		(Get-ObjectID-x86-x64 attr_vla_obj)) ;;; функция Get-ObjectID-x86-x64 принимает как vla, так и ename
	) ;;; в итоге получим возвращаемое значение функции getAttrID, и не нужно лишний раз заносить его в переменную
	
)
Аналогично - с получением ID самого блока:
Код:
[Выделить все]
 (defun getobjID (obj / )
	(if obj
	    (Get-ObjectID-x86-x64 obj)
	) ;;; в итоге получим возвращаемое значение функции getobjID, и не нужно лишний раз заносить его в переменную
)
По сути, вышеприведенная функция является некой "вещью в себе" - я просто для наглядности изобразил, для большей понятности. С тем же успехом можно просто использовать
Код:
[Выделить все]
 (Get-ObjectID-x86-x64 obj)
Однако, в свою функцию можно добавить всяких нужных "плюшек", например, в виде посылок сообщений в комстроку.

Для таких своих библиотечных функций разумно делать свой собсвтенный префикс, например: modest_getobjID

А затем пишем оболочку:
Код:
[Выделить все]
 (defun C:getIDs ( / obj block_ID attr_ID field_code1 field_code2)
	(setq obj (car (entsel "Укажите объект: ")))
	(setq block_ID (getobjID obj))
	(setq attr_ID (getAttrID obj "ТИП"))
	;;; далее собираем коды полей из строк 
	; ; ; %<\AcObjProp.16.2 Object(%<\_ObjId [<ЗДЕСЬ ID ОБЪЕКТА>]>%).Parameter(56).UpdatedDistance \f "%lu2%ds44%zs8">%
	; ; ; %<\AcObjProp Object(%<\_ObjId [<ЗДЕСЬ ID АТРИБУТА>]>%).TextString>% 
	;;; !!! не забываем для дублировать обратный слэш и кавычки предварять обратным слэшем (он превращает управляющий символ в обычный),
	;;; поскольку в лиспе они являются значащими символами (про создание кодов полей в лиспе есть много информации на форуме)
        ;;; (!!!Строки не сформированы правильно до конца - пишу "насухую")
	(setq field_code1 (strcat "%<\\AcObjProp.16.2 Object(%<\\_ObjId" block_ID "........ и так далее"))
	(setq field_code2 (strcat "%<\\AcObjProp Object(%<\_ObjId" attr_ID "........ и так далее"))
	;;; а далее уже можно эти строки объединить с переносом строки (\n)
	(setq field_code (strcat field_code1 "\n" field_code2))
	;;; и добавлять в буфер обмена, например....
)
Ну и, конечно, надо обеспечить загрузку всех упомянутых в кодах библиотечных функций. Только лучше - пока без самодеятельности.
Если при выполнении кода появится сообщение об отсутствии в чертеже описания какой-то функции, вроде того
Код:
[Выделить все]
; no function definition: _DWGRU-PROPERTY-GET
то следует найти эту функцию в поиске и просто добавить в код.

Цитата:
Сообщение от modest-bp Посмотреть сообщение
Вот блин. Ну никому нельзя верить.
Цитата:
Сообщение от modest-bp Посмотреть сообщение
Корявенько в учебнике написали)))
А учиться лучше по нашей великолепнейшей "Азбуке" от Николая Полещука и Петра Лоскутова - "AutoLISP и Visual LISP в среде AutoCAD". Довольно старая Вещь, но актуальная до сих пор. И все еще есть на Озоне в формате pdf - и совсем недорого. Ну и тема "Научите лиспу на примере..." - тоже весьма полезна, хоть и довольно ёмкая по размеру.


Удачи в постижении

Цитата:
Сообщение от koMon Посмотреть сообщение
мне не понятно зачем копировать в буфер, если можно сразу тыкать в ячейку и заливать в неё данные, можно даже на курсор подвесить поля для наглядности.
Для начала это будет трудновато, на мой взгляд. Если не невозможно.
skkkk вне форума  
 
Автор темы   Непрочитано 26.07.2020, 12:21
#19
modest-bp


 
Регистрация: 15.04.2019
Сообщений: 58


Большое спасибо, koMon, skkkk!
Сегодня вечером засяду разбираться с вашими подсказками!

----- добавлено через ~5 ч. -----
Цитата:
Сообщение от skkkk Посмотреть сообщение
- тут не нужно было менять аргумент на obj. В описании функции [(defun _dwgru-block-get-attr-by-mask (block-ref mask /......] block-ref - аргумент, и он имеет для удобства понятное название (вхождение блока - block-reference), потому что в роли этого вхождения у нас выступает ранее полученная переменная obj. Иными словами, переменная полученная при помощи другой функции, не важно - пользовательской или встроенной лисповской (в нашем случае - [(car (entsel))]) - необязательно должна совпадать своим названием с аргументом той функции, которой она скармливается (функции второго уровня) - главное, чтоб у нее был нужный, подходящий тип (если нужен vla-объект, то он, если, например, строка - то она, если число, то оно)
Вот это я вообще никак не пойму. Несколько раз перечитал.
То есть загнали мы в "какую-то" переменную некие данные. Кроме этой переменной данные этого же типа могут лежать в любом количестве других переменных.
Далее нам надо эти данные именно из этой переменной использовать в работе какой-то процедуры, выполняющей какую-то функцию.
Каким образом эта функция узнаёт, из какой именно переменной ей брать данные, если я ей это не укажу?
Вот, следуя этой логике, я и указал в аргументе _dwgru-block-get-attr-by-mask, что речь идёт об объекте, указатель на который лежит в переменной obj (ну, судя по разъяснениям, вы догадались, чего я этим всем имел в виду).

Цитата:
переменная полученная при помощи другой функции, не важно - пользовательской или встроенной лисповской (в нашем случае - [(car (entsel))]) - необязательно должна совпадать своим названием с аргументом той функции, которой она скармливается
Вот как тогда она поймёт, что именно ей скармливается? Ведь данные этого типа могут лежать в самых разных переменных...

----- добавлено через ~5 ч. -----
Цитата:
Сообщение от skkkk Посмотреть сообщение
Однако, нам нужно далее собирать строки в формулу поля, и в этих строках будут использоваться эти полученные ID, и тут нам удобнее уже делать не команду, а функцию второго уровня (свою библиотечную функцию) для использования в команде-оболочке (первого уровня)
Если я вас правильно понял, то это - не то, что мне нужно в самой далёкой перспективе)
Дальняя перспекива - это получить два ID: самого объекта и пользовательского атрибута. С получением идентификатора объекта я уже разобрался. Сейчас у меня забота как раз про получение ID невидимого атрибута (в этом конкретном случае - с тэгом "ТИП").
А саааамый дальний предел - получать ещё и ссылки на параметры выбранного блока по их имени. Но это для меня сейчас настолько высокий пилотаж, что пока не разберусь с этими двумя задачами - туда и не сунусь.

Так вот. Именно по этой причине (т.е. с пристрелкой к дальнейшему объединению процедур, извлекающих два этих ID) я и сделал команду, которая всего лишь выбирает объект, после чего будет запускать функции, извлекающие идентификаторы из выбранного командой объекта. Ну а ниже по коду планирую просто дописать эти самые функции.
Поэтому, наверное, оборачивать командой все эти функции было бы не лучшим выбором (с точки зрения простоты последующего расширения функционала этой вызываемой команды).
Или я вас неправильно понял?

----- добавлено через ~6 ч. -----
Цитата:
Сообщение от koMon Посмотреть сообщение
не надо заниматься ерундой по сращиванию костей / наращиванию ногтей)
(...)
функция (get_block_given_attribute_id) выведет в консоль id выбранного блока и id атрибута с тэгом "NAME", если таковой в блоке обнаружится
Ю-хуууууууу!!! Спасибо!!!! Работаееееет!!!!


Цитата:
Сообщение от koMon Посмотреть сообщение
копировать в буфер, я думаю уже сможешь сам
Да, это сделал.
Вот, что в итоге получилось (на случай, если с такой же проблемой столкнётся ещё кто-то, кроме меня):
Код:
[Выделить все]
 (defun get_block_given_attribute_id ( / picking_entity picked_entity attribute_found block_found)
	(setq picking_entity t
		  attribute_tag "ТИП"
	)
	(while picking_entity
		(setq picked_entity (vl-catch-all-apply 'entsel (list "Выберите блок: ")))
		(cond
			(
				(null picked_entity)
			)
			(
				(vl-catch-all-error-p picked_entity)
					(setq picking_entity nil)
			)
			(
				(and
					(= "INSERT" (cdr (assoc 0 (entget (car picked_entity)))))
					(setq block_found (vlax-ename->vla-object (car picked_entity)))
					(= :vlax-true (vla-get-hasattributes block_found))
					(vl-some '(lambda (each_attribute)
					  				(= attribute_tag (vla-get-tagstring (setq attribute_tested each_attribute)))
							  )
							  (vlax-safearray->list (vlax-variant-value (vla-getattributes block_found)))
					)
					(setq attribute_found attribute_tested)
				)
					(setq picking_entity nil)
			)
			(
				t
					(if block_found
						(setq picking_entity nil)
						(alert "Не блок")
					)
			)
		)
	)
	(if block_found
		(progn
			(princ "\nBlock ID: ")
			(princ (itoa (vla-get-objectid block_found)))
			(if attribute_found
				(progn
					(princ "\nAttribute ID: ")
					(princ (itoa (vla-get-objectid attribute_found)))
				)
				(progn
					(princ "\nВ блоке нет атрибута \"")
					(princ attribute_tag)
					(princ "\"")
				)
			)
		)
	)
	(princ)
	(copyToclipboard (strcat "ID самого выбранного блока: " (itoa (vla-get-objectid block_found)) " и ID его атрибута c тэгом \"ТИП\": " (itoa (vla-get-objectid attribute_found))))
)
(defun copyToclipboard ( text / htmlfile result)
 (setq result
        (vlax-invoke
            (vlax-get
                (vlax-get
                    (setq htmlfile (vlax-create-object "htmlfile"))
                   'ParentWindow
                )
               'ClipBoardData
            )
           'SetData
            "Text"
            text
        )
    )

    (vlax-release-object htmlfile)
    result
)
В итоге в буфере обмена окажется строка:
Цитата:
ID самого выбранного блока: [<ID блока>] и ID его атрибута c тэгом "ТИП": [<ID атрибута>]
Далее, кому нужно, сможет самостоятельно изменить отправляемую в буфер строку под формирование полей в том виде, в каком им надо.

Цитата:
Сообщение от koMon Посмотреть сообщение
хотя мне не понятно зачем копировать в буфер, если можно сразу тыкать в ячейку и заливать в неё данные, можно даже на курсор подвесить поля для наглядности
Так мне нужно ровно это, и ничего более. Просто вовсе не обязательно поля, которые буду формировать в буфере обмена, будут в итоге загоняться именно в таблицу. Где-то - в ячейку таблицы буду их вставлять, где-то - в выноску или даже текст. В таком виде с этим добром работать проще: выделил объект - в буфер легла нужная уже строка - вставил из буфера именно туда, куда оно было нужно.

Спасибо огромное! Вы очень помогли!
Спасибо всем, кто проявил внимание к теме и помогал мне в поиске решения!


Далее примусь за новый уровень: попробую извлечь из блока ссылки на параметры (или как оно называется), которые будут определяться по имени параметра. Чтобы аналогичную процедуру можно было бы применять ко всем блокам, у которых есть параметры с нужным именем. И, похоже, не смогу обойтись без того, чтобы создать здесь новую тему

----- добавлено через ~12 ч. -----
Цитата:
Сообщение от koMon Посмотреть сообщение
функция (get_block_given_attribute_id)
koMon,
всё работает, но, не понимая, как оно работает, успокоиться не могу))))
Попробовал разобрать код, и вот, какие вопросы возникли (в комментариях написал):
Код:
[Выделить все]
 	(setq picking_entity t            ; зачем в этом месте было присваивать picking_entity значение true?
		  attribute_tag "ВЫСОТА"
	)
	(while picking_entity
		(setq picked_entity (vl-catch-all-apply 'entsel (list "Выберите блок: ")))   ; picked_entity присвоили значение по entsel, но каждый элемент списка сделали самостоятельным списком, так?
		(cond                                                                           ; при условии, что...
			(
				(null picked_entity)                                       ; picked_entity не пустая
			)
			(
				(vl-catch-all-error-p picked_entity)                 ; а на её содержимое vl-catch-all-apply не возвращает ошибку аргумента
					(setq picking_entity nil)                         ; в этом случае присвоить picking_entity nil (зачем? То есть в начале мы дали t, а в этом случае - записываем nil)
			)
			(
				(and
					(= "INSERT" (cdr (assoc 0 (entget (car picked_entity)))))                      ; а также picked_entity является блоком
					(setq block_found (vlax-ename->vla-object (car picked_entity)))           ; присваиваем block_found значение указателя picked_entity, конвертировав его из ename в vla-object
					(= :vlax-true (vla-get-hasattributes block_found))                                ; вот от сюда - и до закрытия and совсем не понял...
					(vl-some '(lambda (each_attribute)
					  				(= attribute_tag (vla-get-tagstring (setq attribute_tested each_attribute)))
							  )
							  (vlax-safearray->list (vlax-variant-value (vla-getattributes block_found)))
					)
					(setq attribute_found attribute_tested)
				)
					(setq picking_entity nil)
			)
			(
				t
					(if block_found
						(setq picking_entity nil)                           ; и снова не понимаю, как работает nil? Останавливает процедуру while picking_entity?
						(alert "Не блок")
					)
			)
		)
	)
modest-bp вне форума  
 
Непрочитано 27.07.2020, 17:40
1 | #20
skkkk


 
Регистрация: 20.03.2008
Сообщений: 2,653


Цитата:
Сообщение от modest-bp Посмотреть сообщение
Цитата:
Цитата:
переменная полученная при помощи другой функции, не важно - пользовательской или встроенной лисповской (в нашем случае - [(car (entsel))]) - необязательно должна совпадать своим названием с аргументом той функции, которой она скармливается
Вот как тогда она поймёт, что именно ей скармливается? Ведь данные этого типа могут лежать в самых разных переменных...
Так ведь мы же скармливаем конкретную переменную - подставляем ее на место аргумента. Возьмем тот же пример:
Код:
[Выделить все]
(defun _dwgru-block-get-attr-by-mask (block-ref mask / res).............
Тут в описании функции задан первый аргумент - block-ref. Но когда мы ее вызываем, то подставляем в качестве аргумента переменную, полученную ранее в коде:
Код:
[Выделить все]
(setq obj (car (entsel)))
(_dwgru-block-get-attr-by-mask obj "ТИП")
То есть, необязательно при подстановки переменной в качестве аргумента имя этой переменной должно совпадать с именем аргумента, которое указано в описании функции. Должен совпадать только тип переменной (в нашем случае - объект, причем обязательно - блок). И не нужно в используемой библиотечной функции менять ее имя с block-ref на obj. Вот что я имел в виду.
Цитата:
Сообщение от modest-bp Посмотреть сообщение
; зачем в этом месте было присваивать picking_entity значение true?
Вероятно, koMon не увидит этого дополнения, потому что оно не покажется, как новое сообщение в теме, поэтому отвечу вместо него. По логике этого кода данная переменная используется в качестве аргумента-условия для функции создания цикла (while). По-русски это значит, что пока ("while" так и переводится - "пока", "до тех пор, пока") переменная имеет значение (не nil), то всё, что внутри скобок функции while будет выполнятся циклически. Если в начале одного из следующих циклов этой переменной не будет присвоено значение, то цикл прервется, равно как и при назначении ей nil сознательно, например, в случае, если это не блок или поймалась какая-то ошибка.
skkkk вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > LISP. Получение значения ID пользовательского атрибута динамического блока

Размещение рекламы
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Значение атрибута в текстовое поле динамического блока zekatyumen Динамические блоки 19 28.01.2023 09:26
Как установить значения атрибутов динамического блока? Diam Finn .NET 3 14.01.2020 18:30
LISP. Помогите с лиспом по переименованию нескольких вхождений динамического блока в значение его атрибута. kirillwu LISP 43 09.07.2018 13:29
Изменение атрибута блока , который находится в блоке (из пространства модели) konservnii LISP 17 28.03.2017 15:22
Lisp. Как добраться до подсказки атрибута блока молодой человек LISP 8 25.11.2010 09:20