Skip to main content

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 the developer guide.

Demo

Blender Qt demo

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 PyPI package name is blender-qt. The top-level Python import package remains 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 the blender_qt_sample repository for a sample Blender extension project that uses this wheel and packages it with beb:

https://github.com/minimalefforttech/blender_qt_sample

That sample uses beb because it is a convenient way to build a Blender extension archive around the published blender-qt PyPI package. 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_type and gizmo_id must be unique.
  • Registering a duplicate space or gizmo raises ValueError.
  • Missing QML files raise FileNotFoundError during registration.
  • QML viewport gizmos use is_2d instead of mode.
  • QML viewport gizmos do not use a label argument.
  • Widget viewport gizmos still accept label, which is used as the host window title.
  • Use VIEW_3D, IMAGE_EDITOR, NODE_EDITOR, CLIP_EDITOR, or SEQUENCE_EDITOR for space_type where supported by Blender.

Project Layout

  • blender_qt: importable package
  • docs: contributor documentation
  • tests: 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

blender_qt-0.4.2.tar.gz (76.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

blender_qt-0.4.2-py3-none-any.whl (93.8 kB view details)

Uploaded Python 3

File details

Details for the file blender_qt-0.4.2.tar.gz.

File metadata

  • Download URL: blender_qt-0.4.2.tar.gz
  • Upload date:
  • Size: 76.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for blender_qt-0.4.2.tar.gz
Algorithm Hash digest
SHA256 8469cea3394fe6fa7e35c4392bc36c6a2d92a5f4c1d945fad61b3e034e5a1f08
MD5 4b8ed5ac2d3f01ed805cb6d0729af090
BLAKE2b-256 2d2ae7b36db0f5b4187902116b6ac5fb7a40da44dcdc92eed8e0e20e8cc97aa8

See more details on using hashes here.

Provenance

The following attestation bundles were made for blender_qt-0.4.2.tar.gz:

Publisher: publish.yml on minimalefforttech/blender_qt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file blender_qt-0.4.2-py3-none-any.whl.

File metadata

  • Download URL: blender_qt-0.4.2-py3-none-any.whl
  • Upload date:
  • Size: 93.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for blender_qt-0.4.2-py3-none-any.whl
Algorithm Hash digest
SHA256 588c9e03efbd532ed944e7158daad55ad5f88ed184067ea33cbac3b2e4f17676
MD5 e99a23209773d6882b93c261d681832f
BLAKE2b-256 0bbb07e7a61a571691f8fdbb35faa45b06089ed154b95134154fa13b1272151e

See more details on using hashes here.

Provenance

The following attestation bundles were made for blender_qt-0.4.2-py3-none-any.whl:

Publisher: publish.yml on minimalefforttech/blender_qt

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page