Canvas API

These are the classes that make up the rendercanvas API:

class rendercanvas.BaseRenderCanvas(*args, size: tuple[float, float] | None = (640, 480), title: str | None = '$backend', update_mode: UpdateModeEnum = 'ondemand', min_fps: float = 0.0, max_fps: float = 30.0, vsync: bool = True, present_method: Literal['bitmap', 'screen', None] = None, **kwargs)

The base canvas class.

This base class defines a uniform canvas API so render systems can use code that is portable across multiple GUI libraries and canvas targets. The scheduling mechanics are generic, even though they run on different backend event systems.

Parameters:
  • size (tuple) – the logical size (width, height) of the canvas.

  • title (str) – The title of the canvas. Can use ‘$backend’ to show the RenderCanvas class name, ‘$fps’ to show the fps, and ‘$ms’ to show the frame-time.

  • update_mode (UpdateMode) – The mode for scheduling draws and events. Default ‘ondemand’.

  • min_fps (float) – A minimal frames-per-second to use when the update_mode is ‘ondemand’. The default is 0:

  • max_fps (float) – A maximal frames-per-second to use when the update_mode is ‘ondemand’ or ‘continuous’. The default is 30, which is usually enough.

  • vsync (bool) – Whether to sync the draw with the monitor update. Helps against screen tearing, but limits the fps. Default True.

  • present_method (str | None) – Override the method to present the rendered result. Can be set to ‘screen’ or ‘bitmap’. Default None, which means that the method is selected based on what the canvas and context support and prefer.

classmethod select_loop(loop: BaseLoop) None

Select the loop to run newly created canvases with. Can only be called when there are no live canvases of this class.

get_physical_size() tuple[int, int]

Get the physical size of the canvas in integer pixels.

get_bitmap_context() BitmapContext

Get the BitmapContext to render to this canvas.

get_wgpu_context() WgpuContext

Get the WgpuContext to render to this canvas.

get_context(context_type: str | type) BaseContext

Get a context object that can be used to render to this canvas.

The context takes care of presenting the rendered result to the canvas. Different types of contexts are available:

  • Use “wgpu” to get a WgpuContext

  • Use “bitmap” to get a BitmapContext

  • Use a subclass of BaseContext to create an instance that is set up for this canvas.

Later calls to this method, with the same context_type argument, will return the same context instance as was returned the first time the method was invoked. It is not possible to get a different context object once the first one has been created.

add_event_handler(*args: EventTypeEnum | EventHandlerFunction, order: float = 0) Callable

Register an event handler to receive events.

Parameters:
  • callback (callable, optional) – The event handler. Must accept a single event argument.

  • *types (list of EventType) – A list of event types.

  • order (float) – Set callback priority order. Callbacks with lower priorities are called first. Default is 0. When an event is emitted, callbacks with the same priority are called in the order that they were added.

For the available events, see https://jupyter-rfb.readthedocs.io/en/stable/events.html.

The callback is stored, so it can be a lambda or closure. This also means that if a method is given, a reference to the object is held, which may cause circular references or prevent the Python GC from destroying that object.

Example:

def my_handler(event):
    print(event)

canvas.add_event_handler(my_handler, "pointer_up", "pointer_down")

Can also be used as a decorator:

@canvas.add_event_handler("pointer_up", "pointer_down")
def my_handler(event):
    print(event)

Catch ‘m all:

canvas.add_event_handler(my_handler, "*")
remove_event_handler(callback: EventHandlerFunction, *types: str) None

Unregister an event handler.

Parameters:
  • callback (callable) – The event handler.

  • *types (list of strings) – A list of event types.

submit_event(event: dict) None

Submit an event.

Events are emitted later by the scheduler.

set_update_mode(update_mode: UpdateModeEnum, *, min_fps: float | None = None, max_fps: float | None = None) None

Set the update mode for scheduling draws.

Parameters:
  • update_mode (UpdateMode) – The mode for scheduling draws and events.

  • min_fps (float) – The minimum fps with update mode ‘ondemand’.

  • max_fps (float) – The maximum fps with update mode ‘ondemand’ and ‘continuous’.

request_draw(draw_function: DrawFunction | None = None) None

Schedule a new draw event.

This function does not perform a draw directly, but schedules a draw at a suitable moment in time. At that time the draw function is called, and the resulting rendered image is presented to the canvas.

Only affects drawing with schedule-mode ‘ondemand’.

Parameters:

