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 <info@slint.dev> 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 11from . import language 12 13import types 14import logging 15import copy 16import typing 17from typing import Any 18import pathlib 19from .models import ListModel, Model 20from .slint import Image, Color, Brush, Keys, Timer, TimerMode 21from .loop import SlintEventLoop 22from pathlib import Path 23from collections.abc import Coroutine 24import asyncio 25import gettext 26import gzip 27import base64 28 29 30Struct = native.PyStruct 31 32 33class CompileError(Exception): 34 message: str 35 """The error message that produced this compile error.""" 36 37 diagnostics: list[native.PyDiagnostic] 38 """A list of detailed diagnostics that were produced as part of the compilation.""" 39 40 def __init__(self, message: str, diagnostics: list[native.PyDiagnostic]): 41 """@private""" 42 super().__init__(message) 43 self.message = message 44 self.diagnostics = diagnostics 45 for diag in self.diagnostics: 46 self.add_note(str(diag)) 47 48 49class Component: 50 """Component is the base class for all instances of Slint components. Use the member functions to show or hide the 51 window, or spin the event loop.""" 52 53 __instance__: native.ComponentInstance 54 55 def show(self) -> None: 56 """Shows the window on the screen.""" 57 58 self.__instance__.show() 59 60 def hide(self) -> None: 61 """Hides the window from the screen.""" 62 63 self.__instance__.hide() 64 65 def run(self) -> None: 66 """Shows the window, runs the event loop, hides it when the loop is quit, and returns.""" 67 self.show() 68 run_event_loop() 69 self.hide() 70 71 72def _normalize_prop(name: str) -> str: 73 return name.replace("-", "_") 74 75 76def _build_global_class(compdef: native.ComponentDefinition, global_name: str) -> Any: 77 properties_and_callbacks = {} 78 79 for prop_name in compdef.global_properties(global_name).keys(): 80 python_prop = _normalize_prop(prop_name) 81 if python_prop in properties_and_callbacks: 82 logging.warning(f"Duplicated property {prop_name}") 83 continue 84 85 def mk_setter_getter(prop_or_callback_name: str) -> property: 86 def getter(self: Component) -> Any: 87 return self.__instance__.get_global_property( 88 global_name, prop_or_callback_name 89 ) 90 91 def setter(self: Component, value: Any) -> None: 92 self.__instance__.set_global_property( 93 global_name, prop_or_callback_name, value 94 ) 95 96 return property(getter, setter) 97 98 properties_and_callbacks[python_prop] = mk_setter_getter(prop_name) 99 100 for callback_name in compdef.global_callbacks(global_name): 101 python_prop = _normalize_prop(callback_name) 102 if python_prop in properties_and_callbacks: 103 logging.warning(f"Duplicated property {prop_name}") 104 continue 105 106 def mk_setter_getter(prop_or_callback_name: str) -> property: 107 def getter(self: Component) -> typing.Callable[..., Any]: 108 def call(*args: Any) -> Any: 109 return self.__instance__.invoke_global( 110 global_name, prop_or_callback_name, *args 111 ) 112 113 return call 114 115 def setter(self: Component, value: typing.Callable[..., Any]) -> None: 116 self.__instance__.set_global_callback( 117 global_name, prop_or_callback_name, value 118 ) 119 120 return property(getter, setter) 121 122 properties_and_callbacks[python_prop] = mk_setter_getter(callback_name) 123 124 for function_name in compdef.global_functions(global_name): 125 python_prop = _normalize_prop(function_name) 126 if python_prop in properties_and_callbacks: 127 logging.warning(f"Duplicated function {prop_name}") 128 continue 129 130 def mk_getter(function_name: str) -> property: 131 def getter(self: Component) -> typing.Callable[..., Any]: 132 def call(*args: Any) -> Any: 133 return self.__instance__.invoke_global( 134 global_name, function_name, *args 135 ) 136 137 return call 138 139 return property(getter) 140 141 properties_and_callbacks[python_prop] = mk_getter(function_name) 142 143 return type("SlintGlobalClassWrapper", (), properties_and_callbacks) 144 145 146def _build_class( 147 compdef: native.ComponentDefinition, 148) -> typing.Callable[..., Component]: 149 def cls_init(self: Component, **kwargs: Any) -> Any: 150 self.__instance__ = compdef.create() 151 for name, value in self.__class__.__dict__.items(): 152 if hasattr(value, "slint.callback"): 153 callback_info = getattr(value, "slint.callback") 154 name = callback_info["name"] 155 156 is_async = getattr(value, "slint.async", False) 157 if is_async: 158 if "global_name" in callback_info: 159 global_name = callback_info["global_name"] 160 is_void = compdef.global_callback_returns_void( 161 global_name, name 162 ) 163 if is_void is None: 164 raise AttributeError( 165 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" 166 ) 167 if not is_void: 168 raise RuntimeError( 169 f"Callback '{name}' in global '{global_name}' cannot be used with a callback decorator for an async function, as it doesn't return void" 170 ) 171 else: 172 is_void = compdef.callback_returns_void(name) 173 if is_void is None: 174 raise AttributeError( 175 f"Callback '{name}' cannot be used with a callback decorator for an async function, as it is not declared in Slint component" 176 ) 177 if not is_void: 178 raise RuntimeError( 179 f"Callback '{name}' cannot be used with a callback decorator for an async function, as it doesn't return void" 180 ) 181 182 def mk_callback( 183 self: Any, callback: typing.Callable[..., Any] 184 ) -> typing.Callable[..., Any]: 185 def invoke(*args: Any, **kwargs: Any) -> Any: 186 return callback(self, *args, **kwargs) 187 188 return invoke 189 190 if "global_name" in callback_info: 191 self.__instance__.set_global_callback( 192 callback_info["global_name"], name, mk_callback(self, value) 193 ) 194 else: 195 self.__instance__.set_callback(name, mk_callback(self, value)) 196 197 for prop, val in kwargs.items(): 198 setattr(self, prop, val) 199 200 properties_and_callbacks: dict[Any, Any] = {"__init__": cls_init} 201 202 for prop_name in compdef.properties.keys(): 203 python_prop = _normalize_prop(prop_name) 204 if python_prop in properties_and_callbacks: 205 logging.warning(f"Duplicated property {prop_name}") 206 continue 207 208 def mk_setter_getter(prop_or_callback_name: str) -> property: 209 def getter(self: Component) -> Any: 210 return self.__instance__.get_property(prop_or_callback_name) 211 212 def setter(self: Component, value: Any) -> None: 213 self.__instance__.set_property(prop_or_callback_name, value) 214 215 return property(getter, setter) 216 217 properties_and_callbacks[python_prop] = mk_setter_getter(prop_name) 218 219 for callback_name in compdef.callbacks: 220 python_prop = _normalize_prop(callback_name) 221 if python_prop in properties_and_callbacks: 222 logging.warning(f"Duplicated property {prop_name}") 223 continue 224 225 def mk_setter_getter(prop_or_callback_name: str) -> property: 226 def getter(self: Component) -> typing.Callable[..., Any]: 227 def call(*args: Any) -> Any: 228 return self.__instance__.invoke(prop_or_callback_name, *args) 229 230 return call 231 232 def setter(self: Component, value: typing.Callable[..., Any]) -> None: 233 self.__instance__.set_callback(prop_or_callback_name, value) 234 235 return property(getter, setter) 236 237 properties_and_callbacks[python_prop] = mk_setter_getter(callback_name) 238 239 for function_name in compdef.functions: 240 python_prop = _normalize_prop(function_name) 241 if python_prop in properties_and_callbacks: 242 logging.warning(f"Duplicated function {prop_name}") 243 continue 244 245 def mk_getter(function_name: str) -> property: 246 def getter(self: Component) -> typing.Callable[..., Any]: 247 def call(*args: Any) -> Any: 248 return self.__instance__.invoke(function_name, *args) 249 250 return call 251 252 return property(getter) 253 254 properties_and_callbacks[python_prop] = mk_getter(function_name) 255 256 for global_name in compdef.globals: 257 global_class = _build_global_class(compdef, global_name) 258 259 def mk_global(global_class: typing.Callable[..., Any]) -> property: 260 def global_getter(self: Component) -> Any: 261 wrapper = global_class() 262 setattr(wrapper, "__instance__", self.__instance__) 263 return wrapper 264 265 return property(global_getter) 266 267 properties_and_callbacks[global_name] = mk_global(global_class) 268 269 return type("SlintClassWrapper", (Component,), properties_and_callbacks) 270 271 272def _build_struct(name: str, struct_prototype: native.PyStruct) -> type: 273 def new_struct(cls: Any, *args: Any, **kwargs: Any) -> native.PyStruct: 274 inst = copy.copy(struct_prototype) 275 276 for prop, val in kwargs.items(): 277 setattr(inst, prop, val) 278 279 return inst 280 281 type_dict = { 282 "__new__": new_struct, 283 } 284 285 return type(name, (), type_dict) 286 287 288def _load_file( 289 path: str | os.PathLike[Any] | pathlib.Path, 290 quiet: bool = False, 291 style: typing.Optional[str] = None, 292 include_paths: typing.Optional[typing.List[os.PathLike[Any] | pathlib.Path]] = None, 293 library_paths: typing.Optional[ 294 typing.Dict[str, os.PathLike[Any] | pathlib.Path] 295 ] = None, 296 translation_domain: typing.Optional[str] = None, 297) -> typing.Tuple[types.SimpleNamespace, native.CompilationResult]: 298 """This function is the low-level entry point into Slint for instantiating components. It loads the `.slint` file at 299 the specified `path` and returns a namespace with all exported components as Python classes, as well as enums, and structs. 300 301 * `quiet`: Set to true to prevent any warnings during compilation from being printed to stderr. 302 * `style`: Specify a widget style. 303 * `include_paths`: Additional include paths used to look up `.slint` files imported from other `.slint` files. 304 * `library_paths`: A dictionary that maps library names to their location in the file system. This is then used to look up 305 library imports, such as `import { MyButton } from "@mylibrary";`. 306 * `translation_domain`: The domain to use for looking up the catalogue run-time translations. This must match the 307 translation domain used when extracting translations with `slint-tr-extractor`. 308 309 """ 310 311 compiler = native.Compiler() 312 313 if style is not None: 314 compiler.style = style 315 if include_paths is not None: 316 compiler.include_paths = include_paths 317 if library_paths is not None: 318 compiler.library_paths = library_paths 319 if translation_domain is not None: 320 compiler.translation_domain = translation_domain 321 322 result = compiler.build_from_path(Path(path)) 323 324 diagnostics = result.diagnostics 325 if diagnostics: 326 if not quiet: 327 for diag in diagnostics: 328 if diag.level == native.DiagnosticLevel.Warning: 329 logging.warning(diag) 330 if diag.level == native.DiagnosticLevel.Note: 331 logging.debug(diag) 332 333 errors = [ 334 diag for diag in diagnostics if diag.level == native.DiagnosticLevel.Error 335 ] 336 if errors: 337 raise CompileError(f"Could not compile {path}", diagnostics) 338 339 module = types.SimpleNamespace() 340 for comp_name in result.component_names: 341 wrapper_class = _build_class(result.component(comp_name)) 342 343 setattr(module, comp_name, wrapper_class) 344 345 structs, enums = result.structs_and_enums 346 347 for name, struct_prototype in structs.items(): 348 name = _normalize_prop(name) 349 struct_wrapper = _build_struct(name, struct_prototype) 350 setattr(module, name, struct_wrapper) 351 352 for name, enum_class in enums.items(): 353 name = _normalize_prop(name) 354 setattr(module, name, enum_class) 355 356 for orig_name, new_name in result.named_exports: 357 orig_name = _normalize_prop(orig_name) 358 new_name = _normalize_prop(new_name) 359 setattr(module, new_name, getattr(module, orig_name)) 360 361 return (module, result) 362 363 364def load_file( 365 path: str | os.PathLike[Any] | pathlib.Path, 366 quiet: bool = False, 367 style: typing.Optional[str] = None, 368 include_paths: typing.Optional[typing.List[os.PathLike[Any] | pathlib.Path]] = None, 369 library_paths: typing.Optional[ 370 typing.Dict[str, os.PathLike[Any] | pathlib.Path] 371 ] = None, 372 translation_domain: typing.Optional[str] = None, 373) -> types.SimpleNamespace: 374 """This function is the low-level entry point into Slint for instantiating components. It loads the `.slint` file at 375 the specified `path` and returns a namespace with all exported components as Python classes, as well as enums, and structs. 376 377 * `quiet`: Set to true to prevent any warnings during compilation from being printed to stderr. 378 * `style`: Specify a widget style. 379 * `include_paths`: Additional include paths used to look up `.slint` files imported from other `.slint` files. 380 * `library_paths`: A dictionary that maps library names to their location in the file system. This is then used to look up 381 library imports, such as `import { MyButton } from "@mylibrary";`. 382 * `translation_domain`: The domain to use for looking up the catalogue run-time translations. This must match the 383 translation domain used when extracting translations with `slint-tr-extractor`. 384 385 """ 386 387 return _load_file( 388 path, quiet, style, include_paths, library_paths, translation_domain 389 )[0] 390 391 392def _load_file_checked( 393 path: str | os.PathLike[Any] | pathlib.Path, 394 expected_api_base64_compressed: str, 395 generated_file: str | os.PathLike[Any] | pathlib.Path, 396) -> types.SimpleNamespace: 397 """@private""" 398 399 module, compilation_result = _load_file(path) 400 401 expected_api = gzip.decompress( 402 base64.standard_b64decode(expected_api_base64_compressed) 403 ).decode("utf-8") 404 405 generated_api_module = native.GeneratedAPI(path=generated_file, json=expected_api) 406 actual_api_module = compilation_result.generated_api 407 408 generated_api_module.compare_generated_vs_actual( 409 generated=generated_api_module, actual=actual_api_module 410 ) 411 412 return module 413 414 415class SlintAutoLoader: 416 def __init__(self, base_dir: Path | None = None): 417 self.local_dirs: typing.List[Path] | None = None 418 if base_dir: 419 self.local_dirs = [base_dir] 420 421 def __getattr__(self, name: str) -> Any: 422 for path in self.local_dirs or sys.path: 423 dir_candidate = Path(path) / name 424 if os.path.isdir(dir_candidate): 425 loader = SlintAutoLoader(dir_candidate) 426 setattr(self, name, loader) 427 return loader 428 429 file_candidate = dir_candidate.with_suffix(".slint") 430 if os.path.isfile(file_candidate): 431 type_namespace = load_file(file_candidate) 432 setattr(self, name, type_namespace) 433 return type_namespace 434 435 dir_candidate = Path(path) / name.replace("_", "-") 436 file_candidate = dir_candidate.with_suffix(".slint") 437 if os.path.isfile(file_candidate): 438 type_namespace = load_file(file_candidate) 439 setattr(self, name, type_namespace) 440 return type_namespace 441 442 return None 443 444 445loader = SlintAutoLoader() 446"""Use the global `loader` object to load Slint files from the file system. It exposes two stages of attributes: 4471. Any lookup of an attribute in the loader tries to match a file in `sys.path` with the `.slint` extension. For example 448 `loader.my_component` looks for a file `my_component.slint` in the directories in `sys.path`. 4492. Any lookup in the object returned by the first stage tries to match an exported component in the loaded file, or a 450 struct, or enum. For example `loader.my_component.MyComponent` looks for an *exported* component named `MyComponent` 451 in the file `my_component.slint`. 452 453**Note:** The first entry in the module search path `sys.path` is the directory that contains the input script. 454 455Example: 456```python 457import slint 458# Look for a file `main.slint` in the current directory, 459# #load & compile it, and instantiate the exported `MainWindow` component 460main_window = slint.loader.main_window.MainWindow() 461main_window.show() 462... 463``` 464""" 465 466 467def _callback_decorator( 468 callable: typing.Callable[..., Any], info: typing.Dict[str, Any] 469) -> typing.Callable[..., Any]: 470 if "name" not in info: 471 info["name"] = typing.cast(Any, callable).__name__ 472 setattr(callable, "slint.callback", info) 473 474 try: 475 import inspect 476 477 if inspect.iscoroutinefunction(callable): 478 479 def run_as_task(*args, **kwargs) -> None: 480 loop = asyncio.get_event_loop() 481 loop.create_task(callable(*args, **kwargs)) 482 483 setattr(run_as_task, "slint.callback", info) 484 setattr(run_as_task, "slint.async", True) 485 return run_as_task 486 except ImportError: 487 pass 488 489 return callable 490 491 492def callback( 493 global_name: typing.Callable[..., Any] | str | None = None, name: str | None = None 494) -> typing.Callable[..., Any]: 495 """Use the callback decorator to mark a method as a callback that can be invoked from the Slint component. 496 497 For the decorator to work, the method must be a member of a class that is Slint component. 498 499 Example: 500 ```python 501 import slint 502 503 class AppMainWindow(slint.loader.main_window.MainWindow): 504 505 # Automatically connected to a callback button_clicked() 506 # in main_window.slint's MainWindow. 507 @slint.callback() 508 def button_clicked(self): 509 print("Button clicked") 510 511 ... 512 ``` 513 514 If your Python method has a different name from the Slint component's callback, use the `name` parameter to specify 515 the correct name. Similarly, use the `global_name` parameter to specify the name of the correct global singleton in 516 the Slint component. 517 518 **Note:** The callback decorator can also be used with async functions. They will be run as task in the asyncio event loop. 519 This is only supported for callbacks that don't return any value, and requires Python >= 3.13. 520 """ 521 522 if callable(global_name): 523 callback = global_name 524 return _callback_decorator(callback, {}) 525 else: 526 info = {} 527 if name: 528 info["name"] = name 529 if global_name: 530 info["global_name"] = global_name 531 return lambda callback: _callback_decorator(callback, info) 532 533 534def set_xdg_app_id(app_id: str) -> None: 535 """Sets the application id for use on Wayland or X11 with [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/) 536 compliant window managers. This id must be set before the window is shown; it only applies to Wayland or X11.""" 537 538 native.set_xdg_app_id(app_id) 539 540 541quit_event = asyncio.Event() 542 543 544def run_event_loop( 545 main_coro: typing.Optional[Coroutine[None, None, None]] = None, 546) -> None: 547 """Runs the main Slint event loop. If specified, the coroutine `main_coro` is run in parallel. The event loop doesn't 548 terminate when the coroutine finishes, it terminates when calling `quit_event_loop()`. 549 550 Example: 551 ```python 552 import slint 553 554 ... 555 image_model: slint.ListModel[slint.Image] = slint.ListModel() 556 ... 557 558 async def main_receiver(image_model: slint.ListModel) -> None: 559 async with aiohttp.ClientSession() as session: 560 async with session.get("http://some.server/svg-image") as response: 561 svg = await response.read() 562 image = slint.Image.from_svg_data(svg) 563 image_model.append(image) 564 565 ... 566 slint.run_event_loop(main_receiver(image_model)) 567 ``` 568 569 """ 570 571 async def run_inner() -> None: 572 global quit_event 573 loop = typing.cast(SlintEventLoop, asyncio.get_event_loop()) 574 575 quit_task = asyncio.ensure_future(quit_event.wait(), loop=loop) 576 577 tasks: typing.List[asyncio.Task[typing.Any]] = [quit_task] 578 579 main_task = None 580 if main_coro: 581 main_task = loop.create_task(main_coro) 582 tasks.append(main_task) 583 584 done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) 585 586 if main_task is not None and main_task in done: 587 main_task.result() # propagate exception if thrown 588 if quit_task in pending: 589 await quit_event.wait() 590 591 global quit_event 592 quit_event = asyncio.Event() 593 asyncio.run(run_inner(), debug=False, loop_factory=SlintEventLoop) 594 595 596def quit_event_loop() -> None: 597 """Quits the running event loop in the next event processing cycle. This will make an earlier call to `run_event_loop()` 598 return.""" 599 global quit_event 600 quit_event.set() 601 602 603def init_translations(translations: typing.Optional[gettext.GNUTranslations]) -> None: 604 """Installs the specified translations object to handle translations originating from the Slint code. 605 606 Example: 607 ```python 608 import gettext 609 import slint 610 611 translations_dir = os.path.join(os.path.dirname(__file__), "lang") 612 try: 613 translations = gettext.translation("my_app", translations_dir, ["de"]) 614 slint.install_translations(translations) 615 except OSError: 616 pass 617 ``` 618 """ 619 native.init_translations(translations) 620 621 622__all__ = [ 623 "CompileError", 624 "Component", 625 "load_file", 626 "_load_file_checked", 627 "loader", 628 "Image", 629 "Color", 630 "Brush", 631 "Keys", 632 "Model", 633 "ListModel", 634 "Timer", 635 "TimerMode", 636 "set_xdg_app_id", 637 "callback", 638 "run_event_loop", 639 "quit_event_loop", 640 "init_translations", 641 "language", 642]
34class CompileError(Exception): 35 message: str 36 """The error message that produced this compile error.""" 37 38 diagnostics: list[native.PyDiagnostic] 39 """A list of detailed diagnostics that were produced as part of the compilation.""" 40 41 def __init__(self, message: str, diagnostics: list[native.PyDiagnostic]): 42 """@private""" 43 super().__init__(message) 44 self.message = message 45 self.diagnostics = diagnostics 46 for diag in self.diagnostics: 47 self.add_note(str(diag))
Common base class for all non-exit exceptions.
50class Component: 51 """Component is the base class for all instances of Slint components. Use the member functions to show or hide the 52 window, or spin the event loop.""" 53 54 __instance__: native.ComponentInstance 55 56 def show(self) -> None: 57 """Shows the window on the screen.""" 58 59 self.__instance__.show() 60 61 def hide(self) -> None: 62 """Hides the window from the screen.""" 63 64 self.__instance__.hide() 65 66 def run(self) -> None: 67 """Shows the window, runs the event loop, hides it when the loop is quit, and returns.""" 68 self.show() 69 run_event_loop() 70 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.
365def load_file( 366 path: str | os.PathLike[Any] | pathlib.Path, 367 quiet: bool = False, 368 style: typing.Optional[str] = None, 369 include_paths: typing.Optional[typing.List[os.PathLike[Any] | pathlib.Path]] = None, 370 library_paths: typing.Optional[ 371 typing.Dict[str, os.PathLike[Any] | pathlib.Path] 372 ] = None, 373 translation_domain: typing.Optional[str] = None, 374) -> types.SimpleNamespace: 375 """This function is the low-level entry point into Slint for instantiating components. It loads the `.slint` file at 376 the specified `path` and returns a namespace with all exported components as Python classes, as well as enums, and structs. 377 378 * `quiet`: Set to true to prevent any warnings during compilation from being printed to stderr. 379 * `style`: Specify a widget style. 380 * `include_paths`: Additional include paths used to look up `.slint` files imported from other `.slint` files. 381 * `library_paths`: A dictionary that maps library names to their location in the file system. This is then used to look up 382 library imports, such as `import { MyButton } from "@mylibrary";`. 383 * `translation_domain`: The domain to use for looking up the catalogue run-time translations. This must match the 384 translation domain used when extracting translations with `slint-tr-extractor`. 385 386 """ 387 388 return _load_file( 389 path, quiet, style, include_paths, library_paths, translation_domain 390 )[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.
Represents a key binding created by the @keys(...) macro in Slint.
This is an opaque type. Use str() to get a platform-native representation
of the key binding (e.g. "Ctrl+A" on Linux/Windows, "⌘A" on macOS).
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) -> typing.Self: 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.
535def set_xdg_app_id(app_id: str) -> None: 536 """Sets the application id for use on Wayland or X11 with [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/) 537 compliant window managers. This id must be set before the window is shown; it only applies to Wayland or X11.""" 538 539 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.
493def callback( 494 global_name: typing.Callable[..., Any] | str | None = None, name: str | None = None 495) -> typing.Callable[..., Any]: 496 """Use the callback decorator to mark a method as a callback that can be invoked from the Slint component. 497 498 For the decorator to work, the method must be a member of a class that is Slint component. 499 500 Example: 501 ```python 502 import slint 503 504 class AppMainWindow(slint.loader.main_window.MainWindow): 505 506 # Automatically connected to a callback button_clicked() 507 # in main_window.slint's MainWindow. 508 @slint.callback() 509 def button_clicked(self): 510 print("Button clicked") 511 512 ... 513 ``` 514 515 If your Python method has a different name from the Slint component's callback, use the `name` parameter to specify 516 the correct name. Similarly, use the `global_name` parameter to specify the name of the correct global singleton in 517 the Slint component. 518 519 **Note:** The callback decorator can also be used with async functions. They will be run as task in the asyncio event loop. 520 This is only supported for callbacks that don't return any value, and requires Python >= 3.13. 521 """ 522 523 if callable(global_name): 524 callback = global_name 525 return _callback_decorator(callback, {}) 526 else: 527 info = {} 528 if name: 529 info["name"] = name 530 if global_name: 531 info["global_name"] = global_name 532 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.
545def run_event_loop( 546 main_coro: typing.Optional[Coroutine[None, None, None]] = None, 547) -> None: 548 """Runs the main Slint event loop. If specified, the coroutine `main_coro` is run in parallel. The event loop doesn't 549 terminate when the coroutine finishes, it terminates when calling `quit_event_loop()`. 550 551 Example: 552 ```python 553 import slint 554 555 ... 556 image_model: slint.ListModel[slint.Image] = slint.ListModel() 557 ... 558 559 async def main_receiver(image_model: slint.ListModel) -> None: 560 async with aiohttp.ClientSession() as session: 561 async with session.get("http://some.server/svg-image") as response: 562 svg = await response.read() 563 image = slint.Image.from_svg_data(svg) 564 image_model.append(image) 565 566 ... 567 slint.run_event_loop(main_receiver(image_model)) 568 ``` 569 570 """ 571 572 async def run_inner() -> None: 573 global quit_event 574 loop = typing.cast(SlintEventLoop, asyncio.get_event_loop()) 575 576 quit_task = asyncio.ensure_future(quit_event.wait(), loop=loop) 577 578 tasks: typing.List[asyncio.Task[typing.Any]] = [quit_task] 579 580 main_task = None 581 if main_coro: 582 main_task = loop.create_task(main_coro) 583 tasks.append(main_task) 584 585 done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) 586 587 if main_task is not None and main_task in done: 588 main_task.result() # propagate exception if thrown 589 if quit_task in pending: 590 await quit_event.wait() 591 592 global quit_event 593 quit_event = asyncio.Event() 594 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))
597def quit_event_loop() -> None: 598 """Quits the running event loop in the next event processing cycle. This will make an earlier call to `run_event_loop()` 599 return.""" 600 global quit_event 601 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.
604def init_translations(translations: typing.Optional[gettext.GNUTranslations]) -> None: 605 """Installs the specified translations object to handle translations originating from the Slint code. 606 607 Example: 608 ```python 609 import gettext 610 import slint 611 612 translations_dir = os.path.join(os.path.dirname(__file__), "lang") 613 try: 614 translations = gettext.translation("my_app", translations_dir, ["de"]) 615 slint.install_translations(translations) 616 except OSError: 617 pass 618 ``` 619 """ 620 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