]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-75666: Tkinter: "unbind(sequence, funcid)" now only unbinds "funcid" (GH...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 6 Dec 2023 15:04:07 +0000 (16:04 +0100)
committerGitHub <noreply@github.com>
Wed, 6 Dec 2023 15:04:07 +0000 (15:04 +0000)
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.

(cherry picked from commit cc7e45cc572dd818412a649970fdee579417701f)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: GiovanniL <13402461+GiovaLomba@users.noreply.github.com>
Lib/tkinter/__init__.py
Lib/tkinter/test/test_tkinter/test_misc.py
Misc/NEWS.d/next/Library/2023-10-25-16-37-13.gh-issue-75666.BpsWut.rst [new file with mode: 0644]

index 704e7b8364b8ea6e62dcdfe2fc50ce7a5f2293b7..05558e97733cd9a33864ef391b3d61c470d63069 100644 (file)
@@ -1448,10 +1448,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):
index c772bb804639b892ba447d3fa01cdadf26efe0f9..aa11e65ea948ce8472958570f9ae3f2130e59d46 100644 (file)
@@ -425,26 +425,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/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 (file)
index 0000000..d774cc4
--- /dev/null
@@ -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.