draw_function (callable or None) – The function to set as the new draw function. If not given or None, the last set draw function is used.

force_draw() None

Perform a draw right now.

In most cases you want to use request_draw(). If you find yourself using this, consider using a timer. Nevertheless, sometimes you just want to force a draw right now.

get_logical_size() tuple[float, float]

Get the logical size (width, height) of the canvas in float pixels.

The logical size can be smaller than the physical size, e.g. on HiDPI monitors or when the user’s system has the display-scale set to e.g. 125%.

get_pixel_ratio() float

Get the float ratio between logical and physical pixels.

The pixel ratio is typically 1.0 for normal screens and 2.0 for HiDPI screens, but fractional values are also possible if the system display-scale is set to e.g. 125%. An HiDPI screen can be assumed if the pixel ratio >= 2.0.

close() None

Close the canvas.

get_closed() bool

Get whether the window is closed.

set_logical_size(width: float, height: float) None

Set the window size (in logical pixels).

This changes the physical size of the canvas, such that the new logical size matches the given width and height. Since the physical size is integer (i.e. rounded), the re-calculated logical size may differ slightly from the given width and height (depending on the pixel ratio).

set_title(title: str) None

Set the window title.

A few special placeholders are supported:

  • “$backend”: the name of the backends’s RenderCanvas subclass.

  • “$loop”: the name of the used Loop subclass.

  • “$fps”: the current frames per second, useful as an indication how smooth the rendering feels.

  • “$ms”: the time between two rendered frames in milliseconds, useful for benchmarking.

set_cursor(cursor: Literal['default', 'text', 'crosshair', 'pointer', 'ew_resize', 'ns_resize', 'nesw_resize', 'nwse_resize', 'not_allowed', 'none']) None

Set the cursor shape for the mouse pointer.

See rendercanvas.CursorShape:

class rendercanvas.BaseLoop

The base class for an event-loop object.

The rendercanvas loop object is a proxy to a real event-loop. It abstracts away methods like run(), call_later, call_soon_threadsafe(), and more.

Canvas backends can implement their own loop subclass (like qt and wx do), but a canvas backend can also rely on one of multiple loop implementations (like glfw running on asyncio or trio).

In the majority of use-cases, users don’t need to know much about the loop. It will typically run once. In more complex scenario’s the section below explains the working of the loop in more detail.

Details about loop lifetime

The rendercanvas loop object is a proxy, which has to support a variety of backends. To realize this, it has the following lifetime model:

  • off:
    • Entered when the loop is instantiated, and when the loop has stopped.

    • This is the ‘idle’ state.

    • The backend probably has not even imported dependencies yet.

  • ready:
    • Entered when the first canvas is created that is associated with this loop, or when a task is added.

    • It is assumed that the loop will become active soon.

    • This is when _rc_init() is called to get the backend ready for running.

    • A special ‘loop-task’ is created (a coroutine, which is not yet running).

  • running:
    • Entered when loop.run() is called.

    • The loop is now running.

    • Signal handlers and asyncgen hooks are installed if applicable.

  • interactive:
    • Entered in _rc_init() when the backend detects that the loop is interactive.

    • Example use-cases are a notebook or interactive IDE, usually via asyncio.

    • This means there is a persistent native loop already running, which rendercanvas makes use of.

  • active:
    • Entered when the backend-loop starts running, but not via the loop’s run() method.

    • This is detected via the loop-task.

    • Signal handlers and asyncgen hooks are installed if applicable.

    • Detecting loop stopping occurs by the loop-task being cancelled.

Notes related to starting and stopping:

  • The loop goes back to the “off” state once all canvases are closed.

  • Stopping the loop (via .stop()) closes the canvases, which will then stop the loop.

  • From there it can go back to the ready state (which would call _rc_init() again).

  • In backends like Qt, the native loop can be started without us knowing: state “active”.

  • In interactive settings like an IDE that runs an asyncio or Qt loop, the loop becomes “interactive” as soon as the first canvas is created.

  • The rendercanvas loop can be in the ‘off’ state while the native loop is running (especially for the ‘interactive’ case).

  • On Qt, the app’s ‘aboutToQuit’ signal is used to stop this loop.

  • On wx, the loop is stopped when all windows are closed.

get_canvases(*, close_closed=False) list[BaseRenderCanvas]

Get a list of currently active (not-closed) canvases.

add_task(async_func: Callable[[], Coroutine], *args: Any, name: str | None = None) None

