Создание табличного стиля
В предыдущих частях вроде бы разобрались с созданием и модификацией текстового и размерного стилей. Так сказать, прочувствовали, что создание и изменение текстового стиля проработано просто превосходно (оба варианта - и entmake, и vla - отрабатывают просто отлично); что размерный стиль можно создавать только через entmake (если, конечно, вести разговор именно о LISP'e). Сегодня разберемся с табличными стилями.
Ситуация с табличным стилем совсем иная, нежели с размерным стилем. Да и от текстового стиля методология работы со стилями таблиц отличается.
Описание табличного стиля хранится в специальном словаре "ACAD_TABLESTYLE", и до него можно добраться двумя путями:
- через entget:
1(entget (cdr (assoc 350 (member '(3 . "ACAD_TABLESTYLE") (entget (namedobjdict))))))
- через vla:
1(vla-item (vla-get-dictionaries (vla-get-activedocument (vlax-get-acad-object))) "ACAD_TABLESTYLE")
Допустим, нам надо создать (сначала - именно создать) табличный стиль с именем lispru-tablestyle. Настраивать его будем позже. Скажу честно: попытавшись в свое время разобраться с ename-представлениями и запутавшись в dxf-кодах, я плюнул на entmake и все строил с помощью vla-методов.
Создать стиль через vla-представление очень просто (учтите, код пишется прежде всего для объяснения, а не для работы, поэтому улучшать его можно достаточно долго. В конце, если руки дойдут, сделаем проверку быстродействия начального кода и "улучшенного" варианта):
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 | (vl-load-com) (defun _lispru-style-create-table (doc name / res) ;| * Функция создания табличного стиля * Параметры вызова: doc vla-указатель на документ, в котором надо выполнять создание стиля nil -> текущий name имя создаваемого табличного стиля. nil -> "lisptu-tablestyle" * Возвращает vla-указатель на созданный табличный стиль. В случае ошибки * возвращает указатель на активный табличный стиль |; (cond ((not doc) (setq res (_lispru-style-create-table (vla-get-activedocument (vlax-get-acad-object)) name ) ;_ end of _lispru-style-create-table ) ;_ end of setq ) ((not name) (setq res (_lispru-style-create-table doc "lisptu-tablestyle")) ) ((and doc name) (setq res (vla-addobject (vla-item (vla-get-dictionaries doc) "ACAD_TABLESTYLE") name "AcDbTableStyle" ) ;_ end of vla-addobject ) ;_ end of setq ) ) ;_ end of cond ) ;_ end of defun |
Если исключить все проверки, то фактически самыми интересными строками будут
1 2 3 4 5 | (vla-addobject (vla-item (vla-get-dictionaries doc) "ACAD_TABLESTYLE") name "AcDbTableStyle" ) ;_ end of vla-addobject |
Здесь выполняется добавление объекта в словарь. Единственное требование - необходимо указывать класс создаваемого объекта: "AcDbTableStyle".
Запускаем код на выполнение:
1 2 | _$ (_lispru-style-create-table nil nil) #<VLA-OBJECT IAcadTableStyle2 071c60cc> |
Табличный стиль создан? Да, создан, если чертеж новый и в нем не было такого стиля. Попробуем повторно запустить код:
1 2 | _$ (_lispru-style-create-table nil nil) #<VLA-OBJECT IAcadTableStyle2 0f279294> |
Как видно, стиль "как бы создан", то есть прямой ошибки нет. Правда, указатель уже другой получен, и куда делся предыдущий - неясно. Подобных ситуаций (с потерей указателей) лично я стараюсь не сталкиваться и поэтому ввожу проверку:
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | (vl-load-com) (defun _lispru-style-create-table (doc name / res) ;| * Функция создания табличного стиля * Параметры вызова: doc vla-указатель на документ, в котором надо выполнять создание стиля nil -> текущий name имя создаваемого табличного стиля. nil -> "lisptu-tablestyle" * Возвращает vla-указатель на созданный табличный стиль. В случае ошибки * возвращает указатель на активный табличный стиль |; (cond ((not doc) (setq res (_lispru-style-create-table (vla-get-activedocument (vlax-get-acad-object)) name ) ;_ end of _lispru-style-create-table ) ;_ end of setq ) ((not name) (setq res (_lispru-style-create-table doc "lisptu-tablestyle")) ) ((and doc name) (setq res (cond ((member (strcase name) (mapcar (function (lambda (x) (strcase (vla-get-name x)))) ((lambda (/ _res) (vlax-for item (vla-item (vla-get-dictionaries doc) "ACAD_TABLESTYLE" ) ;_ end of vla-item (setq _res (cons item _res)) ) ;_ end of vlax-for (reverse _res) ) ;_ end of lambda ) ) ;_ end of mapcar ) ;_ end of member (vla-item (vla-item (vla-get-dictionaries doc) "ACAD_TABLESTYLE") name ) ;_ end of vla-item ) (t (vla-addobject (vla-item (vla-get-dictionaries doc) "ACAD_TABLESTYLE") name "AcDbTableStyle" ) ;_ end of vla-addobject ) ) ;_ end of cond ) ;_ end of setq ) ) ;_ end of cond ) ;_ end of defun |
В результате, сколько бы раз мы ни запускали код, все время будем получать один и тот же указатель (естественно, только в текущем документе).
Все, код устойчив и работает (забудем пока про попытки запуска его, например, на BricsCAD или на старых версиях AutoCAD, где табличными стилями и не пахнет). Теперь надо настраивать созданный стиль.
Получим дамп объекта. Для AutoCAD 2008 это будет выглядеть примерно так:
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 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | _$ (vlax-dump-object (_lispru-style-create-table nil nil) t) ; IAcadTableStyle2: AutoCAD IAcadTableStyle Interface ; Property values: ; Application (RO) = #<VLA-OBJECT IAcadApplication 00d74d3c> ; BitFlags = 0 ; Description = "" ; Document (RO) = #<VLA-OBJECT IAcadDocument 022e8950> ; FlowDirection = 0 ; Handle (RO) = "1AD" ; HasExtensionDictionary (RO) = 0 ; HeaderSuppressed = 0 ; HorzCellMargin = 0.06 ; Name = "lisptu-tablestyle" ; NumCellStyles (RO) = 3 ; ObjectID (RO) = -1075178648 ; ObjectName (RO) = "AcDbTableStyle" ; OwnerID (RO) = -1075184080 ; TemplateId = 0 ; TitleSuppressed = 0 ; VertCellMargin = 0.06 ; Methods supported: ; CreateCellStyle (1) ; CreateCellStyleFromStyle (2) ; Delete () ; DeleteCellStyle (1) ; EnableMergeAll (2) ; GetAlignment (1) ; GetAlignment2 (1) ; GetBackgroundColor (1) ; GetBackgroundColor2 (1) ; GetBackgroundColorNone (1) ; GetCellClass (1) ; GetCellStyles (1) ; GetColor (1) ; GetColor2 (1) ; GetDataType (3) ; GetDataType2 (3) ; GetExtensionDictionary () ; GetFormat (1) ; GetFormat2 (2) ; GetGridColor (2) ; GetGridColor2 (2) ; GetGridLineWeight (2) ; GetGridLineWeight2 (2) ; GetGridVisibility (2) ; GetGridVisibility2 (2) ; GetIsCellStyleInUse (1) ; GetIsMergeAllEnabled (1) ; GetRotation (1) ; GetTextHeight (1) ; GetTextHeight2 (1) ; GetTextStyle (1) ; GetTextStyleId (1) ; GetUniqueCellStyleName (1) ; GetXData (3) ; RenameCellStyle (2) ; SetAlignment (2) ; SetAlignment2 (2) ; SetBackgroundColor (2) ; SetBackgroundColor2 (2) ; SetBackgroundColorNone (2) ; SetCellClass (2) ; SetColor (2) ; SetColor2 (2) ; SetDataType (3) ; SetDataType2 (3) ; SetFormat (2) ; SetFormat2 (2) ; SetGridColor (3) ; SetGridColor2 (3) ; SetGridLineWeight (3) ; SetGridLineWeight2 (3) ; SetGridVisibility (3) ; SetGridVisibility2 (3) ; SetRotation (2) ; SetTemplateId (2) ; SetTextHeight (2) ; SetTextHeight2 (2) ; SetTextStyle (2) ; SetTextStyleId (2) ; SetXData (2) |
Казалось бы, все просто и очевидно. Но, к сожалению, это не так: Autodesk почему-то не полностью проработал ActiveX для табличных стилей.
Начнем с самого простого: подавления Title и Head. Вроде бы элементарно:
1 2 3 4 5 6 | _$ (setq style (_lispru-style-create-table nil nil)) #<VLA-OBJECT IAcadTableStyle2 071c60cc> _$ (vla-put-TitleSuppressed style :vlax-true) nil _$ (vla-put-HeaderSuppressed style :vlax-true) nil |
А теперь попробуем создать таблицу нашего стиля. Уже при вызове команды _.table видно, что, несмотря на установленное принудительное подавление Title и Head, все равно эти строки есть. Мало того, они и при создании объекта таблицы существуют (по крайней мере об этом сообщает панель свойств). Да, я понимаю, что таблицы без заголовков существуют весьма редко, но, с другой стороны: уж если заявлено что-то, то добивать надо бы до конца, не бросая задачу на полпути.
С методами тоже не все гладко. Например, метод GetAlignment2 заявлен, но в справке для него объяснения я не увидел. DeleteCellStyle тоже заявлен, и для него даже есть что-то в справке, да только через lisp у меня этот метод не сработал, вызвав ошибку ядра.
Поэтому вывод: работать с табличным стилем приходится очень осторожно, постоянно проверяя код.
Тем не менее, настроим наш стиль. Например:
- Текстовый стиль каждого типа ячейки - возвращаемый функцией _lispru-style-create-textstyle
- Горизонтальное расстояние от текста ячейки (любого типа) до ее границы принимаем 0,5 единиц чертежа
- Вертикальное расстояние принимаем тоже 0,5 единиц чертежа
- Высота текста заголовка таблицы (Title) принимаем 7,5 ед.чертежа (ну вот захотелось мне так :))
- Высота текста заголовков столбцов принимаем 5 ед.чертежа
- Высота текста ячеек с данными составляет 3,5 ед.чертежа
- Цвет текста ячеек независимо от их типа, а также цвет границ ячеек принимается ByBlock (ПоБлоку)
- Ячейки не заливаются никаким цветом
- Границы ячейки заголовка таблицы отсутствуют
- Вес линий границ остальных ячеек принимаются равными 0,25
- Заполнение таблицы идет "свеху вниз"
Вроде ничего не забыли. Но, прежде чем писать код, задумаемся - а все ли надо вводить именно в стиле? Ведь, например, текстовый стиль можно вводить напрямую в ячейке. Да и высота текста, и расстояние - вообще, практически все можно вводить и настраивать для каждой ячейки отдельно. Просто сейчас надо решить вопрос - что и в каком месте настраивать, чтобы потом уже не возвращаться.
В свое время я принял решение: все, кроме выравнивания, задается в стиле; и в объекте таблицы меняется строго индивидуально. Кроме того, есть еще один вопрос: а насколько вообще надо передавать в качестве параметров текстовые стили заголовков и данных? Может, и без этого обойтись можно? А насколько требуются параметры, обуславливающие обрамление ячеек? Ответив (только честно ответив!) на эти и подобные вопросы, количество параметров можно весьма серьезно уменьшить.
Стиль создан, осталось его лишь настроить. Об этом позже.