From: Serhiy Storchaka Date: Sat, 20 Jun 2026 14:31:40 +0000 (+0300) Subject: gh-151678: Add tests for tkinter widget virtual events (GH-151793) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e51b616efff845ea2a7d312aa43d5f5100064d88;p=thirdparty%2FPython%2Fcpython.git gh-151678: Add tests for tkinter widget virtual events (GH-151793) Verify the virtual events that widgets emit in response to user interaction, driven by generated events: <> (Listbox), <> and <> (ttk Spinbox), and <>, <> and <> (ttk Treeview). Co-authored-by: Claude Opus 4.8 --- diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py index 8ce71bc37ca2..4b51d219d87e 100644 --- a/Lib/test/test_tkinter/test_widgets.py +++ b/Lib/test/test_tkinter/test_widgets.py @@ -1926,6 +1926,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 + # <> 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('<>', lambda e: events.append(lb.curselection())) + lb.focus_force() + lb.activate(0) + lb.event_generate('') + lb.event_generate('') + lb.update() + self.assertEqual(events, [(1,), (2,)]) + self.assertEqual(lb.curselection(), (2,)) + @add_configure_tests(PixelSizeTests, StandardOptionsTests) class ScaleTest(AbstractWidgetTest, unittest.TestCase): diff --git a/Lib/test/test_ttk/test_widgets.py b/Lib/test/test_ttk/test_widgets.py index adcd736cd40b..a3b3c88b46ed 100644 --- a/Lib/test/test_ttk/test_widgets.py +++ b/Lib/test/test_ttk/test_widgets.py @@ -1307,6 +1307,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 <> and <> + # virtual events. + events = [] + self.spin.bind('<>', lambda e: events.append('increment')) + self.spin.bind('<>', 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 @@ -1945,6 +1958,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 <>, <> + # and <> 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('<>', + lambda e: selects.append(self.tv.selection())) + self.tv.bind('<>', lambda e: opens.append(self.tv.focus())) + self.tv.bind('<>', 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('') # Open the focused parent. + self.tv.update() + self.assertEqual(opens, [parent]) + + self.tv.event_generate('') # Close it again. + self.tv.update() + self.assertEqual(closes, [parent]) + + self.tv.event_generate('') # 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'])