mirror of
https://github.com/python/cpython.git
synced 2026-05-06 04:37:33 -04:00
gh-47655: Add support for user data and detail of Tk events to tkinter (GH-7142)
Expose the %d substitution as the tkinter.Event attributes: * "detail" for Enter, Leave, FocusIn, FocusOut, and ConfigureRequest events * "user_data" for virtual events Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
committed by
GitHub
parent
1ac9d138ae
commit
f8ce51a522
@@ -1059,6 +1059,11 @@ tkinter
|
||||
with outdated names.
|
||||
(Contributed by Serhiy Storchaka in :gh:`143754`.)
|
||||
|
||||
* Added :class:`!Event` attributes :attr:`!user_data` for Tk virtual events
|
||||
and :attr:`!detail` for ``Enter``, ``Leave``, ``FocusIn``, ``FocusOut``,
|
||||
and ``ConfigureRequest`` events.
|
||||
(Contributed by Matthias Kievernagel and Serhiy Storchaka in :gh:`47655`.)
|
||||
|
||||
|
||||
.. _whatsnew315-tomllib-1-1-0:
|
||||
|
||||
|
||||
@@ -636,6 +636,8 @@ class EventTest(AbstractTkTest, unittest.TestCase):
|
||||
self.assertEqual(e.x_root, '??')
|
||||
self.assertEqual(e.y_root, '??')
|
||||
self.assertEqual(e.delta, 0)
|
||||
self.assertEqual(e.user_data, '??')
|
||||
self.assertEqual(e.detail, 'NotifyAncestor')
|
||||
self.assertEqual(repr(e), '<FocusIn event>')
|
||||
|
||||
def test_configure(self):
|
||||
@@ -669,6 +671,8 @@ class EventTest(AbstractTkTest, unittest.TestCase):
|
||||
self.assertEqual(e.x_root, '??')
|
||||
self.assertEqual(e.y_root, '??')
|
||||
self.assertEqual(e.delta, 0)
|
||||
self.assertEqual(e.user_data, '??')
|
||||
self.assertEqual(e.detail, '??')
|
||||
self.assertEqual(repr(e), '<Configure event x=0 y=0 width=150 height=100>')
|
||||
|
||||
def test_event_generate_key_press(self):
|
||||
@@ -705,6 +709,8 @@ class EventTest(AbstractTkTest, unittest.TestCase):
|
||||
self.assertEqual(e.x_root, -1)
|
||||
self.assertEqual(e.y_root, -1)
|
||||
self.assertEqual(e.delta, 0)
|
||||
self.assertEqual(e.user_data, '??')
|
||||
self.assertEqual(e.detail, '??')
|
||||
self.assertEqual(repr(e),
|
||||
f"<KeyPress event state={e.state:#x} "
|
||||
f"keysym=z keycode={e.keycode} char='z' x={e.x} y={e.y}>")
|
||||
@@ -740,8 +746,17 @@ class EventTest(AbstractTkTest, unittest.TestCase):
|
||||
self.assertEqual(e.x_root, 100 + f.winfo_rootx())
|
||||
self.assertEqual(e.y_root, 50 + f.winfo_rooty())
|
||||
self.assertEqual(e.delta, 0)
|
||||
self.assertEqual(e.user_data, '??')
|
||||
self.assertEqual(e.detail, 'NotifyAncestor')
|
||||
self.assertEqual(repr(e), '<Enter event focus=False x=100 y=50>')
|
||||
|
||||
f.event_generate('<Enter>', x=100, y=50, detail='NotifyPointer')
|
||||
self.assertEqual(len(events), 2, events)
|
||||
e = events[1]
|
||||
self.assertIs(e.type, tkinter.EventType.Enter)
|
||||
self.assertEqual(e.user_data, '??')
|
||||
self.assertEqual(e.detail, 'NotifyPointer')
|
||||
|
||||
def test_event_generate_button_press(self):
|
||||
f = tkinter.Frame(self.root, width=150, height=100)
|
||||
f.pack()
|
||||
@@ -774,6 +789,8 @@ class EventTest(AbstractTkTest, unittest.TestCase):
|
||||
self.assertEqual(e.x_root, f.winfo_rootx() + 100)
|
||||
self.assertEqual(e.y_root, f.winfo_rooty() + 50)
|
||||
self.assertEqual(e.delta, 0)
|
||||
self.assertEqual(e.user_data, '??')
|
||||
self.assertEqual(e.detail, '??')
|
||||
self.assertEqual(repr(e), '<ButtonPress event num=1 x=100 y=50>')
|
||||
|
||||
def test_event_generate_motion(self):
|
||||
@@ -808,6 +825,8 @@ class EventTest(AbstractTkTest, unittest.TestCase):
|
||||
self.assertEqual(e.x_root, f.winfo_rootx() + 100)
|
||||
self.assertEqual(e.y_root, f.winfo_rooty() + 50)
|
||||
self.assertEqual(e.delta, 0)
|
||||
self.assertEqual(e.user_data, '??')
|
||||
self.assertEqual(e.detail, '??')
|
||||
self.assertEqual(repr(e), '<Motion event state=Button1 x=100 y=50>')
|
||||
|
||||
def test_event_generate_mouse_wheel(self):
|
||||
@@ -842,9 +861,11 @@ class EventTest(AbstractTkTest, unittest.TestCase):
|
||||
self.assertEqual(e.x_root, f.winfo_rootx() + 100)
|
||||
self.assertEqual(e.y_root, f.winfo_rooty() + 50)
|
||||
self.assertEqual(e.delta, -5)
|
||||
self.assertEqual(e.user_data, '??')
|
||||
self.assertEqual(e.detail, '??')
|
||||
self.assertEqual(repr(e), '<MouseWheel event delta=-5 x=100 y=50>')
|
||||
|
||||
def test_generate_event_virtual_event(self):
|
||||
def test_event_generate_virtual_event(self):
|
||||
f = tkinter.Frame(self.root, width=150, height=100)
|
||||
f.pack()
|
||||
self.root.wait_visibility() # needed on Windows
|
||||
@@ -876,9 +897,18 @@ class EventTest(AbstractTkTest, unittest.TestCase):
|
||||
self.assertEqual(e.x_root, f.winfo_rootx() + 50)
|
||||
self.assertEqual(e.y_root, -1)
|
||||
self.assertEqual(e.delta, 0)
|
||||
self.assertEqual(e.user_data, '')
|
||||
self.assertEqual(e.detail, '??')
|
||||
self.assertEqual(repr(e),
|
||||
f"<VirtualEvent event x=50 y=0>")
|
||||
|
||||
f.event_generate('<<Spam>>', data='spam')
|
||||
self.assertEqual(len(events), 2, events)
|
||||
e = events[1]
|
||||
self.assertIs(e.type, tkinter.EventType.VirtualEvent)
|
||||
self.assertEqual(e.user_data, 'spam')
|
||||
self.assertEqual(e.detail, '??')
|
||||
|
||||
|
||||
class BindTest(AbstractTkTest, unittest.TestCase):
|
||||
|
||||
|
||||
+17
-4
@@ -255,6 +255,10 @@ class Event:
|
||||
type - type of the event as a number
|
||||
widget - widget in which the event occurred
|
||||
delta - delta of wheel movement (MouseWheel)
|
||||
detail - certain fixed strings (see Tcl/Tk documentation)
|
||||
(Enter, Leave, FocusIn, FocusOut, ConfigureRequest)
|
||||
user_data - data string which was passed to event_generate() or empty
|
||||
string (VirtualEvent)
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
@@ -1538,7 +1542,7 @@ class Misc:
|
||||
<Alt-A> for pressing A and the Alt key (KeyPress can be omitted).
|
||||
An event pattern can also be a virtual event of the form
|
||||
<<AString>> where AString can be arbitrary. This
|
||||
event can be generated by event_generate.
|
||||
event can be generated by event_generate().
|
||||
If events are concatenated they must appear shortly
|
||||
after each other.
|
||||
|
||||
@@ -1723,7 +1727,7 @@ class Misc:
|
||||
w = self
|
||||
while w.master is not None: w = w.master
|
||||
return w
|
||||
_subst_format = ('%#', '%b', '%f', '%h', '%k',
|
||||
_subst_format = ('%#', '%b', '%d', '%f', '%h', '%k',
|
||||
'%s', '%t', '%w', '%x', '%y',
|
||||
'%A', '%E', '%K', '%N', '%W', '%T', '%X', '%Y', '%D')
|
||||
_subst_format_str = " ".join(_subst_format)
|
||||
@@ -1744,11 +1748,14 @@ class Misc:
|
||||
if any(isinstance(s, tuple) for s in args):
|
||||
args = [s[0] if isinstance(s, tuple) and len(s) == 1 else s
|
||||
for s in args]
|
||||
nsign, b, f, h, k, s, t, w, x, y, A, E, K, N, W, T, X, Y, D = args
|
||||
# Missing: (a, c, d, m, o, v, B, R)
|
||||
nsign, b, d, f, h, k, s, t, w, x, y, A, E, K, N, W, T, X, Y, D = args
|
||||
# Missing: (a, c, m, o, v, B, R)
|
||||
e = Event()
|
||||
# serial field: valid for all events
|
||||
# number of button: ButtonPress and ButtonRelease events only
|
||||
# detail: for Enter, Leave, FocusIn, FocusOut and ConfigureRequest
|
||||
# events certain fixed strings (see Tcl/Tk documentation)
|
||||
# user_data: data string from a virtual event or an empty string
|
||||
# height field: Configure, ConfigureRequest, Create,
|
||||
# ResizeRequest, and Expose events only
|
||||
# keycode field: KeyPress and KeyRelease events only
|
||||
@@ -1762,6 +1769,12 @@ class Misc:
|
||||
# KeyRelease, and Motion events
|
||||
e.serial = getint(nsign)
|
||||
e.num = getint_event(b)
|
||||
if T == EventType.VirtualEvent:
|
||||
e.user_data = d
|
||||
e.detail = '??'
|
||||
else:
|
||||
e.user_data = '??'
|
||||
e.detail = d
|
||||
try: e.focus = getboolean(f)
|
||||
except TclError: pass
|
||||
e.height = getint_event(h)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Add support for user data of Tk virtual events and detail for
|
||||
``Enter``, ``Leave``, ``FocusIn``, ``FocusOut``, and
|
||||
``ConfigureRequest`` events to :mod:`tkinter`.
|
||||
Reference in New Issue
Block a user