Тема: LISP.Поля (Field). Удаление, Добавление, Изменение

Мои соображения по поводу вставки, изменения и добавления полей в уже существующем тексте.
Для начала полезные ссылки:
Поля в таблице
LISP. Вставка в таблицу поля, соотвествующего площади примитива
Можно ли программно вставить поле?
Цитата из последный ссылки Александр Ривилис (2005-08-16 20:59:07)

Но тут не все так просто, как хотелось бы. При создании примитива все работает, а вот при его изменении — нет.

При изменении текста тоже работает. Правда пост датирован 2005 годом, может уже все все знают :), но тем не менее парочку функций и команд.
Ф-ции не претендуют на окончательный вариант, все изложенное здесь лишь иллюстрация по работе с полями из лиспа.

;Возвращает T если в объекте есть поле
;;; obj - VLA-объект
(defun isFieldAvailable ( obj  / fc )
  (and
    (vlax-method-applicable-p obj 'FieldCode) ;_есть метод FieldCode
    (setq fc (vlax-invoke obj 'FieldCode))
    (vl-string-search "%<\\Ac" fc)
    (vl-string-search ">%" fc)
   )
)
;_Удаляет все поля из объекта
;;; obj - VLA-объект
;_Возвращает текстовую строку с удаленным описание поля или строку если поля нет или "" если поля нет
;_обновлять в объекте (vlax-put obj 'TextString newstr)
(defun removeAllFieldFromObject ( obj  / fc fb fe fb1 tmp )
  (and
    (vlax-method-applicable-p obj 'FieldCode) ;_есть метод FieldCode
    (setq fc (vlax-invoke obj 'FieldCode))
    (while (and
             (setq fb (vl-string-search "%<\\Ac" fc))
             (if (null (setq fb1 (vl-string-search "%<\\Ac" fc (1+ fb))))
               (setq fb1 (strlen fc)) T)
             (setq fe fb)
             (while (and
                      (setq tmp (vl-string-search ">%" fc (1+ fe)))
                      (< tmp fb1)
                      )
               (setq fe tmp)
               )
             (if (= fb 1)
               (setq fc (substr fc (+ 4 fe)))
               (setq fc (strcat (substr fc 1 fb)(substr fc (+ 4 fe))))
               )
             )
      )
    )
  (if fc fc "")
  )
;_Удаляет поле  из объекта по указанной маске
;;; obj - VLA-объект
;;FieldPattern - маска поля (начало описания поля, см. в редакторе)
;; !! Обращайте внимание, что одиночная \ заменяется двойной \\
;;Например поле свойств - %<\\AcObjProp
;переменные -  %<\\AcVar и т.д.
;_Возвращает текстовую строку с удаленным описанием
;_обновлять в объекте (vlax-put obj 'TextString newstr)
(defun removeSpecifyFieldFromObject ( obj FieldPattern  / fc fb fe fb1 tmp )
  (and
    (vlax-method-applicable-p obj 'FieldCode) ;_есть метод FieldCode
    (setq fc (vlax-invoke obj 'FieldCode))
    (while (and
             (setq fb (vl-string-search FieldPattern fc))
             (if (null (setq fb1 (vl-string-search FieldPattern fc (1+ fb))))
               (setq fb1 (strlen fc)) T)
             (setq fe fb)
             (while (and
                      (setq tmp (vl-string-search ">%" fc (1+ fe)))
                      (< tmp fb1)
                      )
               (setq fe tmp)
               )
             (if (= fb 1)
               (setq fc (substr fc (+ 4 fe)))
               (setq fc (strcat (substr fc 1 fb)(substr fc (+ 4 fe))))
               )
             )
      )
    )
  (if fc fc "")
  )
;;Ф-ция добавляет к объекту поле
;; obj - VLA-объект
;; FieldStr - сформированная строка поля (такая же, какая отражается в окне редактора
;;Никаких проверок на корректность строки и присутствия оной в строке FieldStr не производится
;; !! Обращайте внимание, что одиночная \ заменяется двойной \\
;;Возвращает T - поле добавлено nil - нет
(defun addFieldToObj (obj FieldStr / fc)
  (and
    (vlax-write-enabled-p obj)
    (vlax-method-applicable-p obj 'FieldCode) ;_есть метод FieldCode
    (vlax-property-available-p obj 'TextString)
    (setq fc (vlax-invoke obj 'FieldCode))
    (setq fc (strcat fc " " FieldStr))
    (vlax-put obj 'TextString fc)
    )
  )
;;====== Примеры испольвания ф-ций и просто полезные команды
;_Пример использования ф-ции removeAllFieldFromObject
;_удалить все поля из текста
(defun C:DEMO1 ( )
  (if (and (setq obj (car(entsel "\nУкажи текст для удаления полей: ")))
           (wcmatch (cdr(assoc 0 (entget obj))) "*TEXT")
           (setq obj (vlax-ename->vla-object obj))
           (vlax-write-enabled-p obj)
           )
    (vla-put-TextString obj (removeAllFieldFromObject obj))
    )
  (princ)
  )
;_Пример использования ф-ции removeSpecifyFieldFromObject
;_удалить определенное поле из текста
(defun C:DEMO2 ( )
  (if (and (setq obj (car(entsel "\nУкажи текст для удаления полей %<\\AcVar: ")))
           (wcmatch (cdr(assoc 0 (entget obj))) "*TEXT")
           (setq obj (vlax-ename->vla-object obj))
           (vlax-write-enabled-p obj)
           )
    (vla-put-TextString obj (removeSpecifyFieldFromObject obj "%<\\AcVar"))
    )
  (princ)
  )
;;Пример использования ф-ции addFieldToObj
;добавление поля даты
;;Проверка, естьли уже в поле дата не производиться
(defun C:DEMO3 ( )
  (if (and (setq obj (car(entsel "\nУкажи текст для втавки даты: ")))
           (wcmatch (cdr(assoc 0 (entget obj))) "*TEXT")
           (setq obj (vlax-ename->vla-object obj))
           (vlax-write-enabled-p obj)
           )
    (addFieldToObj obj "%<\\AcVar Date \\f \"yyyy-MM-dd\">%")
    )
  (princ)
  )
;_Пример команда меняет точность представления чисел в полях
;_Например поле длины с установленной точностью N на новую
(defun c:DEMO4 ( / oldpre newpre obj fc newstr)
(princ "\nМеняет точность представления чисел в полях")
(initget 1)
(setq newpre (getint "\nНовая точность: "))
(if (and
      (setq obj (car (entsel "\nУкажите текст, содержаций поле : ")))
      (setq obj (vlax-ename->vla-object obj))
      (vlax-method-applicable-p obj 'FieldCode)
      (vlax-write-enabled-p obj)
      )
  (progn
    (setq fc (vlax-invoke obj 'FieldCode)) ;_Получаем текст + поле
    (if (and
          (setq oldpre (vl-string-search "%pr" fc))
          (vl-string-search "%" fc (1+ oldpre))
          )
      (progn
        (setq oldpre
               (substr fc (1+ oldpre)
                 (- (vl-string-search "%" fc (1+ oldpre))
                    (1- oldpre))
                       )
              )
        (setq newstr (vl-string-subst
                       (strcat "%pr" (itoa newpre) "%")
                       oldpre
                       fc)
              )
        (vlax-put obj 'TextString newstr)
        )
      )
    (princ)
    )
  )
  (princ)
  )
;если нужно просто напечатать в командной строке AutoCAD ID примитива,
;то можно воспользоваться и такой командой:
(defun C:EID ( / )
 (vl-load-com)
 (vla-get-objectid (vlax-ename->vla-object (car (entsel))))
)
;так - чтобы сразу печатался полный текст поля для длины
(defun C:PFLD ( / en)
  (if (setq en (car (entsel))) (progn
    (princ (strcat "\n"
      "%<\\AcObjProp Object(%<\\_ObjId "
      (vl-princ-to-string (vla-get-objectid (vlax-ename->vla-object en)))
      ">%).Length>%"
    ))
  )) ;_endof if progn
  (princ)
) ;_endof defun

Re: LISP.Поля (Field). Удаление, Добавление, Изменение

> VVA
Речь шла об обновлении поля после изменения источника. В lisp'е требовалась регенерация чертежа. В ObjectARX есть специальная функция позволяющая обновить значение поля/полей. В более поздних версиях AutoCAD не проверял.

(изменено: Владимир Азарко, 3 апреля 2009г. 15:12:14)

Re: LISP.Поля (Field). Удаление, Добавление, Изменение

Еще один пример: замена ID владельца свойства в существующем поле

;;;Использование:
;;;Рисуем 2 отрезка разной длины А и B
;;;Создаем текст с полем на длину отрезка A
;;;Запускаем DEMO5
;;;В запросе "Select old object" указываем отрезок A
;;;В запросе "Select new object:" указываем отрезок B
;;;В запросе "Select text:" указываем текст с полем
;;;Смотрим результат
(defun C:DEMO5 ()
  (vl-load-com)
  (and
   (setq oldobjID (car(entsel "\nSelect old object:")))
   (setq newobjID (car(entsel "\nSelect new object:")))
   (setq txt (car(nentsel "\nSelect text:")))
   (change_owner_in_field oldobjID newobjID txt)
 )
)

(defun change_owner_in_field ;_Ф-ция заменяет владельца в поле
                             (oldobjID ;_ Старый владелец ENAME
                              newobjID ;_ Новый владелец   ENAME
                              txt ;_ Хранитель поля (текст или атрибут) ENAME,
                                  ;_ возвращаемое nentsel
                              /           dict ;_ Словарь хранителя поля
                              field ;_ Словарь самого поля
                              field_data ;_ Значение поля (entget field)
                              New_field_data ;_Новый список для entmod
                              property ;_ Название свойства объекта в поле
                             )
;_ Ф-ция заменяет владельца в поле
;_ Аргументы
;_   oldobjID - имя примитива старого владельца ID [ENAME]
;_   newobjID - имя примитива нового владельца ID [ENAME]
;_ Return
;_ T - поле обновлено
;_ nil -нет
;;;!!! Важно: новый владелец должен обладать свойством, используемым в поле

  (and
  (setq dict (cdr (assoc 360 (entget txt)))) ;_Ename Dictionary Словарь примитива
  (setq dict
         (cdr (assoc 360 (member '(3 . "ACAD_FIELD") (entget dict))))
  ) ;_Enable Field Dictionary Есть поля в объекте
  (setq field (cdr (assoc 360 (member '(3 . "TEXT") (entget dict))))) ;_ Field Record Запись поля
  ;_Sub Field Records Вторичные записи полей
  (setq sub_field_list (mapcar 'cdr (vl-remove-if '(lambda(x)(/= (car x) 360))(entget field))))
    ;(setq field (cdr (assoc 360 (entget field)))) ;_Sub Field Record Вторичная запись поля
  (mapcar '(lambda(field_data)
  (setq field_data (entget field_data))
  (if (and (member (cons 330 oldobjID) field_data)
           (member (cons 331 oldobjID) field_data)
           (setq property
                  (vl-princ-to-string
                    (cdr (assoc
                           1
                           (member '(6 . "ObjectPropertyName") field_data)
                         ) ;_ end of assoc
                    ) ;_ end of cdr
                  ) ;_ end of VL-PRINC-TO-STRING
           ) ;_ end of setq
           (vlax-property-available-p
             (vlax-ename->vla-object newobjID)
             property
           ) ;_ end of vlax-property-available-p
      ) ;_ end of and
    (progn
      (setq New_field_data nil)
      (foreach itm field_data
        (cond
          ((and (= (car itm) 330)
                (equal (cdr itm) oldobjID)
           ) ;_ end of and
           (setq New_field_data
                  (append New_field_data
                          (list (cons 330 newobjID))
                  ) ;_ end of append
           ) ;_ end of setq
          )
          ((and (= (car itm) 331)
                (equal (cdr itm) oldobjID)
           ) ;_ end of and
           (setq New_field_data
                  (append New_field_data
                          (list (cons 331 newobjID))
                  ) ;_ end of append
           ) ;_ end of setq
          )
          (t (setq New_field_data (append New_field_data (list itm))))
        ) ;_ end of cond
      ) ;_ end of foreach
      (entmod New_field_data)
      (vl-cmdf "_updatefield" txt "")
      ;(while (> (getvar "CMDACTIVE") 0)(command ""))
      (entupd txt)
    ) ;_ end of progn
    nil
  ) ;_ end of if
             )
          sub_field_list
          )
  )
) ;_ end of defun

Ссылка на FldVizSel - Возвращает список примитивов, входящих в поле (поля)

Re: LISP.Поля (Field). Удаление, Добавление, Изменение

Такой вопрос: возможно ли получить для обработки список доступных ActiveX свойств примитива? Vlax-dump-object, я так понял, такой возможности не даёт. Для работы с Полями такая возможность была бы как раз к стати.

Re: LISP.Поля (Field). Удаление, Добавление, Изменение

Здравствуйте, попробовал использовать код

(defun C:PFLD ( / en)
  (if (setq en (car (entsel))) (progn
    (princ (strcat "\n"
      "%<\\AcObjProp Object(%<\\_ObjId "
      (vl-princ-to-string (vla-get-objectid (vlax-ename->vla-object en)))
      ">%).TextString>%"
    ))
  )) ;_endof if progn
  (princ)
) ;_endof defun

При указании блока пишет вместо %<\AcObjProp Object(%<\_ObjId 8796087808384>%).TextString>%
                                %<\AcObjProp Object(%<\_ObjId 42>%).TextString>%

В чём может быть причина?

Re: LISP.Поля (Field). Удаление, Добавление, Изменение

Лев, Разрядность и версия Автокада? (32 или 64)

Re: LISP.Поля (Field). Удаление, Добавление, Изменение

Пример получения строки поля (опубликовано http://forum.dwg.ru/showthread.php?p=15 … st1544329)

(vl-load-com)
(defun C:DEMO6 ()
  (setq en (car(nentsel "\nВыберите атрибут ")))
  (princ "\nСтрока поля: ")
  (princ(bg:FieldCode en))(princ)
  )
(defun bg:FieldCode (ent / foo elst xdict dict field str)
  ;; credits gile gc:FieldCode
  (defun ObjIdxStr (fld / pos)
  (setq pos (vl-string-search "ObjIdx " (cdr (assoc 2 fldId)) 0))
  (substr fld (1+ pos) (- (vl-string-search ">%" fld pos) pos))
  )
  (defun foo (field str / pos fldID objID)
    (setq pos 0)
    (if (setq pos (vl-string-search "\\_FldIdx " str pos))
      (while (setq pos (vl-string-search "\\_FldIdx " str pos))
        (setq fldId (entget (cdr (assoc 360 field)))
              field (vl-remove (assoc 360 field) field))
        (setq
              str   (strcat
                      (substr str 1 pos)
                      (if (setq objID (cdr (assoc 331 fldId)))
                        (vl-string-subst
                          ;;; (strcat "ObjId " (itoa (gc:EnameToObjectId objID))) ;;; VVA 2015-12-07
                          (strcat "ObjId " (bg:GetObjectIDString objID))
                          ;;; "ObjIdx" ;;; rem VVA 2015-12-07
                          (ObjIdxStr (cdr (assoc 2 fldId))) ;;; add VVA 2015-12-07
                          (cdr (assoc 2 fldId))
                        )
                        (foo fldId (cdr (assoc 2 fldId)))
                      )
                      (substr str (1+ (vl-string-search ">%" str pos)))
                    )
        )
      )
      str
    )
  )
  
  (setq elst (entget ent))
  (if (vlax-property-available-p (vlax-ename->vla-object ent) 'Textstring)
    (cond ((= (cdr(assoc 0 elst)) "MULTILEADER")
           (setq str (cdr(assoc 304 elst)))
           )
          ((and ;;; MTEXT ATTRIB ADD VVA 2011-20-27
             (member (cdr(assoc 0 elst)) '("ATTRIB"))
             (member '(101 . "Embedded Object") elst)
             )
           (setq str (apply 'strcat (append (bg:massoc 3 elst)(bg:massoc 1 (member '(101 . "Embedded Object") elst)))))
           )
          
          ((member (cdr(assoc 0 elst)) '("TEXT" "MTEXT" "ATTRIB"))
           (setq str (apply 'strcat (append (bg:massoc 3 elst)(bg:massoc 1 elst))))
           )
          (t (setq str (vla-get-TextString (vlax-ename->vla-object ent))))
    )
    )
  (if (and
    (member (cdr (assoc 0 elst)) '("ATTRIB" "MTEXT" "TEXT" "MULTILEADER"))
    (setq xdict (cdr (assoc 360 elst)))
    (setq dict (dictsearch xdict "ACAD_FIELD"))
    (setq field (dictsearch (cdr (assoc -1 dict)) "TEXT"))
      )
    (setq str (foo field (cdr (assoc 2 field))))
  )
    str
)
(defun bg:GetObjectIDString ( obj / *util* )
  (if (eq (type obj) 'ENAME)
    (setq obj (vlax-ename->vla-object obj))
    )
  (setq *util* (vla-get-Utility (vla-get-ActiveDocument (vlax-get-acad-object))))
  (if  (vlax-method-applicable-p *util* 'GetObjectIdString)
    (vla-GetObjectIdString *util* obj :vlax-false)
    (itoa (vla-get-ObjectId obj))
  )
 )
(defun bg:massoc (key alist)(mapcar 'cdr (vl-remove-if-not (function (lambda (x) (= key (car x)))) alist)))

(изменено: Дмитрий Филиппов, 16 октября 2016г. 09:58:16)

Re: LISP.Поля (Field). Удаление, Добавление, Изменение

VVA,
Александр Ривилис,
Владимир Азарко,

Вы дали ссылку на lisp который позволяет найти ПРИМИТИВ на который ссылается поле , а можно ли сделать тоже самое, но чтобы при выборе ОБЪЕКТА с полем выделялся ОБЪЕКТ на который ссылается это поле.

В предложенной по ссылке программе выбирается только линия из которой берется длинна... а если в поле вставляется другое значение (например, расстояние, координата) или вообще берется значение из созданного пользователем атрибута блока.

Надеюсь удалось объяснить.... простыми словами нужно чтобы 1) lisp работал не только с примитивами но и с блоками, атрибутами и др. 2) в результате выделялся объект вне зависимости от того что или какое значение/параметр/свойство из него извлекали.


Отредактировано: РЕШЕНИЕ найдено - Field Objects. Найдено на сайте Lee Mac Programming. Работает как надо! http://www.lee-mac.com/fieldobjects.html