Overview
When a tool window is open, its buttons, check boxes, number fields and drop-down lists are available to Python. A script can list them, read their values, change them and press buttons, exactly as you do in the window. This article uses the Mesh Healer tool (Mesh Repair › Mesh Healer) as the example.
Run the scripts in the Python window (Home › Python) with a mesh selected in the scene. How to open tabs and tools from a script is explained in Navigating MeshInspector’s UI Tree Programmatically.
Use the window name in the path
The parameters of a tool are inside the entry named after its window, the title shown at the top of the tool window. This is not always the name of the tool button in Ribbon: the button ['Ribbon', 'Object Section'] opens a window titled Section, so its parameters are under ['Section', ...], and the button ['Ribbon', 'Decimate Mesh'] opens the Simplify window. A wrong name stops the script with the error "No such entry", which lists the names that exist.
Listing Tool Parameters
Open the tool and list everything in its window with uiListEntries():
from meshlib import mrviewerpy as mv
# Open the Mesh Repair tab and the Mesh Healer tool
mv.uiPressButton(['RibbonTabs', 'Mesh Repair'])
mv.Viewer().skipFrames(1)
mv.uiPressButton(['Ribbon', 'Mesh Healer'])
mv.Viewer().skipFrames(1)
# List all controls inside the tool window
for entry in mv.uiListEntries(['Mesh Healer']):
print(entry.name, entry.type)
Example output in MeshInspector 2.5.9 (Mesh Healer opens in the Local Repair mode):
##Auto Repair UiEntryType.button
##Local Repair UiEntryType.button
Disconnected Parts UiEntryType.valueUint
Flipped Normals UiEntryType.valueUint
Holes UiEntryType.valueUint
Repair Resolution UiEntryType.valueReal
Repair Selected UiEntryType.button
Restart on Mesh Selection Change UiEntryType.valueUint
Save Selection on Exit UiEntryType.valueUint
Self-Intersections UiEntryType.valueUint
Show Deviation Map UiEntryType.valueUint
Small Tunnels UiEntryType.valueUint
Thin Walls UiEntryType.valueUint
Undercuts UiEntryType.valueUint
Zero-Area Triangles UiEntryType.valueUint
The type tells you which function reads and writes the entry: button is pressed, valueReal is a number with a fraction, valueInt and valueUint are whole numbers (check boxes are valueUint with the values 0 and 1), valueString is text or a drop-down list.
Reading Parameter Values
Each value type has its own reading function. For a number field such as Repair Resolution use uiReadValueReal():
from meshlib import mrviewerpy as mv
val = mv.uiReadValueReal(['Mesh Healer', 'Repair Resolution'])
print("Current value:", val.value, "| Range:", val.min, "-", val.max)
Example output for a small test mesh (the value depends on the size of the mesh):
Current value: 0.004240000154823065 | Range: 0.001154000055976212 - 9.15999984741211
The result has the current value and the limits min and max of the field.
Changing Parameter Values
One function, uiWriteValue(), writes every type of value. It picks the type from the Python value you pass, so write a real number (0.5, 1.0) into a valueReal field: a whole number such as 1 does not change a real-number field. This script halves Repair Resolution and stays inside the allowed range:
from meshlib import mrviewerpy as mv
val = mv.uiReadValueReal(['Mesh Healer', 'Repair Resolution'])
new_val = max(val.min, min(val.max, val.value * 0.5))
mv.uiWriteValue(['Mesh Healer', 'Repair Resolution'], new_val)
mv.Viewer().skipFrames(1)
updated = mv.uiReadValueReal(['Mesh Healer', 'Repair Resolution']).value
print("Updated value:", updated)
Example output:
Updated value: 0.0021200000774115324
Keep the new value within min and max. Read the value back, as in the script, to make sure the change was applied.
Working with Different Value Types
| Field | Read with | Write with |
|---|---|---|
| Real number | uiReadValueReal() |
uiWriteValue() with a float |
| Whole number | uiReadValueInt() |
uiWriteValue() with an int |
| Unsigned number | uiReadValueUint() |
uiWriteValue() with an int |
| Check box | uiReadValueUint() |
uiWriteValue() with 0 or 1 |
| Text, list | uiReadValueString() |
uiWriteValue() with a string |
All functions take the path of the entry; uiWriteValue() takes the new value as the second argument:
val = mv.uiReadValueReal(['Mesh Healer', 'Repair Resolution'])
mv.uiWriteValue(['Mesh Healer', 'Repair Resolution'], val.value * 0.5)
For a check box, 0 means cleared and 1 means checked. Mesh Healer remembers its check boxes when you close and open it again, so a script should set the ones it relies on. This line clears the Holes check box, so Repair Selected leaves holes alone:
mv.uiWriteValue(['Mesh Healer', 'Holes'], 0)
For a text field or a drop-down list, uiReadValueString() returns the value and, for a list, the allowed values; write one of them.
Triggering Actions (Buttons)
Buttons are pressed with uiPressButton(). In the Local Repair mode of Mesh Healer, Repair Selected fixes the problem types whose check boxes are checked. Mesh Healer also remembers its mode, so press the ##Local Repair button first: in the Auto Repair mode there is no Repair Selected.
from meshlib import mrviewerpy as mv
mv.uiPressButton(['Mesh Healer', '##Local Repair'])
mv.uiPressButton(['Mesh Healer', 'Repair Selected'])
mv.Viewer().skipFrames(1)
print("Action 'Repair Selected' triggered.")
This does the same as clicking the button in the window. A button that cannot be used now (for example, Repair Selected with no check box checked) is not pressed: the script continues without an error and only the MeshInspector log gets a warning. Check the status of the button before you rely on it:
from meshlib import mrviewerpy as mv
for entry in mv.uiListEntries(['Mesh Healer']):
if entry.name == 'Repair Selected':
print(entry.name, '->', entry.status)
The status is available, or the reason why the button is unavailable.
Local Repair and Auto Repair. Mesh Healer has two modes, switched with the buttons ##Local Repair and ##Auto Repair of its window. Repair Resolution belongs to both. The problem check boxes and Repair Selected are in Local Repair; Auto Repair rebuilds the whole model with the Auto Rebuild Model button and has its own settings. After you switch the mode, list the window again to see its controls.
Waiting for Long Operations
Inspection and repair can take a while. While an operation runs, the top of the UI tree has an entry named ProgressBar. This function waits until it disappears:
import time
from meshlib import mrviewerpy as mv
def wait_progress_bar():
mv.Viewer().skipFrames(2)
while any(e.name == "ProgressBar" for e in mv.uiListEntries([])):
time.sleep(0.2)
Call it after you open a tool that inspects the mesh (Mesh Healer does) and after you press a button that starts a calculation.
Name Matching and Best Practices
- List before you use. Get the names with
uiListEntries(): the names are exact, including case, spaces and hyphens. - Use the window title for parameters and the internal tool name for
Ribbonbuttons. - Read before you write, so the new value stays within
minandmax. - Pass the right Python type to
uiWriteValue(): a float for real numbers, an int for whole numbers and check boxes, a string for text. - Wait for long operations before you read results or press the next button.
Example: Full Workflow
This script opens Mesh Healer for the selected mesh, halves Repair Resolution, checks Holes, runs Repair Selected and prints the number of holes before and after:
import time
from meshlib import mrviewerpy as mv
def wait_progress_bar():
mv.Viewer().skipFrames(2)
while any(e.name == "ProgressBar" for e in mv.uiListEntries([])):
time.sleep(0.2)
holes_before = mv.getSelectedMeshes()[0].topology.findNumHoles()
# Open the Mesh Repair tab and the Mesh Healer tool
mv.uiPressButton(['RibbonTabs', 'Mesh Repair'])
mv.uiPressButton(['Ribbon', 'Mesh Healer'])
wait_progress_bar()
# Switch to Local Repair (Mesh Healer opens in the mode it was closed in)
mv.uiPressButton(['Mesh Healer', '##Local Repair'])
# Adjust the parameters: halve Repair Resolution, make sure Holes is checked
val = mv.uiReadValueReal(['Mesh Healer', 'Repair Resolution'])
mv.uiWriteValue(['Mesh Healer', 'Repair Resolution'], max(val.min, val.value * 0.5))
mv.uiWriteValue(['Mesh Healer', 'Holes'], 1)
mv.Viewer().skipFrames(1)
# Run the repair and wait for it
mv.uiPressButton(['Mesh Healer', 'Repair Selected'])
wait_progress_bar()
holes_after = mv.getSelectedMeshes()[0].topology.findNumHoles()
print("Holes before:", holes_before, "after:", holes_after)
Example output for a test mesh with two small holes:
Holes before: 2 after: 0