Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revisionBoth sides next revision | ||
graphic:python:blender [2024/01/24 10:00] – [Blender variable naming standards] ying | graphic:python:blender [2024/02/01 09:13] – [Blender UI code] ying | ||
---|---|---|---|
Line 393: | Line 393: | ||
ref: | ref: | ||
* https:// | * https:// | ||
+ | * https:// | ||
* https:// | * https:// | ||
+ | * https:// | ||
- | * Class name convention | + | |
* UPPER_CASE: normally the ADDON_NAME, or a Unique ID_WORD that make it not crashing into other existing class names | * UPPER_CASE: normally the ADDON_NAME, or a Unique ID_WORD that make it not crashing into other existing class names | ||
* {SEPARATOR} | * {SEPARATOR} | ||
Line 407: | Line 409: | ||
* _Check_Selection | * _Check_Selection | ||
* _check_selection | * _check_selection | ||
- | | + | |
- | * if not follow above: you get warning " | + | * if not follow above: you get warning " |
- | + | | |
- | * operator ID name convention (feel like a username for your operator inside blender ) | + | |
* category_name.operator_task_like_name | * category_name.operator_task_like_name | ||
* custom.addon_name_task_name (snake_case like PEP function) | * custom.addon_name_task_name (snake_case like PEP function) | ||
Line 416: | Line 417: | ||
* class: ADDON_NAME_OT_check_selection | * class: ADDON_NAME_OT_check_selection | ||
* bl_idname: addon_name.check_selection | * bl_idname: addon_name.check_selection | ||
- | + | | |
- | * other same as PEP | + | * obj = " |
- | | + | * obj_max_count = 2 |
- | | + | * def function_name(arg_name) |
- | | + | * class ClassName() |
- | | + | |
+ | Example of class name, balancing between Python PEP | ||
+ | * example addon, <code python> | ||
+ | class BUILDMAKER_OT_CreateAsset(bpy.types.Operator): | ||
+ | bl_idname = " | ||
+ | | ||
+ | class CreateAsset(bpy.types.Operator): | ||
+ | bl_idname = " | ||
+ | |||
+ | class BUILDMAKER_OT_createAsset(bpy.types.Operator): | ||
+ | |||
+ | # 2.8x onwards, property | ||
+ | class MyOperator(bpy.types.Operator): | ||
+ | value: IntProperty() | ||
+ | |||
+ | class ToolProperties(bpy.types.PropertyGroup): | ||
+ | commandLineMode: | ||
+ | name = " | ||
+ | description = "The option specifies if the addon is used in the command line mode", | ||
+ | default = False | ||
+ | ) | ||
+ | | ||
+ | class ToolProps(bpy.types.PropertyGroup): | ||
+ | email : StringProperty( | ||
+ | name=" | ||
+ | description=" | ||
+ | default="" | ||
+ | ) | ||
+ | class TOOL_PROPS(bpy.types.PropertyGroup): | ||
+ | lon: FloatProperty() | ||
+ | lat: FloatProperty() | ||
+ | class BUILDMAKER_PG_color(PropertyGroup): | ||
+ | color: FloatVectorProperty(subtype=' | ||
+ | </ | ||
===== common blender api commands ===== | ===== common blender api commands ===== | ||
Line 542: | Line 575: | ||
**UI** | **UI** | ||
* bpy.types.Panel | * bpy.types.Panel | ||
+ | * the panel display order is determined by the order bpy.utils.register_class processes | ||
* bpy.types.UIList | * bpy.types.UIList | ||
* bpy.types.Operator | * bpy.types.Operator | ||
Line 600: | Line 634: | ||
... | ... | ||
layout.template_list(type_name, | layout.template_list(type_name, | ||
+ | </ | ||
+ | * long label solution and auto wrap <code python> | ||
+ | import bpy | ||
+ | import textwrap | ||
+ | |||
+ | long_text = """ | ||
+ | a long text long text long text | ||
+ | b test | ||
+ | c long text long text long text long text long text long | ||
+ | d text long text long text long text """ | ||
+ | |||
+ | def get_max_label_width(): | ||
+ | # Get the 3D View area | ||
+ | for area in bpy.context.screen.areas: | ||
+ | if area.type == ' | ||
+ | break | ||
+ | # Calculate the width of the panel | ||
+ | panel_width = 280 # default value | ||
+ | for region in area.regions: | ||
+ | if region.type == ' | ||
+ | panel_width = region.width | ||
+ | return panel_width | ||
+ | break | ||
+ | # Calculate the maximum width of the label | ||
+ | uifontscale = 9 * context.preferences.view.ui_scale | ||
+ | max_label_width = int(panel_width // uifontscale) | ||
+ | return max_label_width | ||
+ | |||
+ | def create_long_label(layout, | ||
+ | max_label_width = get_max_label_width() | ||
+ | first_icon_line_done = False | ||
+ | rest_line_indent = indent | ||
+ | if icon == '': | ||
+ | first_icon_line_done = True | ||
+ | rest_line_indent = '' | ||
+ | # Split the text into lines and format each line | ||
+ | for line in long_text.splitlines(): | ||
+ | # Remove leading and trailing whitespace | ||
+ | line = line.strip() | ||
+ | # Split the line into chunks that fit within the maximum label width | ||
+ | for chunk in textwrap.wrap(line, | ||
+ | if not first_icon_line_done: | ||
+ | layout.label(text=chunk, | ||
+ | first_icon_line_done = True | ||
+ | else: | ||
+ | layout.label(text=rest_line_indent+chunk) | ||
+ | |||
+ | class MyPanel(bpy.types.Panel): | ||
+ | bl_idname = " | ||
+ | bl_label = "My Panel" | ||
+ | bl_space_type = " | ||
+ | bl_region_type = " | ||
+ | | ||
+ | def draw(self, context): | ||
+ | layout = self.layout | ||
+ | create_long_label(layout, | ||
+ | | ||
+ | |||
+ | # Register the panel | ||
+ | bpy.utils.register_class(MyPanel) | ||
</ | </ | ||
===== Blender preference ===== | ===== Blender preference ===== |