Skip to content

Commit e152f1d

Browse files
add 'event_freq()'
1 parent 0c0c584 commit e152f1d

File tree

2 files changed

+70
-5
lines changed

2 files changed

+70
-5
lines changed

examples/painter1.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,25 @@ async def main(*, clock: at.Clock, root: tk.Tk):
2727
async def draw_rect(canvas: tk.Canvas, e_press: tk.Event):
2828
ox, oy = e_press.x, e_press.y
2929
rect = canvas.create_rectangle(ox, oy, ox, oy, outline='orange', width=3)
30-
async with at.move_on_when(at.event(canvas, '<ButtonRelease>', filter=lambda e: e.num == e_press.num)):
30+
async with (
31+
at.move_on_when(at.event(canvas, '<ButtonRelease>', filter=lambda e: e.num == e_press.num)),
32+
at.event_freq(canvas, '<Motion>') as mouse_motion,
33+
):
3134
while True:
32-
e = await at.event(canvas, '<Motion>')
35+
e = await mouse_motion()
3336
canvas.coords(rect, ox, oy, e.x, e.y)
3437

3538

3639
async def draw_oval(canvas: tk.Canvas, e_press: tk.Event):
3740
ox, oy = e_press.x, e_press.y
3841
oval = canvas.create_oval(ox, oy, ox, oy, outline='blue', width=3)
3942
bbox = canvas.create_rectangle(ox, oy, ox, oy, outline='black', dash=(3, 3))
40-
async with at.move_on_when(at.event(canvas, '<ButtonRelease>', filter=lambda e: e.num == e_press.num)):
43+
async with (
44+
at.move_on_when(at.event(canvas, '<ButtonRelease>', filter=lambda e: e.num == e_press.num)),
45+
at.event_freq(canvas, '<Motion>') as mouse_motion,
46+
):
4147
while True:
42-
e = await at.event(canvas, '<Motion>')
48+
e = await mouse_motion()
4349
canvas.coords(oval, ox, oy, e.x, e.y)
4450
canvas.coords(bbox, ox, oy, e.x, e.y)
4551
canvas.delete(bbox)

src/asynctkinter/_tkinter_stuffs.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__all__ = (
2-
'event', 'run', 'install',
2+
'event', 'event_freq', 'run', 'install',
33
)
44
import types
55
from functools import lru_cache, partial
@@ -28,6 +28,65 @@ def event(widget, sequence, *, filter=None) -> T.Awaitable[tkinter.Event]:
2828
widget.unbind(sequence, bind_id)
2929

3030

31+
class event_freq:
32+
'''
33+
When handling a frequently occurring event, such as ``<Motion>``, the following code might cause performance
34+
issues:
35+
36+
.. code-block::
37+
38+
e = await event(widget, '<ButtonPress>')
39+
while True:
40+
e = await event(widget, '<Motion>')
41+
...
42+
43+
If that happens, try the following code instead. It might resolve the issue:
44+
45+
.. code-block::
46+
47+
e = await event(widget, '<ButtonPress>')
48+
async with event_freq(widget, '<Motion>') as mouse_motion:
49+
while True:
50+
e = await mouse_motion()
51+
...
52+
53+
The trade-off is that within the context manager, you can't perform any async operations except the
54+
``await mouse_motion()``.
55+
56+
.. code-block::
57+
58+
async with event_freq(...) as xxx:
59+
e = await xxx() # OK
60+
await something_else() # Don't
61+
62+
.. versionadded:: 0.4.1
63+
'''
64+
__slots__ = ('_widget', '_seq', '_filter', '_bind_id', )
65+
66+
def __init__(self, widget, sequence, *, filter=None):
67+
self._widget = widget
68+
self._seq = sequence
69+
self._filter = filter
70+
71+
@types.coroutine
72+
def __aenter__(self):
73+
task = (yield _current_task)[0][0]
74+
self._bind_id = self._widget.bind(
75+
self._seq,
76+
partial(_event_callback, task._step, self._filter),
77+
"+",
78+
)
79+
return self._wait_one
80+
81+
async def __aexit__(self, *args):
82+
self._widget.unbind(self._seq, self._bind_id)
83+
84+
@staticmethod
85+
@types.coroutine
86+
def _wait_one():
87+
return (yield _sleep_forever)[0][0]
88+
89+
3190
@lru_cache(maxsize=1)
3291
def install():
3392
def immediate_call(f):

0 commit comments

Comments
 (0)