From 664ba5b0037533da71fe9a1426fd44363b12f921 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Fri, 6 Dec 2024 12:34:21 +0100 Subject: [PATCH] Changed that CanvasGroup's loop can be set to None, instead of setting _rc_canvas_group to None --- docs/backendapi.rst | 12 ++++++------ rendercanvas/base.py | 28 ++++++++++++++++++---------- rendercanvas/offscreen.py | 8 ++++++-- rendercanvas/stub.py | 5 ++++- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/docs/backendapi.rst b/docs/backendapi.rst index 1067a62..0617176 100644 --- a/docs/backendapi.rst +++ b/docs/backendapi.rst @@ -11,22 +11,22 @@ Also see https://github.com/pygfx/rendercanvas/blob/main/rendercanvas/stub.py. with each version without warning. -.. autoclass:: rendercanvas.stub.StubCanvasGroup +.. autoclass:: rendercanvas.stub.StubLoop :members: :private-members: :member-order: bysource -.. autoclass:: rendercanvas.stub.StubRenderCanvas +.. autoclass:: rendercanvas.stub.StubCanvasGroup :members: :private-members: :member-order: bysource -.. autoclass:: rendercanvas.base.WrapperRenderCanvas - - -.. autoclass:: rendercanvas.stub.StubLoop +.. autoclass:: rendercanvas.stub.StubRenderCanvas :members: :private-members: :member-order: bysource + + +.. autoclass:: rendercanvas.base.WrapperRenderCanvas diff --git a/rendercanvas/base.py b/rendercanvas/base.py index f0e6c0c..fac5b4d 100644 --- a/rendercanvas/base.py +++ b/rendercanvas/base.py @@ -30,30 +30,32 @@ class BaseCanvasGroup: def __init__(self, default_loop): self._canvases = weakref.WeakSet() - self._loop = default_loop + self._loop = None self.select_loop(default_loop) def _register_canvas(self, canvas, task): """Used by the canvas to register itself.""" self._canvases.add(canvas) loop = self.get_loop() - loop._register_canvas_group(self) - loop.add_task(task, name="scheduler-task") + if loop is not None: + loop._register_canvas_group(self) + loop.add_task(task, name="scheduler-task") def select_loop(self, loop): """Select the loop to use for this group of canvases.""" - if not isinstance(loop, BaseLoop): - raise TypeError("select_loop() requires a loop instance.") + if not (loop is None or isinstance(loop, BaseLoop)): + raise TypeError("select_loop() requires a loop instance or None.") elif len(self._canvases): raise RuntimeError("Cannot select_loop() when live canvases exist.") elif loop is self._loop: pass else: - self._loop._unregister_canvas_group(self) + if self._loop is not None: + self._loop._unregister_canvas_group(self) self._loop = loop def get_loop(self): - """Get the currently associated loop.""" + """Get the currently associated loop (can be None for canvases that don't run a scheduler).""" return self._loop def get_canvases(self): @@ -88,7 +90,6 @@ class BaseRenderCanvas: _rc_canvas_group = None """Class attribute that refers to the ``CanvasGroup`` instance to use for canvases of this class. It specifies what loop is used, and enables users to changing the used loop. - Set to None to not use a loop. """ @classmethod @@ -132,14 +133,19 @@ def __init__( "fps": "?", "backend": self.__class__.__name__, "loop": self._rc_canvas_group.get_loop().__class__.__name__ - if self._rc_canvas_group + if (self._rc_canvas_group and self._rc_canvas_group.get_loop()) else "no-loop", } # Events and scheduler self._events = EventEmitter() self.__scheduler = None - if self._rc_canvas_group is not None: + if self._rc_canvas_group is None: + pass # No scheduling, not even grouping + elif self._rc_canvas_group.get_loop() is None: + # Group, but no loop: no scheduling + self._rc_canvas_group._register_canvas(self, None) + else: self.__scheduler = Scheduler( self, self._events, @@ -583,6 +589,8 @@ class WrapperRenderCanvas(BaseRenderCanvas): wrapped canvas and set it as ``_subwidget``. """ + _rc_canvas_group = None # No grouping for these wrappers + @classmethod def select_loop(cls, loop): m = sys.modules[cls.__module__] diff --git a/rendercanvas/offscreen.py b/rendercanvas/offscreen.py index 29880f6..4327188 100644 --- a/rendercanvas/offscreen.py +++ b/rendercanvas/offscreen.py @@ -6,7 +6,11 @@ import time -from .base import BaseRenderCanvas, BaseLoop +from .base import BaseCanvasGroup, BaseRenderCanvas, BaseLoop + + +class OffscreenCanvasGroup(BaseCanvasGroup): + pass class ManualOffscreenRenderCanvas(BaseRenderCanvas): @@ -15,7 +19,7 @@ class ManualOffscreenRenderCanvas(BaseRenderCanvas): Call the ``.draw()`` method to perform a draw and get the result. """ - _rc_canvas_group = None # unmanaged, no loop + _rc_canvas_group = OffscreenCanvasGroup(None) # no loop, no scheduling def __init__(self, *args, pixel_ratio=1.0, **kwargs): super().__init__(*args, **kwargs) diff --git a/rendercanvas/stub.py b/rendercanvas/stub.py index 3d2271b..f96974c 100644 --- a/rendercanvas/stub.py +++ b/rendercanvas/stub.py @@ -37,6 +37,9 @@ def _rc_call_later(self, delay, callback): raise NotImplementedError() +loop = StubLoop() + + class StubCanvasGroup(BaseCanvasGroup): """ The ``CanvasGroup`` representss a group of canvas objects from the same class, that share a loop. @@ -75,7 +78,7 @@ def _draw_frame_and_present(self): # Must be implemented by subclasses. - _rc_canvas_group = None + _rc_canvas_group = StubCanvasGroup(loop) def _rc_gui_poll(self): raise NotImplementedError()