Удобство редактирования чертежей является одной из ключевых характеристик систем автоматизированного проектирования. Важным инструментом для работы с объектами чертежа служат ручки (grips) — специальные маркеры в ключевых точках объекта, которые позволяют видоизменять объект с помощью мыши, без использования меню или командной строки.
Механизм управления ручками в MultiCAD.NET позволяет работать как с простыми, так и интеллектуальным ручками. Про простые ручки мы писали в одной из прошлых статей, здесь же мы рассмотрим интеллектуальные ручки, которые, помимо формы (круглые, треугольные, ромбовидные и т.д.), отличаются от простых тем, что они могут изменять отдельные параметры объекта, вызывать всплывающее меню или выполнять набор действий, определенный в обработчике. Кроме, этого API интеллектуальных ручек позволяет также создавать и простые ручки, но используя при этом новый, унифицированный подход.
Под катом код создания нескольких видов интеллектуальных ручек объекта и анимированные изображения, демонстрирующие их использование.
Класс McSmartGrip<T>
Для описания интеллектуальных ручек в MultiCAD.NET API используется класс McSmartGrip<T>
. Данный класс содержит несколько вариантов конструктора с различными списками параметров, а также обработчики событий, которые генерируются в зависимости от действий пользователя:
MoveGrip
— вызывается при перемещении ручки,MouseMove
— вызывается при перемещении ручки интерактивного типа,GetContextMenu
— вызывается при щелчке на ручке с типомGripType.PopupMenu
,OnCommand
— вызывается при щелчке на ручке с типомGripType.Button
или по пункту контекстного меню полученного изGetContextMenu
.
Например, для создания простой ручки, отвечающей за перемещение точки объекта, может быть использован следующий конструктор:
var simpleGrip = new McSmartGrip<ObjectRefEntity>(position, (obj, g, offset) => { obj.TryModify(); obj._pnt += offset; }
Данный конструктор предусматривает реализацию делегата MoveGrip
, что мы и сделали, с помощью лямбда-выражения (http://msdn.microsoft.com/ru-ru/library/bb397687.aspx), а именно, переместили позицию объекта на величину offset
.
Регистрация ручек
Регистрация ручек пользовательского объекта производится с помощью метода AppendGrip()
класса GripPointsInfo
:
public void AppendGrip(Multicad.CustomObjectBase.McBaseGrip grip);
Этот класс используется в качестве аргумента метода GetGripPoints()
, который вызывается для получения ручек каждый раз при отображении объекта:
public virtual bool GetGripPoints(Multicad.CustomObjectBase.GripPointsInfo info);
Следующий фрагмент кода создает и добавляет всю ту же простую ручку:
public override bool GetGripPoints(GripPointsInfo info)
{
info.AppendGrip(new McSmartGrip<ObjectRefEntity>(_pnt, (obj, g, offset) => { obj.TryModify(); obj._pnt += offset; }));
}
Как видите, вся процедура очень компактна и занимает всего одну строку кода. Однако, это касалось самого элементарного случая, а именно, простых ручек. Давайте рассмотрим какие еще типы ручек поддерживаются в MultiCAD.NET API, а также специфику работы с каждым из них.
Типы ручек
Используя MulitiCAD.NET, можно создавать ручки следующих типов:
Simple
— простая ручка. Обработка перемещения ручки, реализуется вMoveGrip
.PopupMenu
— ручка, по щелчку на которой отображается всплывающие меню. Обработка события реализуется вOnCommand
.Button
— ручка-кнопка, при нажатии на которую выполняются действия, описанные вOnCommand
.Interactive
— тип, похожий наSimple
, но позволяющий работать с объектными привязками. В отличие от простой ручки обработка события реализуется вMouseMove
.
Внешний вид ручек
Один объект может содержать несколько ручек различного типа; для того, чтобы визуально их различать, можно назначить внешний вид каждой из них, определив ее форму и цвет. Многообразие форм ручек определяется перечислением McBaseGrip.GripAppearance
. Вот некоторые из них:
Также может быть задан желаемый цвет ручек из набора цветов, определенного в классе GripColors
, или же можно определить цвет стандартным способом, с помощью System.Drawing.Color
.
Давайте посмотрим как это работает. В качестве примера возьмем знакомый нам примитив TextInBox
, описанный в этой статье и создадим для него несколько интеллектуальных ручек различного типа.
Простая ручка
Этот вид ручек мы уже упоминали в статье, и, как можно догадаться из названия, он используется для простых действий, например, для перемещения точек объекта. Добавим одну простую ручку для перемещения угловой точки нашего примитива:
info.AppendGrip(new McSmartGrip<ObjectRefEntity>(_pnt, (obj, g, offset) => { obj.TryModify(); obj._pnt += offset; }));
Результат работы такой ручки — на анимированной иллюстрации:
Ручка-кнопка
Добавим ручку-кнопку, которая будет управлять отображением рамки вокруг текста по нажатию. Для создания такой ручки используется конструктор с указанием типа ручки McBaseGrip.GripType.Button
и базовым цветом. Обработчик нажатия на кнопку OnCommand
меняет значение индикатор рисования рамки _show_frame
на обратное. Для созданной ручки-кнопки определим внешний вид «включено», который будет меняться на «выключено» при нажатии, и обратно.
var OnOffGrip = new McSmartGrip<TextInBox>(McBaseGrip.GripType.Button, 1, _pnt + stepVector,
McBaseGrip.GripAppearance.SwitchOn, 0, "Hide Frame", GripColors.Base);
OnOffGrip.Tag = "OnOffGrip";
if (_show_frame == false)
OnOffGrip.SetAppearanceAndText(McBaseGrip.GripAppearance.SwitchOff, "Show frame");
OnOffGrip.OnCommand = (obj, commandId, grip) => { obj.TryModify(); obj._show_frame = !obj._show_frame;};
info.AppendGrip(OnOffGrip);
Результат:
Также по нажатию ручки-кнопки может быть вызвана необходимая зарегистрированная команда:
var cmdGrip = new McSmartGrip<TextInBox>( McBaseGrip.GripType.Button, 1, _pnt + 2 * stepVector,
McBaseGrip.GripAppearance.Circle, 0, "button", GripColors.Base);
cmdGrip.Tag="cmd";
cmdGrip.OnCommand = (obj, commandId, grip) =>
{
McContext.ExecuteCommand(grip.Tag.ToString());
};
Ручка-меню
Еще один тип ручек, который можно создавать в MultiCAD.NET — ручка для вызова контекстного меню. Данный вид ручек используется, когда пользователю необходимо выбрать из списка необходимое значение параметра объекта из списка.
Данный вид ручек создается с помощью конструктора с указанием типа McBaseGrip.GripType.PopupMenu
и внешнего вида, определенного значением McBaseGrip.GripAppearance.PopupMenu
. Для работы с контекстным меню необходимо реализовать два делегата:
GetContextMenu
— вызов меню при нажатии на ручку,
OnCommand
— вызов действий при выборе пунктов
var ctxGrip = new McSmartGrip<TextInBox>(McBaseGrip.GripType.PopupMenu, 2, _pnt + 2 * stepVector,
McBaseGrip.GripAppearance.PopupMenu, 0, "Select menu", System.Drawing.Color.Lime);
ctxGrip.GetContextMenu = (obj, items) =>
{
items.Add(new ContextMenuItem("Command 1", "none", 1));
};
ctxGrip.OnCommand = (obj, commandId, grip) =>
{
if (grip.Id == 2)
{
switch (commandId)
{
case 1:
{
MessageBox.Show("Command 1 is selected");
break;
}
}
}
};
info.AppendGrip(ctxGrip);
Результат:
Интерактивная ручка
И, наконец, последний тип ручек, который мы рассмотрим — интерактивный. Главное отличие этих ручек в том, что они могут использовать информацию об объектах привязки и в зависимости от этого определять свое поведение.
В качестве примера, добавим одну из таких ручек, которая позволит менять текст нашего примитива на имя выбранного объекта (за исключением родительского объекта). В зависимости от объекта привязки ручка будет менять цвет: в исходном состоянии ручка будет иметь цвет GripColors.Base
, при наведении на родительский объект цвет будет меняться на Color.Red
, на любой другой объект, поддерживающий привязку — на Color.Green
.
Интерактивная ручка создается конструктором с указанием типа McBaseGrip.GripType.Interactive
, а работа ручки реализуется в делегате MouseMove
(в отличие от простых ручек, где используется MoveGrip
).
var interactiveGrip = new McSmartGrip<TextInBox>(McBaseGrip.GripType.Interactive, 3, _pnt + 3 * stepVector,
McBaseGrip.GripAppearance.Arrow, 0, "interactive", GripColors.Base);
interactiveGrip.IsMovable = true;
interactiveGrip.MouseMove = (obj, entInfo, grip, offset) =>
{
grip.Color = GripColors.Base;
if (!entInfo.SnapedObjectId.IsNull)
{
if (ID == entInfo.SnapedObjectId)
{
grip.Color = Color.Red;
}
else
{
grip.Color = Color.Green;
obj.TryModify();
obj.Text = (entInfo.SnapedObjectId.GetObject().GetType().ToString());
}
}
};
info.AppendGrip(interactiveGrip);
Результат: текст «Text field» заменен на «MultiCAD.Samples.TextInBox».
Мы перечислили основные типы интеллектуальных ручек, которые позволяют создать эффективный интерфейс для работы с пользовательскими объектами, созданными на MultiCAD.NET. Документация по MultiCAD.NET входит в состав nanoCAD SDK, доступ к которому можно получить, зарегистрировавшись в Клубе разработчиков nanoCAD.
Автор: ISL