В Blender Python API определенные операторы можно вызывать только в той рабочей области, для которой они предназначены. Если вызвать такой оператор в другой рабочей области, он не будет выполнен или же Blender выдаст ошибку. Для того чтобы вызвать такой оператор из непредназначенной для него области, нужно переопределить для него контекст.
До версии 3.2, чтобы переопределить контекст, в операторах Blender был предусмотрен скрытый первый параметр, и если через него передать структуру, скопированную с контекста нужной рабочей области, оператор корректно выполняется.
Однако начиная с версии 3.2 такой метод считается устаревшим (deprecated). Это означает, что в более поздних версиях Blender, его все еще можно применять, однако, никаких гарантий стабильной работы не дается. А в дальнейшем он будет вообще удален из API Blender.
Вместо того чтобы передавать переопределенный контекст в первом параметре оператора, Blender API начиная с версии 3.2 предлагает использовать метод контекста temp_override(), который при вызове возвращает дескриптор переопределенного контекста.
Для переопределения контекста нужно вызывать этот метод, передав в его параметрах указатель на регион, контекст которого нужно переопределить.
Переопределять контекст можно для:
- окна целиком (window)
- рабочую область (area)
- регион рабочей области (region)
- а также указывая точный ключ, указывающий на контекст объекта (например bone или active_object)
Для того чтобы переопределить контекст, например, рабочей области окна 3D вьюпорта
- нужно получить указатель на нее:
1 |
area = [area for area in bpy.context.screen.areas if area.type == "VIEW_3D"][0] |
- и вызывать функцию переопределения контекста:
1 2 3 |
bpy.context.temp_override(area=area) # <ContextTempOverride object at 0x00000150E29E5080> |
Пока дескриптор переопределенного контекста активен, все дальнейшие вызовы операторов будут производиться так, как будто они вызываются в нужном контексте.
Для того чтобы не заботиться о правильном закрытии дескриптора лучше всего вызывать функцию temp_override() при помощи инструкции with. В этом случае после завершения блока with дескриптор будет автоматически удален, и дальнейший код будет выполняться в изначальном контексте.
Например, чтобы вызывать оператор смены способа выделения объектов в окне 3D вьюпорта с бокса на круг из окна текстового редактора Text Editor нужно вызвать следующий код:
1 2 3 4 5 6 |
import bpy area = [area for area in bpy.context.screen.areas if area.type == "VIEW_3D"][0] with bpy.context.temp_override(area=area): bpy.ops.wm.tool_set_by_id(name='builtin.select_circle') |
Сначала мы получаем указатель на area – рабочую область 3D вьюпорта. Далее мы передаем полученный указатель в параметре функции temp_override(area=area) и внутри блока with вызываем оператор с нужным контекстом.