Closed yowoda closed 1 month ago
What is the meaning of tkinter.Event[tkinter.Canvas]
? Why the Event class is considered generic?
https://github.com/python/typeshed/issues/12591#issuecomment-2308961044
In this case, it implies the event was caused by an interaction with the canvas
How do canvas events differ from others?
It means that some_event.widget
is specifically a tkinter.Canvas
object. Even if you don't directly use that attribute, being able to annotate your event handler functions with the specific widget would allow checkers to catch passing the wrong event handler to bind()
.
You can also do e.g. event.widget.create_rectangle(...)
with an event that came from a Canvas.
To me, this is a very stable part of tkinter stubs. The genericness of Event
will not change any time soon, and Event
has been generic since 2020.
(I am the typeshed maintainer who basically takes care of everything tkinter related.)
Older discussion about this: https://github.com/python/typeshed/issues/4431
So this is for the widget
attribute? This is not correct. widget
is not always the same as the widget for which bind()
was called.
Example:
import tkinter
root = tkinter.Tk()
f = tkinter.Frame(root, name='frame', width=150, height=100)
f.pack()
root.wait_visibility()
root.update_idletasks()
def handler(e: 'tkinter.Event[tkinter.Tk]'):
# assert isinstance(e.widget, tkinter.Tk)
print(e.widget)
event = '<Enter>'
assert isinstance(root, tkinter.Tk)
root.bind(event, lambda e: print(e.widget))
f.event_generate(event)
The output is .frame
, not .
. And the commented out assert in the handler would fail.
Well but the event does come from tkinter.Frame
so imo the correct way to type hint this is tkinter.Event[tkinter.Frame]
since hovering over the frame is what causes the function to be called
You are using Tk.bind()
, which is already typed with tkinter.Event[tkinter.Misc]
(that is, an event where the widget may be of any type). The same goes for Toplevel.bind
. For other widgets, event.widget
is always* the same widget whose .bind()
was called, and the stubs define it in that way.
* Technically not correct. You could use a Frame
as a toplevel with the wm manage
command and then receive events from arbitrary widgets, as with Tk
and Toplevel
, but most tkinter users don't do that and tkinter wasn't written to support it very well (Frame
doesn't inherit from Wm
).
Well, you're probably right. I was not able to find example with non-toplevel widgets.
Bug report
Bug description:
This has been briefly discussed at https://github.com/python/typeshed/issues/12591
It would be great if this problem (a little more detailed version here) could be fixed in the entire standard library. As of right now, the inconsistency of class subscription support is just way too confusing for developers.
CPython versions tested on:
3.8, 3.9, 3.10, 3.11, 3.12, 3.13, CPython main branch
Operating systems tested on:
Linux, Windows
Linked PRs