]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-73588: Fix generation of the default name of tkinter.Checkbutton. (GH-97547)
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 27 Sep 2022 11:05:05 +0000 (14:05 +0300)
committerGitHub <noreply@github.com>
Tue, 27 Sep 2022 11:05:05 +0000 (14:05 +0300)
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.

Lib/test/test_tkinter/test_widgets.py
Lib/test/test_ttk/test_widgets.py
Lib/tkinter/__init__.py
Lib/tkinter/dialog.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 1cddbe17ba5207ebb6aebcb55a57233800a05f16..6cde1ccdbfcda859b3e88ac1008dc7e397fb99f4 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 eb0cc93ce270b5dcf63c5c9cc5c4a2ae0b361c1b..6f47ccb8e8b3dedc36bc2a2bdcc693db0f6e1c43 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 296320235afddb26809c29e332707b1578781ca6..356446911e0abc3ba5dac10272b626e35f03c896 100644 (file)
@@ -2619,7 +2619,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)]
@@ -3038,6 +3038,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."""
 
@@ -3053,6 +3055,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 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.