summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2023-12-06 14:42:15 (GMT)
committerGitHub <noreply@github.com>2023-12-06 14:42:15 (GMT)
commitcc7e45cc572dd818412a649970fdee579417701f (patch)
treee307b22d849cad24d54eb6858e7335c25cacc798
parent828451dfde324f9499ffebc023a22b84dc5a125b (diff)
downloadcpython-cc7e45cc572dd818412a649970fdee579417701f.zip
cpython-cc7e45cc572dd818412a649970fdee579417701f.tar.gz
cpython-cc7e45cc572dd818412a649970fdee579417701f.tar.bz2
gh-75666: Tkinter: "unbind(sequence, funcid)" now only unbinds "funcid" (GH-111322)
Previously, "widget.unbind(sequence, funcid)" destroyed the current binding for "sequence", leaving "sequence" unbound, and deleted the "funcid" command. Now it removes only "funcid" from the binding for "sequence", keeping other commands, and deletes the "funcid" command. It leaves "sequence" unbound only if "funcid" was the last bound command. Co-authored-by: GiovanniL <13402461+GiovaLomba@users.noreply.github.com>
-rw-r--r--Lib/test/test_tkinter/test_misc.py34
-rw-r--r--Lib/tkinter/__init__.py22
-rw-r--r--Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst6
3 files changed, 51 insertions, 11 deletions
diff --git a/Lib/test/test_tkinter/test_misc.py b/Lib/test/test_tkinter/test_misc.py
index ca99caa..6639eaa 100644
--- a/Lib/test/test_tkinter/test_misc.py
+++ b/Lib/test/test_tkinter/test_misc.py
@@ -479,26 +479,46 @@ class BindTest(AbstractTkTest, unittest.TestCase):
def test_unbind2(self):
f = self.frame
+ f.wait_visibility()
+ f.focus_force()
+ f.update_idletasks()
event = '<Control-Alt-Key-c>'
self.assertEqual(f.bind(), ())
self.assertEqual(f.bind(event), '')
- def test1(e): pass
- def test2(e): pass
+ def test1(e): events.append('a')
+ def test2(e): events.append('b')
+ def test3(e): events.append('c')
funcid = f.bind(event, test1)
funcid2 = f.bind(event, test2, add=True)
+ funcid3 = f.bind(event, test3, add=True)
+ events = []
+ f.event_generate(event)
+ self.assertEqual(events, ['a', 'b', 'c'])
- f.unbind(event, funcid)
+ f.unbind(event, funcid2)
script = f.bind(event)
- self.assertNotIn(funcid, script)
- self.assertCommandNotExist(funcid)
- self.assertCommandExist(funcid2)
+ self.assertNotIn(funcid2, script)
+ self.assertIn(funcid, script)
+ self.assertIn(funcid3, script)
+ self.assertEqual(f.bind(), (event,))
+ self.assertCommandNotExist(funcid2)
+ self.assertCommandExist(funcid)
+ self.assertCommandExist(funcid3)
+ events = []
+ f.event_generate(event)
+ self.assertEqual(events, ['a', 'c'])
- f.unbind(event, funcid2)
+ f.unbind(event, funcid)
+ f.unbind(event, funcid3)
self.assertEqual(f.bind(event), '')
self.assertEqual(f.bind(), ())
self.assertCommandNotExist(funcid)
self.assertCommandNotExist(funcid2)
+ self.assertCommandNotExist(funcid3)
+ events = []
+ f.event_generate(event)
+ self.assertEqual(events, [])
# non-idempotent
self.assertRaises(tkinter.TclError, f.unbind, event, funcid2)
diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
index 0df7f9d..1248824 100644
--- a/Lib/tkinter/__init__.py
+++ b/Lib/tkinter/__init__.py
@@ -1527,10 +1527,24 @@ class Misc:
return self._bind(('bind', self._w), sequence, func, add)
def unbind(self, sequence, funcid=None):
- """Unbind for this widget for event SEQUENCE the
- function identified with FUNCID."""
- self.tk.call('bind', self._w, sequence, '')
- if funcid:
+ """Unbind for this widget the event SEQUENCE.
+
+ If FUNCID is given, only unbind the function identified with FUNCID
+ and also delete the corresponding Tcl command.
+
+ Otherwise destroy the current binding for SEQUENCE, leaving SEQUENCE
+ unbound.
+ """
+ if funcid is None:
+ self.tk.call('bind', self._w, sequence, '')
+ else:
+ lines = self.tk.call('bind', self._w, sequence).split('\n')
+ prefix = f'if {{"[{funcid} '
+ keep = '\n'.join(line for line in lines
+ if not line.startswith(prefix))
+ if not keep.strip():
+ keep = ''
+ self.tk.call('bind', self._w, sequence, keep)
self.deletecommand(funcid)
def bind_all(self, sequence=None, func=None, add=None):
diff --git a/Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst b/Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst
new file mode 100644
index 0000000..d774cc4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst
@@ -0,0 +1,6 @@
+Fix the behavior of :mod:`tkinter` widget's ``unbind()`` method with two
+arguments. Previously, ``widget.unbind(sequence, funcid)`` destroyed the
+current binding for *sequence*, leaving *sequence* unbound, and deleted the
+*funcid* command. Now it removes only *funcid* from the binding for
+*sequence*, keeping other commands, and deletes the *funcid* command. It
+leaves *sequence* unbound only if *funcid* was the last bound command.