Qt integration for Blender
Project description
blender_qt
Qt integration for Blender with support for:
- custom node-editor spaces backed by QML or
QWidget - viewport gizmos backed by QML or
QWidget - managed top-level Qt windows
Developer-oriented architecture and workaround notes live in docs/developer-guide.md.
Stable public API is exposed from the top-level blender_qt package.
Modules under blender_qt.core, blender_qt.qml, blender_qt.widgets, and blender_qt._internal
should be treated as implementation details unless explicitly documented otherwise.
Installation
pip install blender_qt
The wheel is published for add-on authors who want to depend on Blender Qt from normal Python packaging workflows.
The package can be imported outside Blender for metadata and API discovery, but runtime features still require Blender's Python environment and modules such as bpy.
Sample Extension
See blender_qt_sample/README.md for a sample Blender extension project that uses this wheel and packages it with beb.
That sample uses beb because it is a convenient way to build a Blender extension archive around the local blender_qt wheel. You do not need to use beb for your own Blender Qt-based add-ons unless that workflow fits your packaging needs.
Lifecycle
Call blender_qt.init() before registering spaces, gizmos, or windows.
Call blender_qt.shutdown() when your add-on unloads.
import blender_qt
def register() -> None:
blender_qt.init()
def unregister() -> None:
blender_qt.shutdown()
Register a custom QML space
Use register_qml_space() to add a custom node-editor space rendered from a QML root item.
from pathlib import Path
import blender_qt
TREE_TYPE = "MY_ADDON_QML_NT"
QML_PATH = Path(__file__).with_name("main.qml")
blender_qt.register_qml_space(
tree_type=TREE_TYPE,
label="My QML Space",
qml_path=QML_PATH,
icon="NODETREE",
sidebar_category="My Tools",
)
Unregister a custom space
Use unregister_space() with the same tree_type.
blender_qt.unregister_space("MY_ADDON_QML_NT")
Register a custom widget space
Use register_widget_space() when your UI is a QWidget tree.
from PySide6 import QtWidgets
import blender_qt
class MyWidgetSurface(QtWidgets.QWidget):
def __init__(self, parent: QtWidgets.QWidget | None = None) -> None:
super().__init__(parent)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(QtWidgets.QLabel("Hello from a widget space"))
blender_qt.register_widget_space(
tree_type="MY_ADDON_WIDGET_NT",
label="My Widget Space",
widget_factory=MyWidgetSurface,
icon="NODETREE",
sidebar_category="My Tools",
)
Unregister it the same way:
blender_qt.unregister_space("MY_ADDON_WIDGET_NT")
List active custom spaces:
tree_types = blender_qt.registered_space_types()
Register a QML viewport gizmo
Use register_qml_viewport_gizmo() to render a floating viewport panel from QML.
from pathlib import Path
import blender_qt
blender_qt.register_qml_viewport_gizmo(
gizmo_id="MY_ADDON_QML_GIZMO",
qml_path=Path(__file__).with_name("gizmo.qml"),
space_type="VIEW_3D",
width=320,
height=220,
is_2d=True,
initial_position=(80, 80),
)
3D QML gizmo
Set is_2d=False to anchor the panel in world space.
blender_qt.register_qml_viewport_gizmo(
gizmo_id="MY_ADDON_QML_GIZMO_3D",
qml_path=Path(__file__).with_name("gizmo.qml"),
space_type="VIEW_3D",
width=320,
height=220,
is_2d=False,
initial_3d_position=(0.0, 0.0, 1.0),
billboard=True,
use_depth_test=True,
)
Register a widget viewport gizmo
Use register_widget_viewport_gizmo() to render a floating viewport panel from a QWidget.
from PySide6 import QtWidgets
import blender_qt
class MyViewportPanel(QtWidgets.QWidget):
def __init__(self, parent: QtWidgets.QWidget | None = None) -> None:
super().__init__(parent)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(QtWidgets.QPushButton("Action"))
blender_qt.register_widget_viewport_gizmo(
gizmo_id="MY_ADDON_WIDGET_GIZMO",
widget_factory=MyViewportPanel,
label="My Widget Gizmo",
space_type="VIEW_3D",
width=280,
height=180,
is_2d=True,
initial_position=(120, 120),
)
Unregister a viewport gizmo
Use unregister_viewport_gizmo() with the same gizmo_id.
blender_qt.unregister_viewport_gizmo("MY_ADDON_WIDGET_GIZMO")
List active gizmos:
gizmo_ids = blender_qt.registered_viewport_gizmo_ids()
Managed windows
Use register_window() for standalone top-level windows.
from PySide6 import QtWidgets
import blender_qt
window = QtWidgets.QDialog()
window.setWindowTitle("My Tool")
blender_qt.register_window(window, unique=True)
Optional close callback:
def _on_window_closed(widget: QtWidgets.QWidget) -> None:
print("Closed", widget.objectName())
blender_qt.register_window(window, unique=True, on_close=_on_window_closed)
Get active managed windows:
windows = blender_qt.managed_windows()
Close them all:
blender_qt.close_managed_windows()
Recommended add-on structure
import blender_qt
def register() -> None:
blender_qt.init()
blender_qt.register_qml_space(
tree_type="MY_ADDON_QML_NT",
label="My Space",
qml_path="/path/to/main.qml",
)
blender_qt.register_qml_viewport_gizmo(
gizmo_id="MY_ADDON_GIZMO",
qml_path="/path/to/gizmo.qml",
is_2d=True,
)
def unregister() -> None:
blender_qt.unregister_viewport_gizmo("MY_ADDON_GIZMO")
blender_qt.unregister_space("MY_ADDON_QML_NT")
blender_qt.shutdown()
Notes
tree_typeandgizmo_idmust be unique.- Registering a duplicate space or gizmo raises
ValueError. - Missing QML files raise
FileNotFoundErrorduring registration. - QML viewport gizmos use
is_2dinstead ofmode. - QML viewport gizmos do not use a
labelargument. - Widget viewport gizmos still accept
label, which is used as the host window title. - Use
VIEW_3D,IMAGE_EDITOR,NODE_EDITOR,CLIP_EDITOR, orSEQUENCE_EDITORforspace_typewhere supported by Blender.
Project Layout
blender_qt: importable packagedocs: contributor documentationtests: standalone smoke tests for package metadata and public API imports
Releases
GitHub Actions runs tests and build validation on pushes and pull requests, and publishes tagged releases to PyPI.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file blender_qt-0.4.0.tar.gz.
File metadata
- Download URL: blender_qt-0.4.0.tar.gz
- Upload date:
- Size: 76.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d296c43a632599ebd70eea5223abc7d7e46c5777ea1eb38fad9fc9f0e2a7fa1
|
|
| MD5 |
682bb6c150019887b7bf815d9997996d
|
|
| BLAKE2b-256 |
697e3b0247497fc139ddc318f6686bfd97f8a95238d842d6b2d2de28b35f8950
|
File details
Details for the file blender_qt-0.4.0-py3-none-any.whl.
File metadata
- Download URL: blender_qt-0.4.0-py3-none-any.whl
- Upload date:
- Size: 94.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46f601a6e49ec77937737227a181f9a5a5ee04a13563d094f348d635a1e6b3d0
|
|
| MD5 |
30d73378dfa5529c562d50c08e21e3a5
|
|
| BLAKE2b-256 |
5b35b9744d9df3b4e3d01157f4f551dd6729e84ba806b02c660f9d5ae2e003ce
|