Про развитие и рефакторинг собственного кода
В очередной раз убедился, что даже сформированный на единственную задачу код может запросто потребовать развития.
На форуме dwg.ru в очередной раз потребовалось развить код. Реально, сначала думал записать ролик, но потом подумал, что и статья тоже сгодится.
Исходный код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | (defun t1 (/ str dim vla_dim err) (if (and (= (type (setq str (vl-catch-all-apply (function (lambda () (getstring t "\nEnter text : ")))))) 'str ) ;_ end of = (= (type (setq dim (vl-catch-all-apply (function (lambda () (car (entsel "\nSelect dim : "))))))) 'ename ) ;_ end of = (= (cdr (assoc 0 (entget dim))) "DIMENSION") ) ;_ end of and (if (vl-catch-all-error-p (setq err (vl-catch-all-apply (function (lambda () (setq vla_dim (vlax-ename->vla-object dim)) (vla-put-textoverride vla_dim (strcat (cond ((= (vla-get-textoverride vla_dim) "") "<>\\X" ) ((wcmatch (vla-get-textoverride vla_dim) "*\\X*") (strcat (vla-get-textoverride vla_dim) " ") ) (t (strcat (vla-get-textoverride vla_dim) "\\X")) ) ;_ end of cond str ) ;_ end of strcat ) ;_ end of vla-put-textoverride ) ;_ end of lambda ) ;_ end of function ) ;_ end of vl-catch-all-apply ) ;_ end of setq ) ;_ end of vl-catch-all-error-p (princ (strcat "\nError : " (vl-catch-all-error-message err))) ) ;_ end of if ) ;_ end of if (princ) ) ;_ end of defun |
Прежде всего - в коде как минимум 2 части: одна получает указатель на размер и добавляемый текст, вторая собственно меняет объект размера. Выношу вторую часть в отдельную функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | (defun _kpblc-ent-modify-dim-underlinetext (dim text / err vla_dim) ;| * Изменяет объект размера, помещая переданный текст под строку размера * Параметры вызова: dim ; ename-указатель на объект размера text ; устанавливаемый текст |; (if (vl-catch-all-error-p (setq err (vl-catch-all-apply (function (lambda () (setq vla_dim (vlax-ename->vla-object dim)) (vla-put-textoverride vla_dim (strcat (cond ((= (vla-get-textoverride vla_dim) "") "<>\\X" ) ((wcmatch (vla-get-textoverride vla_dim) "*\\X*" ) ;_ end of wcmatch (strcat (vla-get-textoverride vla_dim) " ") ) (t (strcat (vla-get-textoverride vla_dim) "\\X") ) ) ;_ end of cond text ) ;_ end of strcat ) ;_ end of vla-put-textoverride ) ;_ end of lambda ) ;_ end of function ) ;_ end of vl-catch-all-apply ) ;_ end of setq ) ;_ end of vl-catch-all-error-p (princ (strcat "\nError : " (vl-catch-all-error-message err)) ) ;_ end of princ ) ;_ end of if ) ;_ end of defun |
Результат так себе, поскольку будет работать только с ename-представлением размера. Но пока оставлю как есть. И общий код станет выглядеть уже по-другому (заодно переименуем функцию в команду):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | (defun c:dimunderline-ask (/ str dim vla_dim err) ;| * Добавляет под размерную линию введенный текст |; (if (and (= (type (setq str (vl-catch-all-apply (function (lambda () (getstring t "\nEnter text : "))) ) ;_ end of vl-catch-all-apply ) ;_ end of setq ) ;_ end of type 'str ) ;_ end of = (= (type (setq dim (vl-catch-all-apply (function (lambda () (car (entsel "\nSelect dim : "))) ) ;_ end of function ) ;_ end of vl-catch-all-apply ) ;_ end of setq ) ;_ end of type 'ename ) ;_ end of = (= (cdr (assoc 0 (entget dim))) "DIMENSION") ) ;_ end of and (_kpblc-ent-modify-dim-underlinetext dim str) ) ;_ end of if (princ) ) |
Вроде бы мало что изменилось, правда? А вот не совсем.
Попробую-ка решить задачку "запомнить введенный текст". Каким образом? Да элементарно - загнать его в какую-нибудь глобальную переменную. Системные переменные типа USERS* пользовать не хочу, так что сделаю собственный вариант:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | (and (= (type (setq str (vl-catch-all-apply (function (lambda (/ res) (setq res (getstring t (strcat "\nEnter text <" (if (and *kpblc-dimtext* (/= *kpblc-dimtext* "") ) ;_ end of and *kpblc-dimtext* "Cancel" ) ;_ end of if "> : " ) ;_ end of strcat ) ;_ end of getstring ) ;_ end of setq (cond ((/= res "") res) ((and (= res "") *kpblc-dimtext*) *kpblc-dimtext* ) (t nil) ) ;_ end of cond ) ;_ end of lambda ) ;_ end of function ) ;_ end of vl-catch-all-apply ) ;_ end of setq ) ;_ end of type 'str ) ;_ end of = (/= str "") ) ;_ end of and |
Так, стоп. Но это практически то же самое, что и в начальном варианте! Не, копипастингом заниматься не хочу. Лучше уж сделать отдельную функцию, которая будет возвращать текст либо основываясь на значении "по умолчанию", либо требуя ввода от пользователя (вариант запроса текста по "ткните на объект чертежа" рассматривать лениво, хотя и это можно сделать):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | (defun _kpblc-get-text-with-default (default / str) ;| * Запрос текста у пользователя. * Параметры вызова: default ; текст по умолчанию. nil -> пользователь будет вводить текст каждый раз. |; (if (and (= (type (setq str (vl-catch-all-apply (function (lambda (/ res) (setq res (getstring t (strcat "\nEnter text <" (if (and default (/= default "") ) ;_ end of and default "Cancel" ) ;_ end of if "> : " ) ;_ end of strcat ) ;_ end of getstring ) ;_ end of setq (cond ((/= res "") res) ((and (= res "") default) default ) (t nil) ) ;_ end of cond ) ;_ end of lambda ) ;_ end of function ) ;_ end of vl-catch-all-apply ) ;_ end of setq ) ;_ end of type 'str ) ;_ end of = (/= str "") ) ;_ end of and str ) ;_ end of if ) ;_ end of defun |
В таком случае первая команда становится уже такой:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | (defun c:dimunderline-ask (/ str dim vla_dim err) ;| * Добавляет под размерную линию введенный текст |; (if (and (setq str (_kpblc-get-text-with-default nil)) (= (type (setq dim (vl-catch-all-apply (function (lambda () (car (entsel "\nSelect dim : "))) ) ;_ end of function ) ;_ end of vl-catch-all-apply ) ;_ end of setq ) ;_ end of type 'ename ) ;_ end of = (= (cdr (assoc 0 (entget dim))) "DIMENSION") ) ;_ end of and (_kpblc-ent-modify-dim-underlinetext dim str) ) ;_ end of if (princ) ) ;_ end of defun |
А вторая становится чуть другой, но не сложнее первой:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | (defun c:dimunderline-remember (/ str dim vla_dim err) ;| * Добавляет под размерную линию введенный текст с запоминанием последнего введенного текста |; (if (and (setq *kpblc-underline-dimtext* (_kpblc-get-text-with-default *kpblc-underline-dimtext*)) (= (type (setq dim (vl-catch-all-apply (function (lambda () (car (entsel "\nSelect dim : "))) ) ;_ end of function ) ;_ end of vl-catch-all-apply ) ;_ end of setq ) ;_ end of type 'ename ) ;_ end of = (= (cdr (assoc 0 (entget dim))) "DIMENSION") ) ;_ end of and (_kpblc-ent-modify-dim-underlinetext dim *kpblc-underline-dimtext*) ) ;_ end of if (princ) ) ;_ end of defun |
Естественно, что все функции должны быть загружены. Самый элементарный способ - поместить все команды и все функции внутрь одного lsp-файла и обеспечить его загрузку.
P.S. Естественно, что можно и дальше развивать - например, запрашивать размеры в цикле, или вообще выбор размеров закинуть в обработку набора примитивов. Или вынести функционал получения размеров в отдельный код. Но делать уже неохота.