]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-151678: Add tests for tkinter widget virtual events (GH-151793) (GH-151807)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 20 Jun 2026 14:56:01 +0000 (16:56 +0200)
committerGitHub <noreply@github.com>
Sat, 20 Jun 2026 14:56:01 +0000 (14:56 +0000)
Verify the virtual events that widgets emit in response to user
interaction, driven by generated events: <<ListboxSelect>> (Listbox),
<<Increment>> and <<Decrement>> (ttk Spinbox), and <<TreeviewSelect>>,
<<TreeviewOpen>> and <<TreeviewClose>> (ttk Treeview).
(cherry picked from commit e51b616efff845ea2a7d312aa43d5f5100064d88)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Lib/test/test_tkinter/test_widgets.py
Lib/test/test_ttk/test_widgets.py

index 6c319cbb2c387dda692d62a6e3e80a76962c0dab..4d67c3ebc61311df519b89508776e2a4dcdd7dee 100644 (file)
@@ -1837,6 +1837,23 @@ class ListboxTest(AbstractWidgetTest, unittest.TestCase):
         self.assertRaisesRegex(TclError, 'bad listbox index "spam"',
                                lb.selection_includes, 'spam')
 
+    def test_selection_event(self):
+        # Keyboard navigation changes the selection and fires the
+        # <<ListboxSelect>> virtual event.
+        lb = self.create(selectmode='browse', exportselection=False)
+        lb.insert(0, *('el%d' % i for i in range(5)))
+        lb.pack()
+        lb.update()
+        events = []
+        lb.bind('<<ListboxSelect>>', lambda e: events.append(lb.curselection()))
+        lb.focus_force()
+        lb.activate(0)
+        lb.event_generate('<Down>')
+        lb.event_generate('<Down>')
+        lb.update()
+        self.assertEqual(events, [(1,), (2,)])
+        self.assertEqual(lb.curselection(), (2,))
+
 
 @add_standard_options(PixelSizeTests, StandardOptionsTests)
 class ScaleTest(AbstractWidgetTest, unittest.TestCase):
index 5758298e8fe362e090743e2d72928a0f511d364f..9c16a717e5d2a00a08bddad64cee9e0ac8e3f238 100644 (file)
@@ -1276,6 +1276,19 @@ class SpinboxTest(EntryTest, unittest.TestCase):
         self.spin.update()
         self.assertEqual(len(success), 2)
 
+    def test_increment_decrement_events(self):
+        # Clicking the arrows fires the <<Increment>> and <<Decrement>>
+        # virtual events.
+        events = []
+        self.spin.bind('<<Increment>>', lambda e: events.append('increment'))
+        self.spin.bind('<<Decrement>>', lambda e: events.append('decrement'))
+        self.spin.update()
+        self._click_increment_arrow()
+        self.spin.update()
+        self._click_decrement_arrow()
+        self.spin.update()
+        self.assertEqual(events, ['increment', 'decrement'])
+
     def test_configure_to(self):
         self.spin['from'] = 0
         self.spin['to'] = 5
@@ -1910,6 +1923,37 @@ class TreeviewTest(AbstractWidgetTest, unittest.TestCase):
         self.tv.selection_toggle((c1, c3))
         self.assertEqual(self.tv.selection(), (c3, item2))
 
+    def test_virtual_events(self):
+        # Keyboard navigation fires the <<TreeviewSelect>>, <<TreeviewOpen>>
+        # and <<TreeviewClose>> virtual events.
+        parent = self.tv.insert('', 'end')
+        self.tv.insert(parent, 'end')
+        item2 = self.tv.insert('', 'end')
+        self.tv.pack()
+        self.tv.update()
+        selects, opens, closes = [], [], []
+        self.tv.bind('<<TreeviewSelect>>',
+                     lambda e: selects.append(self.tv.selection()))
+        self.tv.bind('<<TreeviewOpen>>', lambda e: opens.append(self.tv.focus()))
+        self.tv.bind('<<TreeviewClose>>', lambda e: closes.append(self.tv.focus()))
+        self.tv.focus_force()
+        self.tv.focus(parent)
+        self.tv.selection_set(parent)
+        self.tv.update()
+
+        self.tv.event_generate('<Right>')  # Open the focused parent.
+        self.tv.update()
+        self.assertEqual(opens, [parent])
+
+        self.tv.event_generate('<Left>')  # Close it again.
+        self.tv.update()
+        self.assertEqual(closes, [parent])
+
+        self.tv.event_generate('<Down>')  # Move the selection.
+        self.tv.update()
+        self.assertEqual(self.tv.selection(), (item2,))
+        self.assertIn((item2,), selects)
+
     def test_set(self):
         self.tv['columns'] = ['A', 'B']
         item = self.tv.insert('', 'end', values=['a', 'b'])