Skip to content

Instantly share code, notes, and snippets.

@itzexor
Last active August 17, 2022 13:27
Show Gist options
  • Save itzexor/b1093d447648397b061f9d54dcfe7d78 to your computer and use it in GitHub Desktop.
Save itzexor/b1093d447648397b061f9d54dcfe7d78 to your computer and use it in GitHub Desktop.
Simple dearpygui test app that tries to run at low fps when user is not interacting
#!/usr/bin/python
from collections import deque
from threading import Thread
from time import perf_counter as get_time
from sched import Event, scheduler
import stats
import dearpygui.dearpygui as dpg
FPS = 60
IDLE_FPS = 6
IDLE_TIMEOUT = 5
DATA_UPDATE_INTERVAL = 1
TPS = 1
FRAME_TIMING = TPS / FPS
IDLE_FRAME_TIMING = TPS / IDLE_FPS
class TimerObject():
event_id = 0
interval = 0
callback = None
args = None
def __init__(self, interval, callback, args) -> None:
self.interval = interval
self.callback = callback
self.args = args
class DpgApp:
_idle_info = (0, 0, 0)
_is_idle = False
_render_time = 0
_render_event = None
_mainloop = scheduler(timefunc=get_time)
_ui_queue = deque()
_timers = {}
_next_timer_id = 0
def __init__(self, window_title="") -> None:
dpg.create_context()
dpg.setup_dearpygui()
dpg.create_viewport(title=window_title)
dpg.set_viewport_vsync(False)
stats.init()
dpg.show_metrics()
def _process_ui_queue(self) -> None:
while len(self._ui_queue):
d = self._ui_queue.popleft()
dpg.set_value(item=d[0], value=f'{d[1]:0.3}')
def _render(self) -> None:
if not dpg.is_dearpygui_running():
return
self._render_event = None
self._process_ui_queue()
dpg.render_dearpygui_frame()
self._check_idle()
self._queue_render()
def _queue_render(self, force_active=False) -> None:
if not force_active and self._is_idle:
delay = IDLE_FRAME_TIMING
else:
delay = FRAME_TIMING
next = self._next_render_time + delay
if self._render_event:
self._mainloop.cancel(self._render_event)
self._next_render_time = next
self._render_event = self.queue_event(self._render, time=next, priority=0)
def _check_idle(self) -> None:
(x1, y1, t) = self._idle_info
(x2, y2) = dpg.get_mouse_pos(local=False)
if x1 != x2 or y1 != y2:
self._idle_info = (x2, y2, get_time())
self._is_idle = False
elif get_time() - t > IDLE_TIMEOUT:
self._is_idle = True
@property
def is_idle(self) -> bool:
return self._is_idle
def _run_threads(self) -> None:
Thread(target=stats.run, args=[self]).start()
def _run_timer(self, id) -> None:
t = self._timers[id]
t.callback(*t.args)
t.event_id = self.queue_event(callback=self._run_timer, args=[id], delay=t.interval)
def queue_render(self) -> None:
self._queue_render(force_active=True)
def queue_event(self, callback, args=[], kwargs={}, delay=0, time=None, priority=100) -> Event:
if not dpg.is_dearpygui_running():
return
if time:
return self._mainloop.enterabs(time, priority, callback, args, kwargs)
return self._mainloop.enter(delay, priority, callback, args, kwargs)
def cancel_event(self, event) -> bool:
try:
self._mainloop.cancel(event)
except ValueError:
return False
return True
def start_timer(self, interval, callback, args=[]) -> str:
self._next_timer_id += 1
t = TimerObject(interval, callback, args)
self._timers[self._next_timer_id] = t
t.event_id = self.queue_event(callback=self._run_timer, args=[self._next_timer_id], delay=interval)
return self._next_timer_id
def stop_timer(self, id) -> bool:
t = self._timers[id]
self.cancel_event(t.event_id)
del self._timers[id]
def run(self) -> None:
self._last_active_time = self._next_render_time = get_time()
self._queue_render()
dpg.show_viewport()
self._is_running = True
self.start_timer(DATA_UPDATE_INTERVAL * TPS, self._run_threads)
self._mainloop.run()
if __name__ == "__main__":
app = DpgApp("Test App")
app.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment