]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-73588: Fix generation of the default name of tkinter.Checkbutton. (GH-97547)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 27 Sep 2022 11:39:31 +0000 (04:39 -0700)
committerGitHub <noreply@github.com>
Tue, 27 Sep 2022 11:39:31 +0000 (04:39 -0700)
Previously, checkbuttons in different parent widgets could have the same
short name and share the same state if arguments "name" and "variable" are
not specified. Now they are globally unique.
(cherry picked from commit adbed2d542a815b8175db965742211856b19b52f)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Lib/tkinter/__init__.py
Lib/tkinter/dialog.py
Lib/tkinter/test/test_tkinter/test_widgets.py
Lib/tkinter/test/test_ttk/test_widgets.py
Lib/tkinter/tix.py
Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst [new file with mode: 0644]

index b20c16d6c8f39203346513c54dc137f566e7f3c0..c7176e69e529d8b909789fea7d358edef62a53eb 100644 (file)
@@ -2592,7 +2592,7 @@ class BaseWidget(Misc):
         if kw:
             cnf = _cnfmerge((cnf, kw))
         self.widgetName = widgetName
-        BaseWidget._setup(self, master, cnf)
+        self._setup(master, cnf)
         if self._tclCommands is None:
             self._tclCommands = []
         classes = [(k, v) for k, v in cnf.items() if isinstance(k, type)]
@@ -3011,6 +3011,8 @@ class Canvas(Widget, XView, YView):
         return self.tk.call(self._w, 'type', tagOrId) or None
 
 
+_checkbutton_count = 0
+
 class Checkbutton(Widget):
     """Checkbutton widget which is either in on- or off-state."""
 
@@ -3026,6 +3028,14 @@ class Checkbutton(Widget):
         underline, variable, width, wraplength."""
         Widget.__init__(self, master, 'checkbutton', cnf, kw)
 
+    def _setup(self, master, cnf):
+        if not cnf.get('name'):
+            global _checkbutton_count
+            name = self.__class__.__name__.lower()
+            _checkbutton_count += 1
+            cnf['name'] = f'!{name}{_checkbutton_count}'
+        super()._setup(master, cnf)
+
     def deselect(self):
         """Put the button in off-state."""
         self.tk.call(self._w, 'deselect')
index 8ae214011727cc88775aecee5dbe925a7d4e0f7a..36ae6c277cb66ac86a48f42d07ce4c08dce10738 100644 (file)
@@ -11,7 +11,7 @@ class Dialog(Widget):
     def __init__(self, master=None, cnf={}, **kw):
         cnf = _cnfmerge((cnf, kw))
         self.widgetName = '__dialog__'
-        Widget._setup(self, master, cnf)
+        self._setup(master, cnf)
         self.num = self.tk.getint(
                 self.tk.call(
                       'tk_dialog', self._w,
index c0b92bf3b1921b0373debc93ebe4abd8666bebb8..562f4718cd2145bfa94b57a5e428e3507eecf982 100644 (file)
@@ -212,6 +212,32 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
         widget = self.create()
         self.checkParams(widget, 'onvalue', 1, 2.3, '', 'any string')
 
+    def test_unique_variables(self):
+        frames = []
+        buttons = []
+        for i in range(2):
+            f = tkinter.Frame(self.root)
+            f.pack()
+            frames.append(f)
+            for j in 'AB':
+                b = tkinter.Checkbutton(f, text=j)
+                b.pack()
+                buttons.append(b)
+        variables = [str(b['variable']) for b in buttons]
+        self.assertEqual(len(set(variables)), 4, variables)
+
+    def test_same_name(self):
+        f1 = tkinter.Frame(self.root)
+        f2 = tkinter.Frame(self.root)
+        b1 = tkinter.Checkbutton(f1, name='test', text='Test1')
+        b2 = tkinter.Checkbutton(f2, name='test', text='Test2')
+
+        v = tkinter.IntVar(self.root, name='test')
+        b1.select()
+        self.assertEqual(v.get(), 1)
+        b2.deselect()
+        self.assertEqual(v.get(), 0)
+
 
 @add_standard_options(StandardOptionsTests)
 class RadiobuttonTest(AbstractLabelTest, unittest.TestCase):
index 1cb7e74c66ec748f3eb5f965ae947e3c902b3bc5..c3142966ac2e0005cf884194a38154b5dd436a40 100644 (file)
@@ -275,6 +275,21 @@ class CheckbuttonTest(AbstractLabelTest, unittest.TestCase):
         self.assertEqual(cbtn['offvalue'],
             cbtn.tk.globalgetvar(cbtn['variable']))
 
+    def test_unique_variables(self):
+        frames = []
+        buttons = []
+        for i in range(2):
+            f = ttk.Frame(self.root)
+            f.pack()
+            frames.append(f)
+            for j in 'AB':
+                b = ttk.Checkbutton(f, text=j)
+                b.pack()
+                buttons.append(b)
+        variables = [str(b['variable']) for b in buttons]
+        print(variables)
+        self.assertEqual(len(set(variables)), 4, variables)
+
 
 @add_standard_options(IntegerSizeTests, StandardTtkOptionsTests)
 class EntryTest(AbstractWidgetTest, unittest.TestCase):
index 44ecae1a326831d9fc39aaa497f2375a83ce7758..ce218265d4a824c717565e4390387c97c0f1519b 100644 (file)
@@ -310,7 +310,7 @@ class TixWidget(tkinter.Widget):
                 del cnf[k]
 
         self.widgetName = widgetName
-        Widget._setup(self, master, cnf)
+        self._setup(master, cnf)
 
         # If widgetName is None, this is a dummy creation call where the
         # corresponding Tk widget has already been created by Tix
diff --git a/Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst b/Misc/NEWS.d/next/Library/2022-09-25-20-42-33.gh-issue-73588.uVtjEA.rst
new file mode 100644 (file)
index 0000000..d8a0e69
--- /dev/null
@@ -0,0 +1,4 @@
+Fix generation of the default name of :class:`tkinter.Checkbutton`.
+Previously, checkbuttons in different parent widgets could have the same
+short name and share the same state if arguments "name" and "variable" are
+not specified. Now they are globally unique.