From abf5fda2f5e464087dce672fe7aebf19bd1c61cf Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Wed, 12 Nov 2025 15:36:46 +0100 Subject: [PATCH 1/2] Allow displaying frame-time in ms in title ( instead of ) --- rendercanvas/_scheduler.py | 8 ++++---- rendercanvas/base.py | 15 +++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/rendercanvas/_scheduler.py b/rendercanvas/_scheduler.py index 8ac50a4..5185318 100644 --- a/rendercanvas/_scheduler.py +++ b/rendercanvas/_scheduler.py @@ -209,11 +209,11 @@ def on_draw(self): count, last_time = self._draw_stats count += 1 if time.perf_counter() - last_time > 1.0: - fps = count / (time.perf_counter() - last_time) + frame_time = (time.perf_counter() - last_time) / count self._draw_stats = 0, time.perf_counter() else: - fps = None + frame_time = None self._draw_stats = count, last_time - # Return fps or None. Will change with better stats at some point - return fps + # Return frame_time or None. Will change with better stats at some point + return frame_time diff --git a/rendercanvas/base.py b/rendercanvas/base.py index c3b7971..b5bba2b 100644 --- a/rendercanvas/base.py +++ b/rendercanvas/base.py @@ -90,7 +90,7 @@ class BaseRenderCanvas: Arguments: 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, - and '$fps' to show the fps. + '$fps' to show the fps, and '$ms' to show the frame-time (recommended for benchmarks). 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' @@ -147,6 +147,7 @@ def __init__( self.__title_info = { "raw": "", "fps": "?", + "ms": "?", "backend": self.__class__.__name__, "loop": self._rc_canvas_group.get_loop().__class__.__name__ if (self._rc_canvas_group and self._rc_canvas_group.get_loop()) @@ -533,12 +534,14 @@ def _draw_frame_and_present(self): # Notify the scheduler if self.__scheduler is not None: - fps = self.__scheduler.on_draw() + frame_time = self.__scheduler.on_draw() # Maybe update title - if fps is not None: - self.__title_info["fps"] = f"{fps:0.1f}" - if "$fps" in self.__title_info["raw"]: + if frame_time is not None: + self.__title_info["fps"] = f"{min(9999, 1 / frame_time):0.1f}" + self.__title_info["ms"] = f"{min(9999, 1000 * frame_time):0.1f}" + raw_title = self.__title_info["raw"] + if "$fps" in raw_title or "$ms" in raw_title: self.set_title(self.__title_info["raw"]) # Perform the user-defined drawing code. When this errors, @@ -630,7 +633,7 @@ def set_logical_size(self, width: float, height: float) -> None: def set_title(self, title: str) -> None: """Set the window title. - The words "$backend", "$loop", and "$fps" can be used as variables that + The words "$backend", "$loop", "$fps", and "$ms" can be used as variables that are filled in with the corresponding values. """ self.__title_info["raw"] = title From 4d2fc79e21c521a3a28ed2a8a5f98c17e865df05 Mon Sep 17 00:00:00 2001 From: Almar Klein Date: Thu, 13 Nov 2025 09:47:37 +0100 Subject: [PATCH 2/2] docs --- rendercanvas/base.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rendercanvas/base.py b/rendercanvas/base.py index b5bba2b..4637d46 100644 --- a/rendercanvas/base.py +++ b/rendercanvas/base.py @@ -90,7 +90,7 @@ class BaseRenderCanvas: Arguments: 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 (recommended for benchmarks). + '$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' @@ -633,8 +633,12 @@ def set_logical_size(self, width: float, height: float) -> None: def set_title(self, title: str) -> None: """Set the window title. - The words "$backend", "$loop", "$fps", and "$ms" can be used as variables that - are filled in with the corresponding values. + 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. """ self.__title_info["raw"] = title for k, v in self.__title_info.items():