Введение в написание скриптов на Питоне для Блендера 2.5x. Примеры кода - страница 27
или >'CANCELLED'
. Grab (сдвиг), Rotate (вращение), Scale (масштабирование) и Fly-Mode (режим полёта) - примеры модальных операторов. Они особенно полезны для интерактивных инструментов, ваш оператор может иметь собственное состояние, в котором клавиши переключают опции работы оператора.
Когда вызывается оператор в этом примере, он добавляет модального обработчика к себе с помощью вызова >context.window_manager.modal_handler_add(self)
. После этого активный объект продолжает перемещаться по плоскости XY, повторяя перемещения мыши. Для того, чтобы выйти, нажмите кнопку мыши или клавишу Esc.
Модальный метод обрабатывает три типа событий:
1. Перемещение мыши перемещает активный объект.
2. Нажатие ЛКМ для подтверждения и выхода в нормальный режим. Объект оставляется в своей новой позиции.
3. Нажатие ПКМ или клавиши Esc, чтобы отменить и выйти в нормальный режим. Объект возвращается в свою первоначальную позицию.
Важно, чтобы был некоторый способ выходить в нормальный режим. Если функция modal() всегда возвращает 'RUNNING_MODAL', скрипт войдёт в бесконечный цикл, и Вам придётся перезапускать Блендер.
Модальный оператор определяет два специальных метода с именами >__init()__
и >__del()__
, которые вызываются, когда модальная операция начинается и прекращается, соответственно.
Запустите скрипт. Активный объект перемещается по плоскости XY при перемещении мыши. Скрипт также создает панель с кнопкой, нажатием на которую Вы также можете выполнить модальный оператор.
>#----------------------------------------------------------
># File modal.py
># from API documentation
>#----------------------------------------------------------
>import bpy
>class MyModalOperator(bpy.types.Operator):
> bl_idname = "mine.modal_op"
> bl_label = "Move in XY plane"
> def __init__(self):
> print("Start moving")
> def __del__(self):
> print("Moved from (%d %d) to (%d %d)" %
> (self.init_x, self.init_y, self.x, self.y))
> def execute(self, context):
> context.object.location.x = self.x / 100.0
> context.object.location.y = self.y / 100.0
> def modal(self, context, event):
> if event.type == 'MOUSEMOVE':
># Применение
> self.x = event.mouse_x
> self.y = event.mouse_y
> self.execute(context)
> elif event.type == 'LEFTMOUSE':
># Подтверждение
> return {'FINISHED'}
> elif event.type in ('RIGHTMOUSE', 'ESC'):
># Отмена
> return {'CANCELLED'}
> return {'RUNNING_MODAL'}
> def invoke(self, context, event):
> self.x = event.mouse_x
> self.y = event.mouse_y
> self.init_x = self.x
> self.init_y = self.y
> self.execute(context)
> print(context.window_manager.modal_handler_add(self))
> return {'RUNNING_MODAL'}
>#
># Панель в районе tools
>#
>class MyModalPanel(bpy.types.Panel):
> bl_label = "My modal operator"
> bl_space_type = "VIEW_3D"
> bl_region_type = "TOOLS"
> def draw(self, context):
> self.layout.operator("mine.modal_op")
># Регистрация
>bpy.utils.register_module(__name__)
># Автоматически перемещает активный объект при запуске
>bpy.ops.mine.modal_op('INVOKE_DEFAULT')
Этот скрипт иллюстрирует разницу между invoke (вызывать) и execute (выполнять). Вызываемое (invoking) событие является аргументом функции >Operator.invoke
, который устанавливает два свойства целого типа x и y для положения мыши и вызывает функцию >Operator.execute
. Как альтернатива, мы можем выполнить (execute) оператор и явно установить >x
и >y
: >bpy.ops.wm.mouse_position(’EXEC_DEFAULT’, x=20, y=66
)
Вместо вывода координат мыши в окно терминала, информация отправляется в информационную панель в верхнем правом углу. Это хорошее место для отображения краткого уведомления, так как пользователю не придется искать его в другом окне, тем более, что терминал/DOS-окно отображается не во всех версиях Blender. Однако длинные сообщения трудно вписываются в ограниченное пространство информационной панели.
>#----------------------------------------------------------