Сегодня мы посмотрим, как создаются интеллектуальные смарт-шейпы. К этому типу относится больше половины шейпов из трафаретов, поставляемых в составе Visio. Это не просто картинки, а разумные картинки, поэтому с ними так легко работать. Естественно, когда-то возникает желание научиться и самому делать такие же, но ориентированные на нужное вам применение.
Основой управления шейпами является шейп-лист (ShapeSheet). Это просто таблица, в которой хранятся все данные о шейпе. В Visio — каждый шейп, группа, стиль, страница, документ — имеют свой шейп-лист. Там содержатся такие данные, как высота, ширина, угол, цвет и другие атрибуты, определяющие вид и поведение шейпа.
Шейп-лист разбит на секции, в каждой секции несколько строк, в строке несколько ячеек. Ячейка может содержать либо константу, либо формулу, значение которой зависит от других ячеек или от свойств других объектов Visio. При построении формул могут использоваться встроенные функции, (математические, статистические, преобразование типов и т.д.).
Собственно говоря, в Visio сделано все, чтобы можно было обойтись без этой статьи. Дело в том, что все изменения на странице рисунка тут же отображаются в шейп-листе. Открыв одновременно и рисунок и шейп-лист можно изменять шейп на странице рисунка и наблюдать, как это проявляется в ячейках шейп-листа. Соответственно, действует и обратный процесс, что позволяет легко набирать экспериментальные данные, даже если вы не любите читать документацию.
Шейп-лист открывается через меню Window/Show ShapeSheet. Причем открывается шейп-лист выбранного в данный момент шейпа. Если шейп не выбран, откроется шейп-лист страницы рисунка. Для открытия другого шейп-листа нужно вернуться к странице рисунка, выбрать другой шейп и повторить команду открытия Window/Show ShapeSheet.
И последний вводный момент. Иногда в шейп-листе вы не видите нужной секции, значит либо нужно попросить вывести ее (например, в меню View/Sections щелкнуть по кнопке All), либо ввести какие-то данные, чтобы было что показывать в этой секции (например, секция Text Fields не показывается, пока шейп не содержит поля, вводимого через меню Insert/Fields…).
А теперь переходим к примерам
1. Сделаем стрелку, автоматически измеряющую то, к чему мы ее приклеим.
Сначала нарисуем две размерные линии, соединим их и выберем оформление типа 13 (стрелки) для обоих концов соединяющей линии. Для размещения соответствующего текста нужно:
- выбрать горизонтальную линию;
- через меню Insert/Field вставить поле Geometry/Width, выбрав для значения Format: третью строчку «0».
Непосредственно на горизонтальной линии появляется оцифровка, показывающая ее длину. Контролируем эти изменения в шейп-листе. Мы обнаруживаем там секцию Text Fields, имеющую два поля Format: со значением FieldPicture(2) и Value: со значением width. Данный формат указывает, что нам нужны только целые значения оцифровки.
Можно было при установке поля выбрать другой формат, и он отразился бы в этой ячейке. Значение Width говорит о том, что в текстовом поле будет отображаться ширина горизонтальной стрелки в тех единицах измерения, которые выбраны для страницы рисунка.
Если для страницы рисунка в качестве единиц измерения выбраны, например, дюймы, а нам нужно измерять отрезки в сантиметрах, то нужно изменить эту формулу. Щелкаем мышью по ячейке шейп-листа с надписью Width и видим, как наверху в поле формулы появляется текст =Width. Ставим туда курсор и дописываем формулу =Width/25,4. Для принятия формулы нужно щелкнуть по соседней кнопке с галочкой и всплывающей подписью Accept. Теперь на стрелке мы получим значение в нужных единицах измерения.
Желательно цифры располагать не на стрелке, а над ней. Текст можно сместить средством Text Block Tool, а можно просто в секции Text Transform в ячейку TxtPinY шейп-листа ввести значение 2,5 mm. Это значит, что центр текста будет располагаться на 2,5 мм выше центра размерной линии.
Группируем получившуюся конструкцию. Группа обладает свойствами 2-D шейпа, то есть получился прямоугольник, который не будет работать в качестве коннектора, а это нужное свойство при измерении. Поэтому переключаем Interaction Style в меню Format/Behavior на Line (1-dimensional).
Теперь прямоугольник считается линией, имеющей начало и конец, только они расположены не в тех местах, которые нам нужны, а посредине вертикальных черточек. Для смещения начала и конца линии нужно выбрать группу, открыть ее шейп-лист и в секции Shape Transform изменить формулу в ячейке LocPinY с Height*0,5 на Height*0. Тем самым мы переносим центр вращения в самый низ группы.
Осталось только проверить результат. Помещаем на страницу рисунка квадрат, прицепляем к его углам нашу стрелку и начинаем менять его размеры. Мы видим, что они тут же отслеживаются цифрами над стрелкой. Дублируем стрелку, поворачиваем ее на 90 градусов и цепляем к вертикальной стороне квадрата. С удовольствием наблюдаем, как стрелки следуют за квадратом и измеряют его.
2. Прямоугольник, длина которого отслеживает введенное число.
Рисуем прямоугольник и начинаем его настраивать. Каждому шейпу можно приписать в любом количестве пользовательские свойства. Воспользуемся этим. Выбираем наш прямоугольник и через меню Shape/Custom Properties, нажав на кнопку Yes, переходим к созданию свойства под названием «Значение». Заполнив три поля как показано на рисунке, нажимаем кнопку OK.
В шейп-листе теперь можно найти секцию Custom Properties, в строке Prop.Row_1 которой имеются ячейки Label, содержащая метку «Значение», и Value, куда мы ввели значение «1».Нам нужно, чтобы ширина прямоугольника отслеживала значение ячейки Value. Для этого в ячейку Width секции Shape Transform помещаем формулу =Prop.Row_1/2,54.
Более строго было бы написать Prop.Row_1.Value, но ячейка Value является в данной секции значением по умолчанию, поэтому она выбирается автоматически при указании секции. 2,54 нужно, чтобы пересчитать введенное значение из дюймов в сантиметры (вводится оно в дюймах). Чуть ниже мы исправим эту формулу, но об этом в свое время.
Если теперь через меню Shape/Custom Properties изменить значение на 2, то наш прямоугольник станет вдвое шире. Однако при этом центр его остается на месте, а оба конца уползают в стороны. Для гистограммы такое поведение нас не устраивает. Желательно, чтобы левый конец оставался на месте, а перемещался только правый. Для этого нужно сместить центр вращения шейпа в крайнюю левую точку — ввести в ячейку LocPinX секции Shape Transform вместо формулы =Width*0,5 формулу =Width*0.
Можно добавить и оцифровку. Для этого стандартным способом включаем поле Insert/Fields/Custom Properties/Значение/Format=0. Подвешиваем оцифровку над прямоугольником путем ввода в шейп-лист секцию Text Transform ячейку TxtPinY формулы =Height*1,5.
Получилось уже почти то, что нужно. Вот только при дублировании шейпа значение Width переопределяется и шейп теряет приданные ему свойства. Чтобы этого не происходило, нужно опять вернуться к ячейке Width секции Shape Transform и поставить туда защиту формулы =Guard(Prop.Row_1/2,54). Такой шейп можно спокойно дублировать.
Проверяем эффект. Выбираем шейп, выбираем Shape/Custom Properties, изменяем значение — наблюдаем изменение длины и новую оцифровку.
3. Постоянная ориентация текста
В двух разобранных примерах текст поворачивался вместе с шейпом. Однако иногда необходимо сделать так, чтобы шейп поворачивался, а текст оставался в том же положении.
На этом рисунке показаны линии, индицирующие свою длину. Сделаны они примерно так же, как и размерная стрелка в первом примере (только вместо сложной группы использована всего одна линия). В секцию Text Transform в ячейку TxtAngle введена формула =-Angle. Ячейка Angle расположена в секции Shape Transform и показывает угол поворота шейпа, значит ссылкой на эту ячейку со знаком минус мы заставляем текст повернуться на такой же угол в обратную сторону, что и дает нужный эффект.
Все три приведенных примера в виде рисунка Visio можно взять в архиве Source1.zip.
4. Позиционирование штампа чертежа
Усложним задачу. Заставим шейп следить не только за своими параметрами, но еще искать и использовать параметры другого шейпа и страницы рисунка. Такая задача возникает, например, если мы хотим нарисовать универсальный штамп с рамкой для чертежа по требованиям ЕСКД. Внешнюю рамку допускается не использовать. Для усложнения задачи считаем, что требования к полям могут меняться в зависимости от используемого принтера.
Таким образом, имеем два основных объекта:
- внутренняя рамка;
- основной штамп.
У внутренней рамки зададим пользовательские свойства — поля. Будем позиционировать ее по размеру рисунка и величинам полей. Установим минимальную ширину рамки 185 мм и если заданные поля не обеспечивают минимальной ширины, пусть нарушается условие левой границы. То есть, если на формате А4 установить левое поле 20 мм, а правое 6 мм, то рамка должна сама переставить левое поле на 19 мм.
Штамп будем позиционировать по рамке, связывая их правыми нижними углами. Таким образом в шейп-листе рамки должны быть установлены:
в секции Custom Properties:
Label | Type | Value | |
Prop.Row_1 | «Нижнее поле» | 2 | 6 |
Prop.Row_2 | «Правое поле» | 2 | 6 |
Prop.Row_3 | «Верхнее поле» | 2 | 6 |
Prop.Row_4 | «Левое поле» | 2 | 19 |
в секции Scratch:
A1 | =FORMATEX(Prop.Row_1;»0.000 u»;»mm»;»ft») |
B1 | =FORMATEX(Prop.Row_2;»0.000 u»;»mm»;»ft») |
C1 | =FORMATEX(Prop.Row_3;»0.000 u»;»mm»;»ft») |
D1 | =FORMATEX(Prop.Row_4;»0.000 u»;»mm»;»ft») |
A2 | =ThePage!PageWidth-(Scratch.D1+Scratch.B1) |
в секции Shape Transform:
Width | =GUARD(if(Scratch.A2<(185/25.4); 185/25.4; Scratch.A2)) |
Height | =GUARD(ThePage!PageHeight-(Scratch.A1+Scratch.C1)) |
Angle | =GUARD(0) |
PinX | =GUARD(ThePage!PageWidth-Scratch.B1) |
PinY | =GUARD(Scratch.A1) |
LocPinX | =GUARD(Width) |
LocPinY | =GUARD(0) |
В шейп-листе штампа установлены:
в секции Shape Transform:
PinX | =GUARD(Scratch.C1&Scratch.B1) |
PinY | =GUARD(Scratch.C1&Scratch.D1) |
LocPinX | =GUARD(Width) |
LocPinY | =GUARD(0) |
в секции Scratch:
B1 | =»!PinX» |
C1 | =»» |
D1 | =»!PinY» |
в секции Scratch:
EventDrop | =SETF(GetRef(Scratch.C1);»»»Рамка чертежа»»») |
EventDblClick | =SETF(GetRef(Scratch.C1);»»»Рамка чертежа»»») |
Что это значит
В секции Custom Properties устанавливаются вводимые поля для рамки, причем значения вводятся в миллиметрах. Дальше Visio считает в дюймах. Для перевода значений из миллиметров в дюймы создается секция Scratch, в ячейках A1-D1 которой с помощью функции FORMATEX производится преобразование единиц измерения, а в ячейке A2 рассчитывается теоретическая ширина рамки в зависимости от ширины страницы рисунка и величины полей. При ссылке на другой объект (страницу рисунка) он отделяется восклицательным знаком (ThePage!PageWidth).
В секции Shape Transform вычисляется ширина рамки. Теоретическая ширина рамки либо принимается (если она больше 185 мм), либо заменяется величиной 185 мм.
Высота рамки рассчитывается простым вычитанием вертикальных полей из высоты страницы рисунка. В качестве центра вращения (PinX, PinY — его координаты относительно страницы) устанавливается правый нижний угол. Его локальными координатами являются LocPinX, LocPinY. Все перечисленные ячейки секции защищаются от изменения.
Ситуация с штампом несколько сложнее. Мы поставили себе задачу привязать его координаты к координатам рамки. Если бы разговор шел о шейпах, расположенных на листе рисунка, то такая привязка достигалась бы простой ссылкой на ячейку другого объекта PinX=GUARD(Рамка чертежа!PinX). Но если мы хотим разместить штамп в трафарете в качестве мастер-шейпа, то Visio не позволит поставить ссылку на несуществующий шейп. Значит нужно вычислять эту ссылку в процессе работы.
Одним из удобных моментов представляется момент опускания мастер-шейпа на страницу рисунка. Связь с этим событием устанавливается через ячейку EventDrop секции Events. В нашем случае в момент его наступления функция SETF запишет в ячейку Scratch.C1 имя шейпа рамки «Рамка чертежа». Потом это имя скомпонуется со ссылками на PinX и PinY и поступит в соответствующие ячейки секции Shape Transform.
Такая связка срабатывает, но к сожалению, только один раз. При изменении размеров страницы рисунка рамка уползает вместе со страницей, а штамп остается на месте. Однако, если такую же формулу записать и в качестве реакции на второе событие — двойной щелчок мыши (ячейка EventDblClick), то положение штампа всегда можно будет легко откорректировать.
Записываем оба объекта в трафарет Stencil2.vss, рабочий пример — в файл Source2.vsd. Все это можно взять в архиве Source2.zip.
Отмечу, что рисунок сделан только в целях демонстрации и не следует использовать его для оформления настоящих чертежей.