Для кастомных свойств в Blender Python API можно задать определенные максимальное и минимальное значения. В этом случае пользователь, вводя нужное значение в поле, не сможет указать для него величину, выходящую за указанные пределы.
Для того, чтобы задать минимальное и максимальное ограничения нужно указать в создаваемом свойстве параметры «min» и «max» и присвоить им нужные ограничивающие значения.
Например, при создании целочисленного свойства «limited_value» ему можно задать ограничения на ввод от 0 до 25 следующим образом:
|
1 2 3 4 5 6 7 |
import bpy bpy.types.Scene.limited_value = bpy.props.IntProperty( name='limited_value', min=0, max=25 ) |
Теперь, если попытаться задать для этого свойства значение вне указанного промежутка, например «50», свойству будет присвоено только максимально возможное значение — «25».
Значения «max» и «min» задаются статически. Однако иногда бывает нужно в процессе работы аддона изменить указанные пределы.
Если вместо статического значения попробовать указать функцию, динамически возвращающую нужные ограничения, например для максимального значения:
|
1 2 3 4 5 6 7 8 |
def dynamic_max(): return bpy.context.scene.frame_current bpy.types.Scene.limited_value = bpy.props.IntProperty( name='limited_value', default=0, max=dynamic_max ) |
Blender вернет сообщение об ошибке:
TypeError: an integer is required (got type function)
ValueError: bpy_struct registration error: IntProperty could not register
Это происходит потому, что параметры «max» и «min» при определении свойства IntPropert требуется задавать только числовыми значениями.
Задать напрямую динамические параметры «max» и «min» нельзя, однако, мы все же можем добиться нужного нам поведения свойства, переопределив для него функции «set» и «get».
Для начала определим два дополнительных кастомных свойства, в которых будем хранить нужные нам максимальное и минимальное значения:
|
1 2 3 4 5 6 7 8 9 |
bpy.types.Scene.dynamic_max = bpy.props.IntProperty( name='dynamic_max', default=15 ) bpy.types.Scene.dynamic_min = bpy.props.IntProperty( name='dynamic_min', default=0 ) |
Они динамические, и мы можем их легко менять, вынеся на панель интерфейса, или напрямую в коде:
|
1 |
bpy.context.scene.dynamic_min = 5 |
Определим функции «get_limited_value» и «set_limited_value». Внутри функции «set_limited_value», которая отвечает за присваивание свойству значения будем контролировать, не выходил ли оно за заданные пределы и, если выходит, корректировать его.
|
1 2 3 4 5 6 7 8 9 |
def set_limited_value(self, new_value): if new_value > bpy.context.scene.dynamic_max: new_value = bpy.context.scene.dynamic_max if new_value < bpy.context.scene.dynamic_min: new_value = bpy.context.scene.dynamic_min self['limited_value'] = new_value def get_limited_value(self): return self.get('limited_value', 0) |
Функция «get_limited_value» просто возвращает значение свойства.
При определении самого свойства, переопределим его функции «get» и «set» нашими:
|
1 2 3 4 5 6 |
bpy.types.Scene.limited_value = bpy.props.IntProperty( name='limited_value', default=0, get=lambda self: get_limited_value(self), set=lambda self, value: set_limited_value(self, value) ) |
Теперь при каждом присваивании значения свойству «limited_value» будет вызываться переопределенная нами функция «set_limited_value» в которой это значение будет корректироваться в соответствии с указанными в «dynamic_min» и «dynamic_max» лимитами.
Вынесем все три наших свойства на UI-панель в окне «3D Viewport»:
|
1 2 3 4 5 6 7 8 9 10 11 |
class test_PT_Panel(bpy.types.Panel): bl_idname = 'TEST_PT_panel' bl_label = 'DYNAMIC MAX-MIN' bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'TEST' def draw(self, context): self.layout.prop(bpy.context.scene, 'limited_value') self.layout.prop(bpy.context.scene, 'dynamic_max') self.layout.prop(bpy.context.scene, 'dynamic_min') |
Теперь мы можем задавать значения для свойства «limited_value», которые всегда будут лежать в указанных в «dynamic_min» и «dynamic_max» пределах, и в тоже время свободно изменять эти пределы по своему усмотрению.
Полный код:
|
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 |
import bpy class test_PT_Panel(bpy.types.Panel): bl_idname = 'TEST_PT_panel' bl_label = 'DYNAMIC MAX-MIN' bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'TEST' def draw(self, context): self.layout.prop(bpy.context.scene, 'limited_value') self.layout.prop(bpy.context.scene, 'dynamic_max') self.layout.prop(bpy.context.scene, 'dynamic_min') # functions for get/set value with dynamic limits def set_limited_value(self, new_value): if new_value > bpy.context.scene.dynamic_max: new_value = bpy.context.scene.dynamic_max if new_value < bpy.context.scene.dynamic_min: new_value = bpy.context.scene.dynamic_min self['limited_value'] = new_value def get_limited_value(self): return self.get('limited_value', 0) def register(): bpy.types.Scene.dynamic_max = bpy.props.IntProperty( name='dynamic_max', default=15 ) bpy.types.Scene.dynamic_min = bpy.props.IntProperty( name='dynamic_min', default=0 ) bpy.context.scene.dynamic_min = 5 bpy.types.Scene.limited_value = bpy.props.IntProperty( name='limited_value', default=0, get=lambda self: get_limited_value(self), set=lambda self, value: set_limited_value(self, value) ) bpy.utils.register_class(test_PT_Panel) register() |

Content on Patreon