Skip to content

Commit 90e84e5

Browse files
gh-151678: Add tests for tkinter widget virtual events
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). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent aa5b164 commit 90e84e5

2 files changed

Lines changed: 61 additions & 0 deletions

File tree

Lib/test/test_tkinter/test_widgets.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,23 @@ def test_selection(self):
19261926
self.assertRaisesRegex(TclError, 'bad listbox index "spam"',
19271927
lb.selection_includes, 'spam')
19281928

1929+
def test_selection_event(self):
1930+
# Keyboard navigation changes the selection and fires the
1931+
# <<ListboxSelect>> virtual event.
1932+
lb = self.create(selectmode='browse', exportselection=False)
1933+
lb.insert(0, *('el%d' % i for i in range(5)))
1934+
lb.pack()
1935+
lb.update()
1936+
events = []
1937+
lb.bind('<<ListboxSelect>>', lambda e: events.append(lb.curselection()))
1938+
lb.focus_force()
1939+
lb.activate(0)
1940+
lb.event_generate('<Down>')
1941+
lb.event_generate('<Down>')
1942+
lb.update()
1943+
self.assertEqual(events, [(1,), (2,)])
1944+
self.assertEqual(lb.curselection(), (2,))
1945+
19291946

19301947
@add_configure_tests(PixelSizeTests, StandardOptionsTests)
19311948
class ScaleTest(AbstractWidgetTest, unittest.TestCase):

Lib/test/test_ttk/test_widgets.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,19 @@ def test_configure_command(self):
13071307
self.spin.update()
13081308
self.assertEqual(len(success), 2)
13091309

1310+
def test_increment_decrement_events(self):
1311+
# Clicking the arrows fires the <<Increment>> and <<Decrement>>
1312+
# virtual events.
1313+
events = []
1314+
self.spin.bind('<<Increment>>', lambda e: events.append('increment'))
1315+
self.spin.bind('<<Decrement>>', lambda e: events.append('decrement'))
1316+
self.spin.update()
1317+
self._click_increment_arrow()
1318+
self.spin.update()
1319+
self._click_decrement_arrow()
1320+
self.spin.update()
1321+
self.assertEqual(events, ['increment', 'decrement'])
1322+
13101323
def test_configure_to(self):
13111324
self.spin['from'] = 0
13121325
self.spin['to'] = 5
@@ -1945,6 +1958,37 @@ def test_selection(self):
19451958
self.tv.selection_toggle((c1, c3))
19461959
self.assertEqual(self.tv.selection(), (c3, item2))
19471960

1961+
def test_virtual_events(self):
1962+
# Keyboard navigation fires the <<TreeviewSelect>>, <<TreeviewOpen>>
1963+
# and <<TreeviewClose>> virtual events.
1964+
parent = self.tv.insert('', 'end')
1965+
self.tv.insert(parent, 'end')
1966+
item2 = self.tv.insert('', 'end')
1967+
self.tv.pack()
1968+
self.tv.update()
1969+
selects, opens, closes = [], [], []
1970+
self.tv.bind('<<TreeviewSelect>>',
1971+
lambda e: selects.append(self.tv.selection()))
1972+
self.tv.bind('<<TreeviewOpen>>', lambda e: opens.append(self.tv.focus()))
1973+
self.tv.bind('<<TreeviewClose>>', lambda e: closes.append(self.tv.focus()))
1974+
self.tv.focus_force()
1975+
self.tv.focus(parent)
1976+
self.tv.selection_set(parent)
1977+
self.tv.update()
1978+
1979+
self.tv.event_generate('<Right>') # Open the focused parent.
1980+
self.tv.update()
1981+
self.assertEqual(opens, [parent])
1982+
1983+
self.tv.event_generate('<Left>') # Close it again.
1984+
self.tv.update()
1985+
self.assertEqual(closes, [parent])
1986+
1987+
self.tv.event_generate('<Down>') # Move the selection.
1988+
self.tv.update()
1989+
self.assertEqual(self.tv.selection(), (item2,))
1990+
self.assertIn((item2,), selects)
1991+
19481992
def test_set(self):
19491993
self.tv['columns'] = ['A', 'B']
19501994
item = self.tv.insert('', 'end', values=['a', 'b'])

0 commit comments

Comments
 (0)