# How to scale an object via a slider in Python?

First: I'm new to Python programming in Blender.

I already know how add a row to scale one single axis of an object by using a slider in the tools panel e.g. I'm using this code snippet to do this:

import bpy # Python API for Blender
from bpy.types import Panel, Operator

# Class for the panel, derived by Panel
class SimpleToolPanel(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_label = 'CW Tools'
bl_context = 'objectmode'
bl_category = 'CW Tools' # Where the Panel have to appear. In this case in the Tools cetegory.

# Add UI elements here
def draw(self, context):
layout = self.layout

# New row
row = layout.row()

# get the selected object
obj = context.object

#Let's display the scale of the object
str_scale = 'Object: ' + obj.name + ' scale: ' + str(obj.scale)

row.label(text=str_scale)

#Add scale slider property
row = layout.row()
row.prop(obj, 'scale', index=0, text='Scale x:')

row = layout.row()
row.prop(obj, 'scale', index=1, text='Scale y:')

row = layout.row()
row.prop(obj, 'scale', index=2, text='Scale z:')

# Register
def register():
bpy.utils.register_class(SimpleToolPanel)

# Unregister
def unregister():
bpy.utils.unregister_class(SimpleToolPanel)

# Run in text editor
if __name__ == "__main__":
register()


My question:

How is the code to resize a complete active object via one single slider, please?

• What happens if you don't mention the index? Will it scale the whole object then? Nov 19 '18 at 15:47
• Sorry. The row scales the x-axis only. I would like to scale all three axis together e.g. Nov 19 '18 at 15:52
• I've replaced the whole code to show you my current version. At the moment I'm able to scale every single axis of an active object. But I would like to scale the whole object by using one single slider only. Nov 19 '18 at 15:57
• @CraigDJones To answer your question: No. I see all three axes at once side by side then. Nov 19 '18 at 16:02

## 2 Answers

Make the current scale "unity" for the scale_factor.

This is a bit of an old chestnut, if a simple scale factor is added such that

ob.scale *= scale_factor


which is how the scale operator works somewhat, everything turns to zero once the scale hits zero... And it also acts geometrically making it very unmanageable very quickly.

As a workaround I've added a boolean to copy the current scale to a vector property and set the scale factor to 1. To reset click the boolean back on and off. (prob should be an operator instead but you get the idea.)

import bpy
from mathutils import Vector
from bpy.types import Panel, Operator
from bpy.props import (FloatProperty,
FloatVectorProperty,
BoolProperty)

class SimpleToolPanel(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_label = 'CW Tools'
bl_context = 'objectmode'
bl_category = 'Tools'

def draw(self, context):
layout = self.layout
row = layout.row()
obj = context.object
row.prop(obj, "scale_set", toggle=True)
if obj.scale_set:
row = layout.row()
row.prop(obj, 'scale_factor')

def scale_set(self, context):
if self.scale_set:
self.scale_vector = self.scale.copy()
self["scale_factor"] = 1

def scale_obj(self, context):
self.scale = self.scale_factor * Vector(self.scale_vector)

def register():
bpy.types.Object.scale_vector = FloatVectorProperty()
bpy.types.Object.scale_set = BoolProperty(
default=False,
update=scale_set)

bpy.types.Object.scale_factor = FloatProperty(
name="Scale Factor",
default=1,
update=scale_obj
)
bpy.utils.register_class(SimpleToolPanel)

def unregister():
bpy.utils.unregister_class(SimpleToolPanel)

if __name__ == "__main__":
register()

• This is a nice solution too. Thank you for your efforts. See my answer above to know what I miss in your code. Nov 20 '18 at 12:32
• IMO the accepted answer is not the way to go.... unless the question is how to make the y and z scale the value of x scale. It scales an object to scale.x * (1, 1, 1,) taking into no account if the object already has non-uniform scale. Eg If the object already has scale.x = 0, then the object becomes scaled to zero. (0, 0, 0) . If an object has scale (3, 0, 0) it gets scaled to (3, 3, 3) If the initial scale is (1, 1, 1) my answer will do same. But if the initial scale is (1, 2, 3) and I scale it by 2 I get (2, 4, 6) which makes sense to me, (2, 2, 2) not so sure. Anyway your question.. Nov 20 '18 at 12:59
• You are completely right. Your solution answers my basic question and scales an object the right way. But both solutions here are a good foundation for myself to work with and learn more. Thank you. Nov 21 '18 at 17:07

Here's the script to do this (open to corrections):

[Edit: Added getVal to reflect current X scale]

import bpy # Python API for Blender
from bpy.types import Panel, Operator

# Class for the panel, derived by Panel
class SimpleToolPanel(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_label = 'CW Tools'
bl_context = 'objectmode'
bl_category = 'CW Tools' # Where the Panel have to appear. In this case in the Tools cetegory.

def setVal(self, val):
self.objects.active.scale[0] = val
self.objects.active.scale[1] = val
self.objects.active.scale[2] = val

#Edit: Pick the value from the X scale, assuming all scale values are the same
def getVal(self):
return self.objects.active.scale[0]

bpy.types.Scene.scaleVal = bpy.props.FloatProperty(set = setVal, get = getVal)

# Add UI elements here
def draw(self, context):
layout = self.layout

# New row
row = layout.row()

# get the selected object
obj = context.object

#Let's display the scale of the object
str_scale = 'Object: ' + obj.name + ' scale: ' + str(obj.scale)

row.label(text=str_scale)

#Add scale slider property

row = layout.row()
row.prop(bpy.context.scene, 'scaleVal', text='Scale:')

# Register
def register():
bpy.utils.register_class(SimpleToolPanel)

# Unregister
def unregister():
bpy.utils.unregister_class(SimpleToolPanel)

# Run in text editor
if __name__ == "__main__":
register()

• Thank you! It's nearly what I was looking for. Now I have to check out how to set the current object scale value before adjusting it with the slider. In your version the slider is always zero and does not read the active object scale before adjusting it. Nov 20 '18 at 8:09
• You are welcome. It's trivial to read the active objects scale. You need to just have another function getVal(self) and set it to get parameter of FloatProperty constructor. But there are going to be three different values. How would you like to combine them? In the edit I am setting it to the first scale value. Assuming all three would be the same. Nov 20 '18 at 9:03
• Exactly. I need just one same value for all parameters (x,y,z). Thank you! Nov 20 '18 at 12:16