Run an async function in the event-loop.

All tasks are stopped when the loop stops. See Async for the limitations of async code in rendercanvas.

call_soon(callback: CallbackFunction, *args: Any) None

Arrange for a callback to be called as soon as possible.

The callback will be called in the next iteration of the event-loop, but other pending events/callbacks may be handled first. Returns None.

Not thread-safe; use call_soon_threadsafe() for scheduling callbacks from another thread.

call_soon_threadsafe(callback: CallbackFunction, *args: Any) None

A thread-safe variant of call_soon().

call_later(delay: float, callback: CallbackFunction, *args: Any) None

Arrange for a callback to be called after the given delay (in seconds).

run() None

Enter the main loop.

This provides a generic API to start the loop. When building an application (e.g. with Qt) its fine to start the loop in the normal way.

This call usually blocks, but it can also return immediately, e.g. when there are no canvases, or when the loop is already active (e.g. interactive via IDE).

async run_async() None

“Alternative to run(), to enter the mainloop from a running async framework.

Only supported by the asyncio and trio loops.

stop(*, force=False) None

Close all windows and stop the currently running event-loop.

If the loop is active but not running via the run() method, the loop moves back to its off-state, but the underlying loop is not stopped.

Normally, the windows are closed and the underlying event loop is given time to clean up and actually destroy the window. If force is set, the loop stops immediately. This can be an effective way to stop the loop when the native event loop has stopped.

class rendercanvas.EventType

The EventType enum specifies the possible events for a RenderCanvas.

This includes the events from the jupyter_rfb event spec (see https://jupyter-rfb.readthedocs.io/en/stable/events.html) plus some rendercanvas-specific events.

resize = 'resize'

The canvas has changed size. Has ‘width’ and ‘height’ in logical pixels, ‘pixel_ratio’.

close = 'close'

The canvas is closed. No additional fields.

pointer_down = 'pointer_down'

The pointing device is pressed down. Has ‘x’, ‘y’, ‘button’, ‘butons’, ‘modifiers’, ‘ntouches’, ‘touches’.

pointer_up = 'pointer_up'

The pointing device is released. Same fields as pointer_down. Can occur outside of the canvas.

pointer_move = 'pointer_move'

The pointing device is moved. Same fields as pointer_down. Can occur outside of the canvas if the pointer is currently down.

pointer_enter = 'pointer_enter'

The pointing device is moved into the canvas.

pointer_leave = 'pointer_leave'

The pointing device is moved outside of the canvas (regardless of a button currently being pressed).

double_click = 'double_click'

A double-click / long-tap. This event looks like a pointer event, but without the touches.

wheel = 'wheel'

The mouse-wheel is used (scrolling), or the touchpad/touchscreen is scrolled/pinched. Has ‘dx’, ‘dy’, ‘x’, ‘y’, ‘modifiers’.

key_down = 'key_down'

A key is pressed down. Has ‘key’, ‘modifiers’.

key_up = 'key_up'

A key is released. Has ‘key’, ‘modifiers’.

char = 'char'

Experimental

animate = 'animate'

Animation event. Has ‘step’ representing the step size in seconds. This is stable, except when the ‘catch_up’ field is nonzero.

class rendercanvas.UpdateMode

The UpdateMode enum specifies the different modes to schedule draws for the canvas.

manual = 'manual'

Draw events are never scheduled. Draws only happen when you canvas.force_draw(), and maybe when the GUI system issues them (e.g. when resizing).

ondemand = 'ondemand'

Draws are only scheduled when canvas.request_draw() is called when an update is needed. Safes your laptop battery. Honours min_fps and max_fps.

continuous = 'continuous'

Continuously schedules draw events, honouring max_fps. Calls to canvas.request_draw() have no effect.

fastest = 'fastest'

Continuously schedules draw events as fast as possible. Gives high FPS (and drains your battery).

class rendercanvas.CursorShape

The CursorShape enum specifies the suppported cursor shapes, following CSS cursor names.

default = 'default'

The platform-dependent default cursor, typically an arrow.

text = 'text'

The text input I-beam cursor shape.

crosshair = 'crosshair'
pointer = 'pointer'

The pointing hand cursor shape.

ew_resize = 'ew-resize'

The horizontal resize/move arrow shape.

ns_resize = 'ns-resize'

The vertical resize/move arrow shape.

not_allowed = 'not-allowed'

The operation-not-allowed shape.

none = 'none'

The cursor is hidden.