slint
Slint-python (Beta)
Slint is a UI toolkit that supports different programming languages. Slint-python is the integration with Python.
Warning Slint-python is in a beta phase of development: The APIs while mostly stable, may be subject to further changes. Any changes will be documented in the ChangeLog.
You can track the progress for the Python integration by looking at python-labelled issues at https://github.com/slint-ui/slint/labels/a%3Alanguage-python .
Slint Language Manual
The Slint Language Documentation covers the Slint UI description language in detail.
Prerequisites
Installation
Install Slint with uv or pip from the Python Package Index:
uv add slint
The installation uses binaries provided for macOS, Windows, and Linux for various architectures. If your target platform
is not covered by binaries, uv will automatically build Slint from source. If that happens, you will then need some
software development tools on your machine, as well as Rust.
Quick Start
- Create a new project with
uv init. - Add the Slint Python package to your Python project:
uv add slint - Create a file called
app-window.slint:
import { Button, VerticalBox } from "std-widgets.slint";
export component AppWindow inherits Window {
in-out property<int> counter: 42;
callback request-increase-value();
VerticalBox {
Text {
text: "Counter: \{root.counter}";
}
Button {
text: "Increase value";
clicked => {
root.request-increase-value();
}
}
}
}
- Create a file called
main.py:
import slint
# slint.loader will look in `sys.path` for `app-window.slint`.
class App(slint.loader.app_window.AppWindow):
@slint.callback
def request_increase_value(self):
self.counter = self.counter + 1
app = App()
app.run()
- Run it with
uv run main.py
API Overview
Instantiating a Component
The following example shows how to instantiate a Slint component in Python:
app.slint
export component MainWindow inherits Window {
callback clicked <=> i-touch-area.clicked;
in property <int> counter;
width: 400px;
height: 200px;
i-touch-area := TouchArea {}
}
The exported component is exposed as a Python class. To access this class, you have two options:
Call
slint.load_file("app.slint"). The returned object is a namespace, that provides theMainWindowclass as well as any other explicitly exported component that inheritsWindow:import slint components = slint.load_file("app.slint") main_window = components.MainWindow()Use Slint's auto-loader, which lazily loads
.slintfiles fromsys.path:import slint # Look for for `app.slint` in `sys.path`: main_window = slint.loader.app.MainWindow()Any attribute lookup in
slint.loaderis searched for insys.path. If a directory with the name exists, it is returned as a loader object, and subsequent attribute lookups follow the same logic.If the name matches a file with the
.slintextension, it is automatically loaded withload_fileand the namespace is returned.If the file name contains a dash, like
app-window.slint, an attribute lookup forapp_windowtries to locateapp_window.slintand then fall back toapp-window.slint.
Accessing Properties
Properties declared as out or in-out in .slint files are visible as
properties on the component instance.
main_window.counter = 42
print(main_window.counter)
Accessing Globals
Global Singletons are accessible in Python as properties in the component instance.
For example, this Slint code declares a PrinterJobQueue singleton:
export global PrinterJobQueue {
in-out property <int> job-count;
}
Access it as a property on the component instance by its name:
print("job count:", instance.PrinterJobQueue.job_count)
Note: Global singletons are instantiated once per component. When declaring multiple components for export to Python,
each instance has their own associated globals singletons.
Setting and Invoking Callbacks
Callbacks declared in .slint files are visible as callable properties on the component
instance. Invoke them as functions to invoke the callback, and assign Python callables to set the callback handler.
In Slint, callbacks are defined using the callback keyword and can be connected to another component's callback using
the <=> syntax.
my-component.slint
export component MyComponent inherits Window {
callback clicked <=> i-touch-area.clicked;
width: 400px;
height: 200px;
i-touch-area := TouchArea {}
}
The callbacks in Slint are exposed as properties and that can be called as functions.
main.py
import slint
component = slint.loader.my_component.MyComponent()
# connect to a callback
def clicked():
print("hello")
component.clicked = clicked
// invoke a callback
component.clicked();
Another way to set callbacks is to sub-class and use the @slint.callback decorator:
import slint
class Component(slint.loader.my_component.MyComponent):
@slint.callback
def clicked(self):
print("hello")
component = Component()
The @slint.callback() decorator accepts a name argument, if the name of the method does not match the name of the
callback in the .slint file. Similarly, a global_name argument can be used to bind a method to a callback in a global
singleton.
Type Mappings
Each type used for properties in the Slint Language translates to a specific type in Python. The following table summarizes the mapping:
.slint Type |
Python Type | Notes |
|---|---|---|
int |
int |
|
float |
float |
|
string |
str |
|
color |
slint.Color |
|
brush |
slint.Brush |
|
image |
slint.Image |
|
length |
float |
|
physical_length |
float |
|
duration |
float |
The number of milliseconds |
angle |
float |
The angle in degrees |
| structure | dict/Struct |
When reading, structures are mapped to data classes, when writing dicts are also accepted. |
| array | slint.Model |
Arrays and Models
You can set array properties from Python by passing subclasses of
slint.Model.
Use the slint.ListModel class to construct a model from an iterable:
component.model = slint.ListModel([1, 2, 3]);
component.model.append(4)
del component.model[0]
When sub-classing slint.Model, provide the following methods:
def row_count(self):
"""Return the number of rows in your model"""
def row_data(self, row):
"""Return data at specified row"""
def set_row_data(self, row, data):
"""For read-write models, store data in the given row. When done call set.notify_row_changed:"
..."""
self.notify_row_changed(row)
When adding or inserting rows, call notify_row_added(row, count) on the super class. Similarly, when removing rows, notify
Slint by calling notify_row_removed(row, count).
Structs
Structs declared in Slint and exposed to Python via export are then accessible in the namespace that is returned
when instantiating a component.
app.slint
export struct MyData {
name: string,
age: int
}
export component MainWindow inherits Window {
in-out property <MyData> data;
}
main.py
The exported MyData struct can be constructed as follows:
import slint
# Look for for `app.slint` in `sys.path`:
main_window = slint.loader.app.MainWindow()
data = slint.loader.app.MyData(name = "Simon")
data.age = 10
main_window.data = data
Enums
Enums declared in Slint and exposed to Python via export are then accessible in the namespace that is returned
when instantiating a component. The enums are subclasses of enum.Enum.
app.slint
export enum MyOption {
Variant1,
Variant2
}
export component MainWindow inherits Window {
in-out property <MyOption> data;
}
main.py
Variants of the exported MyOption enum can be constructed as follows:
import slint
# Look for for `app.slint` in `sys.path`:
main_window = slint.loader.app.MainWindow()
value = slint.loader.app.MyOption.Variant2
main_window.data = value
Asynchronous I/O
Use Python's asyncio library to write concurrent Python code with the async/await syntax.
Slint's event loop is a full-featured asyncio event loop. While
the event loop is running, asyncio.get_event_loop() returns
a valid loop. To run an async function when starting the loop, pass a coroutine to slint.run_event_loop().
For the common use case of interacting with REST APIs, we recommend the aiohttp library.
Known Limitations
- Pipes and sub-processes are only supported on Unix-like platforms.
Type Hints
PEP 484 introduces a standard syntax for type annotations to Python, enabling static analysis for type checking, refactoring, and code completion. Popular type checkers include mypy, Pyre, and Astral's ty.
Use Slint's slint-compiler to generate stub .py files for .slint files, which are annotated with
type information. These replace the need to call load_file or any use of slint.loader.
- Create a new project with
uv init. - Add the Slint Python package to your Python project:
uv add slint - Create a file called
app-window.slint:
import { Button, VerticalBox } from "std-widgets.slint";
export component AppWindow inherits Window {
in-out property<int> counter: 42;
callback request-increase-value();
VerticalBox {
Text {
text: "Counter: \{root.counter}";
}
Button {
text: "Increase value";
clicked => {
root.request-increase-value();
}
}
}
}
Run the slint-compiler to generate
app_window.py:uvx slint-compiler -f python -o app_window.py app-window.slintCreate a file called
main.py:
import slint
import app_window
class App(app_window.AppWindow):
@slint.callback
def request_increase_value(self):
self.counter = self.counter + 1
app = App()
app.run()
- Run it with
uv run main.py
Third-Party Licenses
For a list of the third-party licenses of all dependencies, see the separate Third-Party Licenses page.
1# Copyright © SixtyFPS GmbH <[email protected]> 2# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 3 4r""" 5.. include:: ../README.md 6""" 7 8import os 9import sys 10from . import slint as native 11import types 12import logging 13import copy 14import typing 15from typing import Any 16import pathlib 17from .models import ListModel, Model 18from .slint import Image, Color, Brush, Timer, TimerMode 19from .loop import SlintEventLoop 20from pathlib import Path 21from collections.abc import Coroutine 22import asyncio 23import gettext 24import gzip 25import base64 26 27Struct = native.PyStruct 28 29 30class CompileError(Exception): 31 message: str 32 """The error message that produced this compile error.""" 33 34 diagnostics: list[native.PyDiagnostic] 35 """A list of detailed diagnostics that were produced as part of the compilation.""" 36 37 def __init__(self, message: str, diagnostics: list[native.PyDiagnostic]): 38 """@private""" 39 super().__init__(message) 40 self.message = message 41 self.diagnostics = diagnostics 42 for diag in self.diagnostics: 43 self.add_note(str(diag)) 44 45 46class Component: 47 """Component is the base class for all instances of Slint components. Use the member functions to show or hide the 48 window, or spin the event loop.""" 49 50 __instance__: native.ComponentInstance 51 52 def show(self) -> None: 53 """Shows the window on the screen.""" 54 55 self.__instance__.show() 56 57 def hide(self) -> None: 58 """Hides the window from the screen.""" 59 60 self.__instance__.hide() 61 62 def run(self) -> None: 63 """Shows the window, runs the event loop, hides it when the loop is quit, and returns.""" 64 self.show() 65 run_event_loop() 66 self.hide() 67 68 69def _normalize_prop(name: str) -> str: 70 return name.replace("-", "_") 71 72 73def _build_global_class(compdef: native.ComponentDefinition, global_name: str) -> Any: 74 properties_and_callbacks = {} 75 76 for prop_name in compdef.global_properties(global_name).keys(): 77 python_prop = _normalize_prop(prop_name) 78 if python_prop in properties_and_callbacks: 79 logging.warning(f"Duplicated property {prop_name}") 80 continue 81 82 def mk_setter_getter(prop_or_callback_name: str) -> property: 83 def getter(self: Component) -> Any: 84 return self.__instance__.get_global_property( 85 global_name, prop_or_callback_name 86 ) 87 88 def setter(self: Component, value: Any) -> None: 89 self.__instance__.set_global_property( 90 global_name, prop_or_callback_name, value 91 ) 92 93 return property(getter, setter) 94 95 properties_and_callbacks[python_prop] = mk_setter_getter(prop_name) 96 97 for callback_name in compdef.global_callbacks(global_name): 98 python_prop = _normalize_prop(callback_name) 99 if python_prop in properties_and_callbacks: 100 logging.warning(f"Duplicated property {prop_name}") 101 continue 102 103 def mk_setter_getter(prop_or_callback_name: str) -> property: 104 def getter(self: Component) -> typing.Callable[..., Any]: 105 def call(*args: Any) -> Any: 106 return self.__instance__.invoke_global( 107 global_name, prop_or_callback_name, *args 108 ) 109 110 return call 111 112 def setter(self: Component, value: typing.Callable[..., Any]) -> None: 113 self.__instance__.set_global_callback( 114 global_name, prop_or_callback_name, value 115 ) 116 117 return property(getter, setter) 118 119 properties_and_callbacks[python_prop] = mk_setter_getter(callback_name) 120 121 for function_name in compdef.global_functions(global_name): 122 python_prop = _normalize_prop(function_name) 123 if python_prop in properties_and_callbacks: 124 logging.warning(f"Duplicated function {prop_name}") 125 continue 126 127 def mk_getter(function_name: str) -> property: 128 def getter(self: Component) -> typing.Callable[..., Any]: 129 def call(*args: Any) -> Any: 130 return self.__instance__.invoke_global( 131 global_name, function_name, *args 132 ) 133 134 return call 135 136 return property(getter) 137 138 properties_and_callbacks[python_prop] = mk_getter(function_name) 139 140 return type("SlintGlobalClassWrapper", (), properties_and_callbacks) 141 142 143def _build_class( 144 compdef: native.ComponentDefinition, 145) -> typing.Callable[..., Component]: 146 def cls_init(self: Component, **kwargs: Any) -> Any: 147 self.__instance__ = compdef.create() 148 for name, value in self.__class__.__dict__.items(): 149 if hasattr(value, "slint.callback"): 150 callback_info = getattr(value, "slint.callback") 151 name = callback_info["name"] 152 153 is_async = getattr(value, "slint.async", False) 154 if is_async: 155 if "global_name" in callback_info: 156 global_name = callback_info["global_name"] 157 is_void = compdef.global_callback_returns_void( 158 global_name, name 159 ) 160 if is_void is None: 161 raise AttributeError( 162 f"Callback '{name}' in global '{global_name}' cannot be used with a callback decorator for an async function, as it is not declared in Slint component" 163 ) 164 if not is_void: 165 raise RuntimeError( 166 f"Callback '{name}' in global '{global_name}' cannot be used with a callback decorator for an async function, as it doesn't return void" 167 ) 168 else: 169 is_void = compdef.callback_returns_void(name) 170 if is_void is None: 171 raise AttributeError( 172 f"Callback '{name}' cannot be used with a callback decorator for an async function, as it is not declared in Slint component" 173 ) 174 if not is_void: 175 raise RuntimeError( 176 f"Callback '{name}' cannot be used with a callback decorator for an async function, as it doesn't return void" 177 ) 178 179 def mk_callback( 180 self: Any, callback: typing.Callable[..., Any] 181 ) -> typing.Callable[..., Any]: 182 def invoke(*args: Any, **kwargs: Any) -> Any: 183 return callback(self, *args, **kwargs) 184 185 return invoke 186 187 if "global_name" in callback_info: 188 self.__instance__.set_global_callback( 189 callback_info["global_name"], name, mk_callback(self, value) 190 ) 191 else: 192 self.__instance__.set_callback(name, mk_callback(self, value)) 193 194 for prop, val in kwargs.items(): 195 setattr(self, prop, val) 196 197 properties_and_callbacks: dict[Any, Any] = {"__init__": cls_init} 198 199 for prop_name in compdef.properties.keys(): 200 python_prop = _normalize_prop(prop_name) 201 if python_prop in properties_and_callbacks: 202 logging.warning(f"Duplicated property {prop_name}") 203 continue 204 205 def mk_setter_getter(prop_or_callback_name: str) -> property: 206 def getter(self: Component) -> Any: 207 return self.__instance__.get_property(prop_or_callback_name) 208 209 def setter(self: Component, value: Any) -> None: 210 self.__instance__.set_property(prop_or_callback_name, value) 211 212 return property(getter, setter) 213 214 properties_and_callbacks[python_prop] = mk_setter_getter(prop_name) 215 216 for callback_name in compdef.callbacks: 217 python_prop = _normalize_prop(callback_name) 218 if python_prop in properties_and_callbacks: 219 logging.warning(f"Duplicated property {prop_name}") 220 continue 221 222 def mk_setter_getter(prop_or_callback_name: str) -> property: 223 def getter(self: Component) -> typing.Callable[..., Any]: 224 def call(*args: Any) -> Any: 225 return self.__instance__.invoke(prop_or_callback_name, *args) 226 227 return call 228 229 def setter(self: Component, value: typing.Callable[..., Any]) -> None: 230 self.__instance__.set_callback(prop_or_callback_name, value) 231 232 return property(getter, setter) 233 234 properties_and_callbacks[python_prop] = mk_setter_getter(callback_name) 235 236 for function_name in compdef.functions: 237 python_prop = _normalize_prop(function_name) 238 if python_prop in properties_and_callbacks: 239 logging.warning(f"Duplicated function {prop_name}") 240 continue 241 242 def mk_getter(function_name: str) -> property: 243 def getter(self: Component) -> typing.Callable[..., Any]: 244 def call(*args: Any) -> Any: 245 return self.__instance__.invoke(function_name, *args) 246 247 return call 248 249 return property(getter) 250 251 properties_and_callbacks[python_prop] = mk_getter(function_name) 252 253 for global_name in compdef.globals: 254 global_class = _build_global_class(compdef, global_name) 255 256 def mk_global(global_class: typing.Callable[..., Any]) -> property: 257 def global_getter(self: Component) -> Any: 258 wrapper = global_class() 259 setattr(wrapper, "__instance__", self.__instance__) 260 return wrapper 261 262 return property(global_getter) 263 264 properties_and_callbacks[global_name] = mk_global(global_class) 265 266 return type("SlintClassWrapper", (Component,), properties_and_callbacks) 267 268 269def _build_struct(name: str, struct_prototype: native.PyStruct) -> type: 270 def new_struct(cls: Any, *args: Any, **kwargs: Any) -> native.PyStruct: 271 inst = copy.copy(struct_prototype) 272 273 for prop, val in kwargs.items(): 274 setattr(inst, prop, val) 275 276 return inst 277 278 type_dict = { 279 "__new__": new_struct, 280 } 281 282 return type(name, (), type_dict) 283 284 285def _load_file( 286 path: str | os.PathLike[Any] | pathlib.Path, 287 quiet: bool = False, 288 style: typing.Optional[str] = None, 289 include_paths: typing.Optional[typing.List[os.PathLike[Any] | pathlib.Path]] = None, 290 library_paths: typing.Optional[ 291 typing.Dict[str, os.PathLike[Any] | pathlib.Path] 292 ] = None, 293 translation_domain: typing.Optional[str] = None, 294) -> typing.Tuple[types.SimpleNamespace, native.CompilationResult]: 295 """This function is the low-level entry point into Slint for instantiating components. It loads the `.slint` file at 296 the specified `path` and returns a namespace with all exported components as Python classes, as well as enums, and structs. 297 298 * `quiet`: Set to true to prevent any warnings during compilation from being printed to stderr. 299 * `style`: Specify a widget style. 300 * `include_paths`: Additional include paths used to look up `.slint` files imported from other `.slint` files. 301 * `library_paths`: A dictionary that maps library names to their location in the file system. This is then used to look up 302 library imports, such as `import { MyButton } from "@mylibrary";`. 303 * `translation_domain`: The domain to use for looking up the catalogue run-time translations. This must match the 304 translation domain used when extracting translations with `slint-tr-extractor`. 305 306 """ 307 308 compiler = native.Compiler() 309 310 if style is not None: 311 compiler.style = style 312 if include_paths is not None: 313 compiler.include_paths = include_paths 314 if library_paths is not None: 315 compiler.library_paths = library_paths 316 if translation_domain is not None: 317 compiler.translation_domain = translation_domain 318 319 result = compiler.build_from_path(Path(path)) 320 321 diagnostics = result.diagnostics 322 if diagnostics: 323 if not quiet: 324 for diag in diagnostics: 325 if diag.level == native.DiagnosticLevel.Warning: 326 logging.warning(diag) 327 328 errors = [ 329 diag for diag in diagnostics if diag.level == native.DiagnosticLevel.Error 330 ] 331 if errors: 332 raise CompileError(f"Could not compile {path}", diagnostics) 333 334 module = types.SimpleNamespace() 335 for comp_name in result.component_names: 336 wrapper_class = _build_class(result.component(comp_name)) 337 338 setattr(module, comp_name, wrapper_class) 339 340 structs, enums = result.structs_and_enums 341 342 for name, struct_prototype in structs.items(): 343 name = _normalize_prop(name) 344 struct_wrapper = _build_struct(name, struct_prototype) 345 setattr(module, name, struct_wrapper) 346 347 for name, enum_class in enums.items(): 348 name = _normalize_prop(name) 349 setattr(module, name, enum_class) 350 351 for orig_name, new_name in result.named_exports: 352 orig_name = _normalize_prop(orig_name) 353 new_name = _normalize_prop(new_name) 354 setattr(module, new_name, getattr(module, orig_name)) 355 356 return (module, result) 357 358 359def load_file( 360 path: str | os.PathLike[Any] | pathlib.Path, 361 quiet: bool = False, 362 style: typing.Optional[str] = None, 363 include_paths: typing.Optional[typing.List[os.PathLike[Any] | pathlib.Path]] = None, 364 library_paths: typing.Optional[ 365 typing.Dict[str, os.PathLike[Any] | pathlib.Path] 366 ] = None, 367 translation_domain: typing.Optional[str] = None, 368) -> types.SimpleNamespace: 369 """This function is the low-level entry point into Slint for instantiating components. It loads the `.slint` file at 370 the specified `path` and returns a namespace with all exported components as Python classes, as well as enums, and structs. 371 372 * `quiet`: Set to true to prevent any warnings during compilation from being printed to stderr. 373 * `style`: Specify a widget style. 374 * `include_paths`: Additional include paths used to look up `.slint` files imported from other `.slint` files. 375 * `library_paths`: A dictionary that maps library names to their location in the file system. This is then used to look up 376 library imports, such as `import { MyButton } from "@mylibrary";`. 377 * `translation_domain`: The domain to use for looking up the catalogue run-time translations. This must match the 378 translation domain used when extracting translations with `slint-tr-extractor`. 379 380 """ 381 382 return _load_file( 383 path, quiet, style, include_paths, library_paths, translation_domain 384 )[0] 385 386 387def _load_file_checked( 388 path: str | os.PathLike[Any] | pathlib.Path, 389 expected_api_base64_compressed: str, 390 generated_file: str | os.PathLike[Any] | pathlib.Path, 391) -> types.SimpleNamespace: 392 """@private""" 393 394 module, compilation_result = _load_file(path) 395 396 expected_api = gzip.decompress( 397 base64.standard_b64decode(expected_api_base64_compressed) 398 ).decode("utf-8") 399 400 generated_api_module = native.GeneratedAPI(path=generated_file, json=expected_api) 401 actual_api_module = compilation_result.generated_api 402 403 generated_api_module.compare_generated_vs_actual( 404 generated=generated_api_module, actual=actual_api_module 405 ) 406 407 return module 408 409 410class SlintAutoLoader: 411 def __init__(self, base_dir: Path | None = None): 412 self.local_dirs: typing.List[Path] | None = None 413 if base_dir: 414 self.local_dirs = [base_dir] 415 416 def __getattr__(self, name: str) -> Any: 417 for path in self.local_dirs or sys.path: 418 dir_candidate = Path(path) / name 419 if os.path.isdir(dir_candidate): 420 loader = SlintAutoLoader(dir_candidate) 421 setattr(self, name, loader) 422 return loader 423 424 file_candidate = dir_candidate.with_suffix(".slint") 425 if os.path.isfile(file_candidate): 426 type_namespace = load_file(file_candidate) 427 setattr(self, name, type_namespace) 428 return type_namespace 429 430 dir_candidate = Path(path) / name.replace("_", "-") 431 file_candidate = dir_candidate.with_suffix(".slint") 432 if os.path.isfile(file_candidate): 433 type_namespace = load_file(file_candidate) 434 setattr(self, name, type_namespace) 435 return type_namespace 436 437 return None 438 439 440loader = SlintAutoLoader() 441"""Use the global `loader` object to load Slint files from the file system. It exposes two stages of attributes: 4421. Any lookup of an attribute in the loader tries to match a file in `sys.path` with the `.slint` extension. For example 443 `loader.my_component` looks for a file `my_component.slint` in the directories in `sys.path`. 4442. Any lookup in the object returned by the first stage tries to match an exported component in the loaded file, or a 445 struct, or enum. For example `loader.my_component.MyComponent` looks for an *exported* component named `MyComponent` 446 in the file `my_component.slint`. 447 448**Note:** The first entry in the module search path `sys.path` is the directory that contains the input script. 449 450Example: 451```python 452import slint 453# Look for a file `main.slint` in the current directory, 454# #load & compile it, and instantiate the exported `MainWindow` component 455main_window = slint.loader.main_window.MainWindow() 456main_window.show() 457... 458``` 459""" 460 461 462def _callback_decorator( 463 callable: typing.Callable[..., Any], info: typing.Dict[str, Any] 464) -> typing.Callable[..., Any]: 465 if "name" not in info: 466 info["name"] = typing.cast(Any, callable).__name__ 467 setattr(callable, "slint.callback", info) 468 469 try: 470 import inspect 471 472 if inspect.iscoroutinefunction(callable): 473 474 def run_as_task(*args, **kwargs) -> None: # type: ignore 475 loop = asyncio.get_event_loop() 476 loop.create_task(callable(*args, **kwargs)) 477 478 setattr(run_as_task, "slint.callback", info) 479 setattr(run_as_task, "slint.async", True) 480 return run_as_task 481 except ImportError: 482 pass 483 484 return callable 485 486 487def callback( 488 global_name: typing.Callable[..., Any] | str | None = None, name: str | None = None 489) -> typing.Callable[..., Any]: 490 """Use the callback decorator to mark a method as a callback that can be invoked from the Slint component. 491 492 For the decorator to work, the method must be a member of a class that is Slint component. 493 494 Example: 495 ```python 496 import slint 497 498 class AppMainWindow(slint.loader.main_window.MainWindow): 499 500 # Automatically connected to a callback button_clicked() 501 # in main_window.slint's MainWindow. 502 @slint.callback() 503 def button_clicked(self): 504 print("Button clicked") 505 506 ... 507 ``` 508 509 If your Python method has a different name from the Slint component's callback, use the `name` parameter to specify 510 the correct name. Similarly, use the `global_name` parameter to specify the name of the correct global singleton in 511 the Slint component. 512 513 **Note:** The callback decorator can also be used with async functions. They will be run as task in the asyncio event loop. 514 This is only supported for callbacks that don't return any value, and requires Python >= 3.13. 515 """ 516 517 if callable(global_name): 518 callback = global_name 519 return _callback_decorator(callback, {}) 520 else: 521 info = {} 522 if name: 523 info["name"] = name 524 if global_name: 525 info["global_name"] = global_name 526 return lambda callback: _callback_decorator(callback, info) 527 528 529def set_xdg_app_id(app_id: str) -> None: 530 """Sets the application id for use on Wayland or X11 with [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/) 531 compliant window managers. This id must be set before the window is shown; it only applies to Wayland or X11.""" 532 533 native.set_xdg_app_id(app_id) 534 535 536quit_event = asyncio.Event() 537 538 539def run_event_loop( 540 main_coro: typing.Optional[Coroutine[None, None, None]] = None, 541) -> None: 542 """Runs the main Slint event loop. If specified, the coroutine `main_coro` is run in parallel. The event loop doesn't 543 terminate when the coroutine finishes, it terminates when calling `quit_event_loop()`. 544 545 Example: 546 ```python 547 import slint 548 549 ... 550 image_model: slint.ListModel[slint.Image] = slint.ListModel() 551 ... 552 553 async def main_receiver(image_model: slint.ListModel) -> None: 554 async with aiohttp.ClientSession() as session: 555 async with session.get("http://some.server/svg-image") as response: 556 svg = await response.read() 557 image = slint.Image.from_svg_data(svg) 558 image_model.append(image) 559 560 ... 561 slint.run_event_loop(main_receiver(image_model)) 562 ``` 563 564 """ 565 566 async def run_inner() -> None: 567 global quit_event 568 loop = typing.cast(SlintEventLoop, asyncio.get_event_loop()) 569 570 quit_task = asyncio.ensure_future(quit_event.wait(), loop=loop) 571 572 tasks: typing.List[asyncio.Task[typing.Any]] = [quit_task] 573 574 main_task = None 575 if main_coro: 576 main_task = loop.create_task(main_coro) 577 tasks.append(main_task) 578 579 done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) 580 581 if main_task is not None and main_task in done: 582 main_task.result() # propagate exception if thrown 583 if quit_task in pending: 584 await quit_event.wait() 585 586 global quit_event 587 quit_event = asyncio.Event() 588 asyncio.run(run_inner(), debug=False, loop_factory=SlintEventLoop) 589 590 591def quit_event_loop() -> None: 592 """Quits the running event loop in the next event processing cycle. This will make an earlier call to `run_event_loop()` 593 return.""" 594 global quit_event 595 quit_event.set() 596 597 598def init_translations(translations: typing.Optional[gettext.GNUTranslations]) -> None: 599 """Installs the specified translations object to handle translations originating from the Slint code. 600 601 Example: 602 ```python 603 import gettext 604 import slint 605 606 translations_dir = os.path.join(os.path.dirname(__file__), "lang") 607 try: 608 translations = gettext.translation("my_app", translations_dir, ["de"]) 609 slint.install_translations(translations) 610 except OSError: 611 pass 612 ``` 613 """ 614 native.init_translations(translations) 615 616 617__all__ = [ 618 "CompileError", 619 "Component", 620 "load_file", 621 "_load_file_checked", 622 "loader", 623 "Image", 624 "Color", 625 "Brush", 626 "Model", 627 "ListModel", 628 "Timer", 629 "TimerMode", 630 "set_xdg_app_id", 631 "callback", 632 "run_event_loop", 633 "quit_event_loop", 634 "init_translations", 635]
31class CompileError(Exception): 32 message: str 33 """The error message that produced this compile error.""" 34 35 diagnostics: list[native.PyDiagnostic] 36 """A list of detailed diagnostics that were produced as part of the compilation.""" 37 38 def __init__(self, message: str, diagnostics: list[native.PyDiagnostic]): 39 """@private""" 40 super().__init__(message) 41 self.message = message 42 self.diagnostics = diagnostics 43 for diag in self.diagnostics: 44 self.add_note(str(diag))
Common base class for all non-exit exceptions.
47class Component: 48 """Component is the base class for all instances of Slint components. Use the member functions to show or hide the 49 window, or spin the event loop.""" 50 51 __instance__: native.ComponentInstance 52 53 def show(self) -> None: 54 """Shows the window on the screen.""" 55 56 self.__instance__.show() 57 58 def hide(self) -> None: 59 """Hides the window from the screen.""" 60 61 self.__instance__.hide() 62 63 def run(self) -> None: 64 """Shows the window, runs the event loop, hides it when the loop is quit, and returns.""" 65 self.show() 66 run_event_loop() 67 self.hide()
Component is the base class for all instances of Slint components. Use the member functions to show or hide the window, or spin the event loop.
360def load_file( 361 path: str | os.PathLike[Any] | pathlib.Path, 362 quiet: bool = False, 363 style: typing.Optional[str] = None, 364 include_paths: typing.Optional[typing.List[os.PathLike[Any] | pathlib.Path]] = None, 365 library_paths: typing.Optional[ 366 typing.Dict[str, os.PathLike[Any] | pathlib.Path] 367 ] = None, 368 translation_domain: typing.Optional[str] = None, 369) -> types.SimpleNamespace: 370 """This function is the low-level entry point into Slint for instantiating components. It loads the `.slint` file at 371 the specified `path` and returns a namespace with all exported components as Python classes, as well as enums, and structs. 372 373 * `quiet`: Set to true to prevent any warnings during compilation from being printed to stderr. 374 * `style`: Specify a widget style. 375 * `include_paths`: Additional include paths used to look up `.slint` files imported from other `.slint` files. 376 * `library_paths`: A dictionary that maps library names to their location in the file system. This is then used to look up 377 library imports, such as `import { MyButton } from "@mylibrary";`. 378 * `translation_domain`: The domain to use for looking up the catalogue run-time translations. This must match the 379 translation domain used when extracting translations with `slint-tr-extractor`. 380 381 """ 382 383 return _load_file( 384 path, quiet, style, include_paths, library_paths, translation_domain 385 )[0]
This function is the low-level entry point into Slint for instantiating components. It loads the .slint file at
the specified path and returns a namespace with all exported components as Python classes, as well as enums, and structs.
quiet: Set to true to prevent any warnings during compilation from being printed to stderr.style: Specify a widget style.include_paths: Additional include paths used to look up.slintfiles imported from other.slintfiles.library_paths: A dictionary that maps library names to their location in the file system. This is then used to look up library imports, such asimport { MyButton } from "@mylibrary";.translation_domain: The domain to use for looking up the catalogue run-time translations. This must match the translation domain used when extracting translations withslint-tr-extractor.
Use the global loader object to load Slint files from the file system. It exposes two stages of attributes:
- Any lookup of an attribute in the loader tries to match a file in
sys.pathwith the.slintextension. For exampleloader.my_componentlooks for a filemy_component.slintin the directories insys.path. - Any lookup in the object returned by the first stage tries to match an exported component in the loaded file, or a
struct, or enum. For example
loader.my_component.MyComponentlooks for an exported component namedMyComponentin the filemy_component.slint.
Note: The first entry in the module search path sys.path is the directory that contains the input script.
Example:
import slint
# Look for a file `main.slint` in the current directory,
# #load & compile it, and instantiate the exported `MainWindow` component
main_window = slint.loader.main_window.MainWindow()
main_window.show()
...
Image objects can be set on Slint Image elements for display. Use Image.load_from_path to construct Image
objects from a path to an image file on disk.
Loads the image from the specified path. Returns None if the image can't be loaded.
Creates a new image from a string that describes the image in SVG format.
Creates a new image from an array-like object that implements the Buffer Protocol. Use this function to import images created by third-party modules such as matplotlib or Pillow.
The array must satisfy certain contraints to represent an image:
- The buffer's format needs to be
B(unsigned char) - The shape must be a tuple of (height, width, bytes-per-pixel)
- If a stride is defined, the row stride must be equal to width * bytes-per-pixel, and the column stride must equal the bytes-per-pixel.
- A value of 3 for bytes-per-pixel is interpreted as RGB image, a value of 4 means RGBA.
The image is created by performing a deep copy of the array's data. Subsequent changes to the buffer are not automatically reflected in a previously created Image.
Example of importing a matplot figure into an image:
import slint
import matplotlib
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.figure import Figure
fig = Figure(figsize=(5, 4), dpi=100)
canvas = FigureCanvasAgg(fig)
ax = fig.add_subplot()
ax.plot([1, 2, 3])
canvas.draw()
buffer = canvas.buffer_rgba()
img = slint.Image.load_from_array(buffer)
Example of loading an image with Pillow:
import slint
from PIL import Image
import numpy as np
pil_img = Image.open("hello.jpeg")
array = np.array(pil_img)
img = slint.Image.load_from_array(array)
A Color object represents a color in the RGB color space with an alpha. Each color channel and the alpha is represented as an 8-bit integer. The alpha channel is 0 for fully transparent and 255 for fully opaque.
Construct colors from a CSS color string, or by specifying the red, green, blue, and (optional) alpha channels in a dict.
Returns a new color that is brighter than this color by the given factor.
Returns a new color that is darker than this color by the given factor.
Returns a new version of this color with the opacity decreased by factor.
The transparency is obtained by multiplying the alpha channel by (1 - factor).
A brush is a data structure that is used to describe how a shape, such as a rectangle, path or even text, shall be filled. A brush can also be applied to the outline of a shape, that means the fill of the outline itself.
Brushes can only be constructed from solid colors.
Note: In future, we plan to reduce this constraint and allow for declaring graidient brushes programmatically.
Returns true if this brush contains a fully transparent color (alpha value is zero).
Returns a new version of this brush that has the brightness increased
by the specified factor. This is done by calling Color.brighter on
all the colors of this brush.
Returns a new version of this brush that has the brightness decreased
by the specified factor. This is done by calling Color.darker on
all the color of this brush.
Returns a new version of this brush with the opacity decreased by factor.
The transparency is obtained by multiplying the alpha channel by (1 - factor).
See also Color.transparentize.
12class Model[T](native.PyModelBase, Iterable[T]): 13 """Model is the base class for feeding dynamic data into Slint views. 14 15 Subclass Model to implement your own models, or use `ListModel` to wrap a list. 16 17 Models are iterable and can be used in for loops.""" 18 19 def __new__(cls, *args: Any) -> "Model[T]": 20 return super().__new__(cls) 21 22 def __init__(self) -> None: 23 self.init_self(self) 24 25 def __len__(self) -> int: 26 return self.row_count() 27 28 def __getitem__(self, index: int) -> typing.Optional[T]: 29 return self.row_data(index) 30 31 def __setitem__(self, index: int, value: T) -> None: 32 self.set_row_data(index, value) 33 34 def __iter__(self) -> Iterator[T]: 35 return ModelIterator(self) 36 37 def set_row_data(self, row: int, value: T) -> None: 38 """Call this method on mutable models to change the data for the given row. 39 The UI will also call this method when modifying a model's data. 40 Re-implement this method in a sub-class to handle the change.""" 41 super().set_row_data(row, value) 42 43 @abstractmethod 44 def row_data(self, row: int) -> typing.Optional[T]: 45 """Returns the data for the given row. 46 Re-implement this method in a sub-class to provide the data.""" 47 return cast(T, super().row_data(row)) 48 49 def notify_row_changed(self, row: int) -> None: 50 """Call this method from a sub-class to notify the views that a row has changed.""" 51 super().notify_row_changed(row) 52 53 def notify_row_removed(self, row: int, count: int) -> None: 54 """Call this method from a sub-class to notify the views that 55 `count` rows have been removed starting at `row`.""" 56 super().notify_row_removed(row, count) 57 58 def notify_row_added(self, row: int, count: int) -> None: 59 """Call this method from a sub-class to notify the views that 60 `count` rows have been added starting at `row`.""" 61 super().notify_row_added(row, count)
Model is the base class for feeding dynamic data into Slint views.
Subclass Model to implement your own models, or use ListModel to wrap a list.
Models are iterable and can be used in for loops.
37 def set_row_data(self, row: int, value: T) -> None: 38 """Call this method on mutable models to change the data for the given row. 39 The UI will also call this method when modifying a model's data. 40 Re-implement this method in a sub-class to handle the change.""" 41 super().set_row_data(row, value)
Call this method on mutable models to change the data for the given row. The UI will also call this method when modifying a model's data. Re-implement this method in a sub-class to handle the change.
43 @abstractmethod 44 def row_data(self, row: int) -> typing.Optional[T]: 45 """Returns the data for the given row. 46 Re-implement this method in a sub-class to provide the data.""" 47 return cast(T, super().row_data(row))
Returns the data for the given row. Re-implement this method in a sub-class to provide the data.
Call this method from a sub-class to notify the views that a row has changed.
64class ListModel[T](Model[T]): 65 """ListModel is a `Model` that stores its data in a Python list. 66 67 Construct a ListMode from an iterable (such as a list itself). 68 Use `ListModel.append()` to add items to the model, and use the 69 `del` statement to remove items. 70 71 Any changes to the model are automatically reflected in the views 72 in UI they're used with. 73 """ 74 75 def __init__(self, iterable: typing.Optional[Iterable[T]] = None): 76 """Constructs a new ListModel from the give iterable. All the values 77 the iterable produces are stored in a list.""" 78 79 super().__init__() 80 if iterable is not None: 81 self.list = list(iterable) 82 else: 83 self.list = [] 84 85 def row_count(self) -> int: 86 return len(self.list) 87 88 def row_data(self, row: int) -> typing.Optional[T]: 89 return self.list[row] 90 91 def set_row_data(self, row: int, value: T) -> None: 92 self.list[row] = value 93 super().notify_row_changed(row) 94 95 def __delitem__(self, key: int | slice) -> None: 96 if isinstance(key, slice): 97 start, stop, step = key.indices(len(self.list)) 98 del self.list[key] 99 count = len(range(start, stop, step)) 100 super().notify_row_removed(start, count) 101 else: 102 del self.list[key] 103 super().notify_row_removed(key, 1) 104 105 def append(self, value: T) -> None: 106 """Appends the value to the end of the list.""" 107 index = len(self.list) 108 self.list.append(value) 109 super().notify_row_added(index, 1)
ListModel is a Model that stores its data in a Python list.
Construct a ListMode from an iterable (such as a list itself).
Use ListModel.append() to add items to the model, and use the
del statement to remove items.
Any changes to the model are automatically reflected in the views in UI they're used with.
75 def __init__(self, iterable: typing.Optional[Iterable[T]] = None): 76 """Constructs a new ListModel from the give iterable. All the values 77 the iterable produces are stored in a list.""" 78 79 super().__init__() 80 if iterable is not None: 81 self.list = list(iterable) 82 else: 83 self.list = []
Constructs a new ListModel from the give iterable. All the values the iterable produces are stored in a list.
Returns the data for the given row. Re-implement this method in a sub-class to provide the data.
91 def set_row_data(self, row: int, value: T) -> None: 92 self.list[row] = value 93 super().notify_row_changed(row)
Call this method on mutable models to change the data for the given row. The UI will also call this method when modifying a model's data. Re-implement this method in a sub-class to handle the change.
Timer is a handle to the timer system that triggers a callback after a specified period of time.
Use Timer.start() to create a timer that that repeatedly triggers a callback, or
Timer.single_shot() to trigger a callback only once.
The timer will automatically stop when garbage collected. You must keep the Timer object around for as long as you want the timer to keep firing.
class AppWindow(...)
def __init__(self):
super().__init__()
self.my_timer = None
@slint.callback
def button_clicked(self):
self.my_timer = slint.Timer()
self.my_timer.start(timedelta(seconds=1), self.do_something)
def do_something(self):
pass
Timers can only be used in the thread that runs the Slint event loop. They don't fire if used in another thread.
Starts the timer with the given mode and interval, in order for the callback to called when the timer fires. If the timer has been started previously and not fired yet, then it will be restarted.
Arguments:
mode: The timer mode to apply, i.e. whether to repeatedly fire the timer or just once.interval: The duration from now until when the timer should firethe first time, and subsequently forTimerMode.Repeatedtimers.callback: The function to call when the time has been reached or exceeded.
Starts the timer with the duration and the callback to called when the timer fires. It is fired only once and then deleted.
Arguments:
duration: The duration from now until when the timer should fire.callback: The function to call when the time has been reached or exceeded.
Stops the previously started timer. Does nothing if the timer has never been started.
Restarts the timer. If the timer was previously started by calling Timer.start()
with a duration and callback, then the time when the callback will be next invoked
is re-calculated to be in the specified duration relative to when this function is called.
Does nothing if the timer was never started.
The duration of timer.
When setting this property and the timer is running (see Timer.running),
then the time when the callback will be next invoked is re-calculated to be in the
specified duration relative to when this property is set.
The TimerMode specifies what should happen after the timer fired.
Used by the Timer.start() function.
530def set_xdg_app_id(app_id: str) -> None: 531 """Sets the application id for use on Wayland or X11 with [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/) 532 compliant window managers. This id must be set before the window is shown; it only applies to Wayland or X11.""" 533 534 native.set_xdg_app_id(app_id)
Sets the application id for use on Wayland or X11 with xdg compliant window managers. This id must be set before the window is shown; it only applies to Wayland or X11.
488def callback( 489 global_name: typing.Callable[..., Any] | str | None = None, name: str | None = None 490) -> typing.Callable[..., Any]: 491 """Use the callback decorator to mark a method as a callback that can be invoked from the Slint component. 492 493 For the decorator to work, the method must be a member of a class that is Slint component. 494 495 Example: 496 ```python 497 import slint 498 499 class AppMainWindow(slint.loader.main_window.MainWindow): 500 501 # Automatically connected to a callback button_clicked() 502 # in main_window.slint's MainWindow. 503 @slint.callback() 504 def button_clicked(self): 505 print("Button clicked") 506 507 ... 508 ``` 509 510 If your Python method has a different name from the Slint component's callback, use the `name` parameter to specify 511 the correct name. Similarly, use the `global_name` parameter to specify the name of the correct global singleton in 512 the Slint component. 513 514 **Note:** The callback decorator can also be used with async functions. They will be run as task in the asyncio event loop. 515 This is only supported for callbacks that don't return any value, and requires Python >= 3.13. 516 """ 517 518 if callable(global_name): 519 callback = global_name 520 return _callback_decorator(callback, {}) 521 else: 522 info = {} 523 if name: 524 info["name"] = name 525 if global_name: 526 info["global_name"] = global_name 527 return lambda callback: _callback_decorator(callback, info)
Use the callback decorator to mark a method as a callback that can be invoked from the Slint component.
For the decorator to work, the method must be a member of a class that is Slint component.
Example:
import slint
class AppMainWindow(slint.loader.main_window.MainWindow):
# Automatically connected to a callback button_clicked()
# in main_window.slint's MainWindow.
@slint.callback()
def button_clicked(self):
print("Button clicked")
...
If your Python method has a different name from the Slint component's callback, use the name parameter to specify
the correct name. Similarly, use the global_name parameter to specify the name of the correct global singleton in
the Slint component.
Note: The callback decorator can also be used with async functions. They will be run as task in the asyncio event loop. This is only supported for callbacks that don't return any value, and requires Python >= 3.13.
540def run_event_loop( 541 main_coro: typing.Optional[Coroutine[None, None, None]] = None, 542) -> None: 543 """Runs the main Slint event loop. If specified, the coroutine `main_coro` is run in parallel. The event loop doesn't 544 terminate when the coroutine finishes, it terminates when calling `quit_event_loop()`. 545 546 Example: 547 ```python 548 import slint 549 550 ... 551 image_model: slint.ListModel[slint.Image] = slint.ListModel() 552 ... 553 554 async def main_receiver(image_model: slint.ListModel) -> None: 555 async with aiohttp.ClientSession() as session: 556 async with session.get("http://some.server/svg-image") as response: 557 svg = await response.read() 558 image = slint.Image.from_svg_data(svg) 559 image_model.append(image) 560 561 ... 562 slint.run_event_loop(main_receiver(image_model)) 563 ``` 564 565 """ 566 567 async def run_inner() -> None: 568 global quit_event 569 loop = typing.cast(SlintEventLoop, asyncio.get_event_loop()) 570 571 quit_task = asyncio.ensure_future(quit_event.wait(), loop=loop) 572 573 tasks: typing.List[asyncio.Task[typing.Any]] = [quit_task] 574 575 main_task = None 576 if main_coro: 577 main_task = loop.create_task(main_coro) 578 tasks.append(main_task) 579 580 done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) 581 582 if main_task is not None and main_task in done: 583 main_task.result() # propagate exception if thrown 584 if quit_task in pending: 585 await quit_event.wait() 586 587 global quit_event 588 quit_event = asyncio.Event() 589 asyncio.run(run_inner(), debug=False, loop_factory=SlintEventLoop)
Runs the main Slint event loop. If specified, the coroutine main_coro is run in parallel. The event loop doesn't
terminate when the coroutine finishes, it terminates when calling quit_event_loop().
Example:
import slint
...
image_model: slint.ListModel[slint.Image] = slint.ListModel()
...
async def main_receiver(image_model: slint.ListModel) -> None:
async with aiohttp.ClientSession() as session:
async with session.get("http://some.server/svg-image") as response:
svg = await response.read()
image = slint.Image.from_svg_data(svg)
image_model.append(image)
...
slint.run_event_loop(main_receiver(image_model))
592def quit_event_loop() -> None: 593 """Quits the running event loop in the next event processing cycle. This will make an earlier call to `run_event_loop()` 594 return.""" 595 global quit_event 596 quit_event.set()
Quits the running event loop in the next event processing cycle. This will make an earlier call to run_event_loop()
return.
599def init_translations(translations: typing.Optional[gettext.GNUTranslations]) -> None: 600 """Installs the specified translations object to handle translations originating from the Slint code. 601 602 Example: 603 ```python 604 import gettext 605 import slint 606 607 translations_dir = os.path.join(os.path.dirname(__file__), "lang") 608 try: 609 translations = gettext.translation("my_app", translations_dir, ["de"]) 610 slint.install_translations(translations) 611 except OSError: 612 pass 613 ``` 614 """ 615 native.init_translations(translations)
Installs the specified translations object to handle translations originating from the Slint code.
Example:
import gettext
import slint
translations_dir = os.path.join(os.path.dirname(__file__), "lang")
try:
translations = gettext.translation("my_app", translations_dir, ["de"])
slint.install_translations(translations)
except OSError:
pass