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